Commit e7aefbad authored by Matt Mascarenhas's avatar Matt Mascarenhas

cinera.css: Marker and categories style

cinera_player_pre.js: Episode keyboard navigation. Also swap out A for
K, and D for J
cinera_player_pre.js: Handle the case in onRefChanged() in which the
filter_container or filterState is not present
cinera.c: Refetch quotes when processing a set of annotations >60 mins
after the last fetch

Flags:
    -w Force quote cache rebuild
parent 2cac3ed0
...@@ -45,22 +45,16 @@ directory. Typical operation will involve setting these flags: ...@@ -45,22 +45,16 @@ directory. Typical operation will involve setting these flags:
-d Project Input Directory, the directory where the .hmml files reside -d Project Input Directory, the directory where the .hmml files reside
-r Root Directory, path shallower than or equal to the CSS, Images and JS -r Root Directory, path shallower than or equal to the CSS, Images and JS
directories directories
-u Root URL, corresponding to the Root Directory (optional if the Output -R Root URL, corresponding to the Root Directory (optional if the Output
Base Directory resides in the Root Directory) Base Directory resides in the Root Directory)
-c CSS Directory, relative to Root
-i Images Directory, relative to Root
-j JS Directory, relative to Root
-b Output Base Directory, location of the table of contents / search page -b Output Base Directory, location of the table of contents / search page
-t Player Template Location -B Output Base URL, corresponding to the Output Base Directory
-x Index Template Location -t Template Directory
-x Index Template Location, relative to Template Directory
#### Integration -y Player Template Location, relative to Template Directory
CINERA_MODE=INTEGRATE cinera test.hmml
This will integrate into `template_player.html` (configurable with -t) the
player and related elements generated from `test.hmml` and output to
`out_integrated.html`
Feel free to play with `template_player.html` to your heart's content. If you do
anything invalid, `cinera` will tell you what's wrong
#### Templates #### Templates
...@@ -76,60 +70,128 @@ Valid tags: ...@@ -76,60 +70,128 @@ Valid tags:
- `<!-- __CINERA_INDEX__ -->` _the table of contents, and search functionality_ - `<!-- __CINERA_INDEX__ -->` _the table of contents, and search functionality_
*Player Template* *Player Template*
- `<!-- __CINERA_INCLUDES__ -->` _the necessary `.css` and `.js` files, and charset setting_ - `<!-- __CINERA_INCLUDES__ -->` _the necessary `.css` and `.js` files, and
- `<!-- __CINERA_MENUS__ -->` _ _the menu bar that typically appears above the player in my samples_ charset setting_
- `<!-- __CINERA_MENUS__ -->` _ _the menu bar that typically appears above the
player in my samples_
- `<!-- __CINERA_PLAYER__ -->` _the player_ - `<!-- __CINERA_PLAYER__ -->` _the player_
- `<!-- __CINERA_SCRIPT__ -->` _the filter state objects and `.js` file, which must come after both the MENUS and PLAYER tags_ - `<!-- __CINERA_SCRIPT__ -->` _the filter state objects and `.js` file, which
must come after both the MENUS and PLAYER tags_
*Optional tags available for use in your Player Template*
- `<!-- __CINERA_TITLE__ -->` _the title of the video, excluding numbering_
- `<!-- __CINERA_VIDEO_ID__ -->` _the unique identifer of the video as provided
by the VoD platform_
*Other available tags*
- `<!-- __CINERA_PROJECT__ -->` _the full name of the project_
- `<!-- __CINERA_URL__ -->` _the URL where we have derived the page will be
publically accessibly, only really usable if BaseURL is set (-B)_
- `<!-- __CINERA_CUSTOM0__ -->`
- `<!-- __CINERA_CUSTOM1__ -->`
- `<!-- __CINERA_CUSTOM2__ -->`
- `<!-- __CINERA_CUSTOM15__ -->`
_Freeform buffers for small snippets of localised information, e.g. a single
<a> element or perhaps a <!-- comment --> They correspond to the custom0 to
custom15 attributes in the [video] node in your .hmml files 0 to 11 may hold
up to 255 characters 12 to 15 may hold up to 1023 characters_
Feel free to play with templates to your heart's content. If you do anything
invalid, `cinera` will tell you what's wrong.
#### Arguments #### Arguments
Usage: ./cinera [option(s)] filename(s) Usage: ./cinera [option(s)] filename(s)
Options: Options:
Paths: Paths: (advisedly universal, but may be set per-(sub)project as required)
-r <root directory> -r <root directory>
Override default root directory (".") Override default root directory (".")
-u <root URL> -R <root URL>
Override default root URL ("") Override default root URL ("")
-b <base output directory> IMPORTANT: -r and -R must correspond to the same location
Override project's default base output directory (".") UNSUPPORTED: If you move files from RootDir, the RootURL should
correspond to the resulting location
-c <CSS directory path> -c <CSS directory path>
Override default CSS directory (""), relative to root Override default CSS directory (""), relative to root
-i <images directory path> -i <images directory path>
Override default images directory (""), relative to root Override default images directory (""), relative to root
-j <JS directory path> -j <JS directory path>
Override default JS directory (""), relative to root Override default JS directory (""), relative to root
-t <player template location>
Override default player template location ("template_player.html"), relative to root Project Settings:
and automatically enable integration -p <project ID>
Set the project ID, equal to the "project" field in the HMML files
NOTE: Setting the project ID triggers PROJECT EDITION
-m <default medium>
Override default default medium ("programming")
Known project defaults:
book: research
pcalc: programming
riscy: programming
chat: speech
code: programming
intro-to-c: programming
misc: admin
ray: programming
hmdshow: speech
lecture: speech
stream: programming
special: programming
obbg: programming
sysadmin: admin
-s <style>
Set the style / theme, corresponding to a cinera__*.css file
This is equal to the "project" field in the HMML files by default
-q
Quit after syncing with annotation files in project input directory
UNSUPPORTED: This is likely to be removed in the future
Project Input Paths
-d <annotations directory>
Override default annotations directory (".")
-t <templates directory>
Override default templates directory (".")
-x <index template location> -x <index template location>
Override default index template location ("template_index.html"), relative to root Set index template file path, either absolute or relative to
and automatically enable integration template directory, and enable integration
-y <player template location>
Set player template file path, either absolute or relative
to template directory, and enable integration
Project Output Paths
-b <base output directory>
Override project's default base output directory (".")
-B <base URL>
Override default base URL ("")
NOTE: This must be set, if -n or -a are to be used
-n <index location>
Override default index location (""), relative to base
-a <player location>
Override default player location (""), relative to base
NOTE: The PlayerURLPrefix is currently hardcoded in cinera.c but
will be configurable in the full configuration system
Single Edition Output Path
-o <output location> -o <output location>
Override default output player location for SINGLE_EDITION ("out.html") Override default output player location ("out.html")
-d <project directory>
Override default project directory (".")
-e
Display (examine) index file and exit
-f -f
Force integration with an incomplete template Force integration with an incomplete template
-p <project ID> -w
Set the project ID, corresponding to the "project" field in the HMML files Force quote cache rebuild (memory aid: "wget")
-s <style>
Set the style / theme, corresponding to a cinera__*.css file
This is equal to the "project" field in the HMML files by default
-l <n> -l <n>
Override default log level (0), where n is from 0 (terse) to 7 (verbose) Override default log level (0), where n is from 0 (terse) to 7 (verbose)
-m <default medium> -u <seconds>
Override default default medium ("programming") Override default update interval (4)
-U <seconds>
Override default update interval ("4")
-v -v
display version and exit Display version and exit
-h -h
display this help Display this help
#### Environment Variables
CINERA_MODE=INTEGRATE
Enable integration
...@@ -14,7 +14,7 @@ typedef struct ...@@ -14,7 +14,7 @@ typedef struct
version CINERA_APP_VERSION = { version CINERA_APP_VERSION = {
.Major = 0, .Major = 0,
.Minor = 5, .Minor = 5,
.Patch = 35 .Patch = 36
}; };
// TODO(matt): Copy in the DB 3 stuff from cinera_working.c // TODO(matt): Copy in the DB 3 stuff from cinera_working.c
...@@ -83,6 +83,7 @@ enum ...@@ -83,6 +83,7 @@ enum
{ {
MODE_ONESHOT = 1 << 0, MODE_ONESHOT = 1 << 0,
MODE_EXAMINE = 1 << 1, MODE_EXAMINE = 1 << 1,
MODE_NOCACHE = 1 << 2,
} modes; } modes;
enum enum
...@@ -114,6 +115,55 @@ typedef struct ...@@ -114,6 +115,55 @@ typedef struct
int Size; int Size;
} arena; } arena;
typedef struct
{
// Universal
char CacheDir[256];
int Edition;
int LogLevel;
int Mode;
int UpdateInterval;
bool ForceIntegration;
// Advisedly universal, although could be per-project
char *RootDir; // Absolute
char *RootURL;
char *CSSDir; // Relative to Root{Dir,URL}
char *ImagesDir; // Relative to Root{Dir,URL}
char *JSDir; // Relative to Root{Dir,URL}
// Per Project
char *ProjectID;
char *Theme;
char *DefaultMedium;
// Per Project - Input
char *ProjectDir; // Absolute
char *TemplatesDir; // Absolute
char *TemplateIndexLocation; // Relative to TemplatesDir ???
char *TemplatePlayerLocation; // Relative to TemplatesDir ???
// Per Project - Output
char *BaseDir; // Absolute
char *BaseURL;
char *IndexLocation; // Relative to Base{Dir,URL}
char *PlayerLocation; // Relative to Base{Dir,URL}
char *PlayerURLPrefix; /* NOTE(matt): This will become a full blown customisable output URL.
For now it simply replaces the ProjectID */
// Single Edition - Input
char SingleHMMLFilePath[256];
// Single Edition - Output
char *OutLocation;
char *OutIntegratedLocation;
} config;
// NOTE(matt): Globals
config Config = {};
arena MemoryArena;
time_t LastQuoteFetch;
//
typedef struct typedef struct
{ {
char *Location; char *Location;
...@@ -308,53 +358,6 @@ typedef struct ...@@ -308,53 +358,6 @@ typedef struct
buffer Buffer; buffer Buffer;
} template; } template;
typedef struct
{
// Universal
char CacheDir[256];
int Edition;
int LogLevel;
int Mode;
int UpdateInterval;
bool ForceIntegration;
// Advisedly universal, although could be per-project
char *RootDir; // Absolute
char *RootURL;
char *CSSDir; // Relative to Root{Dir,URL}
char *ImagesDir; // Relative to Root{Dir,URL}
char *JSDir; // Relative to Root{Dir,URL}
// Per Project
char *ProjectID;
char *Theme;
char *DefaultMedium;
// Per Project - Input
char *ProjectDir; // Absolute
char *TemplatesDir; // Absolute
char *TemplateIndexLocation; // Relative to TemplatesDir ???
char *TemplatePlayerLocation; // Relative to TemplatesDir ???
// Per Project - Output
char *BaseDir; // Absolute
char *BaseURL;
char *IndexLocation; // Relative to Base{Dir,URL}
char *PlayerLocation; // Relative to Base{Dir,URL}
char *PlayerURLPrefix; /* NOTE(matt): This will become a full blown customisable output URL.
For now it simply replaces the ProjectID */
// Single Edition - Input
char SingleHMMLFilePath[256];
// Single Edition - Output
char *OutLocation;
char *OutIntegratedLocation;
} config;
// NOTE(matt): Globals
config Config = {};
arena MemoryArena;
// TODO(matt): Consider putting the ref_info and quote_info into linked lists on the heap, just to avoid all the hardcoded sizes // TODO(matt): Consider putting the ref_info and quote_info into linked lists on the heap, just to avoid all the hardcoded sizes
typedef struct typedef struct
...@@ -1735,6 +1738,7 @@ CurlIntoBuffer(char *InPtr, size_t CharLength, size_t Chars, char **OutputPtr) ...@@ -1735,6 +1738,7 @@ CurlIntoBuffer(char *InPtr, size_t CharLength, size_t Chars, char **OutputPtr)
void void
CurlQuotes(buffer *QuoteStaging, char *QuotesURL) CurlQuotes(buffer *QuoteStaging, char *QuotesURL)
{ {
fprintf(stderr, "\e[0;35mFetching\e[0m quotes: %s\n", QuotesURL);
CURL *curl = curl_easy_init(); CURL *curl = curl_easy_init();
if(curl) { if(curl) {
CURLcode res; CURLcode res;
...@@ -1800,14 +1804,18 @@ SearchQuotes(buffer *QuoteStaging, int CacheSize, quote_info *Info, int ID) ...@@ -1800,14 +1804,18 @@ SearchQuotes(buffer *QuoteStaging, int CacheSize, quote_info *Info, int ID)
} }
int int
BuildQuote(quote_info *Info, char *Speaker, int ID) BuildQuote(quote_info *Info, char *Speaker, int ID, bool ShouldFetchQuotes)
{ {
// TODO(matt): Rebuild cache option
char QuoteCacheDir[256]; char QuoteCacheDir[256];
CopyString(QuoteCacheDir, "%s/quotes", Config.CacheDir); CopyString(QuoteCacheDir, "%s/quotes", Config.CacheDir);
char QuoteCachePath[256]; char QuoteCachePath[256];
CopyString(QuoteCachePath, "%s/%s", QuoteCacheDir, Speaker); CopyString(QuoteCachePath, "%s/%s", QuoteCacheDir, Speaker);
if(ShouldFetchQuotes)
{
remove(QuoteCachePath);
}
FILE *QuoteCache; FILE *QuoteCache;
char QuotesURL[256]; char QuotesURL[256];
// TODO(matt): Make the URL configurable // TODO(matt): Make the URL configurable
...@@ -1819,7 +1827,7 @@ BuildQuote(quote_info *Info, char *Speaker, int ID) ...@@ -1819,7 +1827,7 @@ BuildQuote(quote_info *Info, char *Speaker, int ID)
if(MakeDir(QuoteCacheDir) == RC_SUCCESS) if(MakeDir(QuoteCacheDir) == RC_SUCCESS)
{ {
CacheAvailable = TRUE; CacheAvailable = TRUE;
}; }
if(!(QuoteCache = fopen(QuoteCachePath, "a+"))) if(!(QuoteCache = fopen(QuoteCachePath, "a+")))
{ {
fprintf(stderr, "Unable to open quote cache %s: %s\n", QuoteCachePath, strerror(errno)); fprintf(stderr, "Unable to open quote cache %s: %s\n", QuoteCachePath, strerror(errno));
...@@ -2103,6 +2111,8 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig) ...@@ -2103,6 +2111,8 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
" Display (examine) index file and exit\n" " Display (examine) index file and exit\n"
" -f\n" " -f\n"
" Force integration with an incomplete template\n" " Force integration with an incomplete template\n"
" -w\n"
" Force quote cache rebuild \e[1;30m(memory aid: \"wget\")\e[0m\n"
"\n" "\n"
" -l <n>\n" " -l <n>\n"
" Override default log level (%d), where n is from 0 (terse) to 7 (verbose)\n" " Override default log level (%d), where n is from 0 (terse) to 7 (verbose)\n"
...@@ -2115,12 +2125,12 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig) ...@@ -2115,12 +2125,12 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
" Display this help\n" " Display this help\n"
"\n" "\n"
"Template:\n" "Template:\n"
" A complete index template shall contain exactly one each of the following tags:\n" " A complete Index Template shall contain exactly one each of the following tags:\n"
" <!-- __CINERA_INCLUDES__ -->\n" " <!-- __CINERA_INCLUDES__ -->\n"
" to put inside your own <head></head>\n" " to put inside your own <head></head>\n"
" <!-- __CINERA_INDEX__ -->\n" " <!-- __CINERA_INDEX__ -->\n"
"\n" "\n"
" A complete player template shall contain exactly one each of the following tags:\n" " A complete Player Template shall contain exactly one each of the following tags:\n"
" <!-- __CINERA_INCLUDES__ -->\n" " <!-- __CINERA_INCLUDES__ -->\n"
" to put inside your own <head></head>\n" " to put inside your own <head></head>\n"
" <!-- __CINERA_MENUS__ -->\n" " <!-- __CINERA_MENUS__ -->\n"
...@@ -2128,7 +2138,7 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig) ...@@ -2128,7 +2138,7 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
" <!-- __CINERA_SCRIPT__ -->\n" " <!-- __CINERA_SCRIPT__ -->\n"
" must come after <!-- __CINERA_MENUS__ --> and <!-- __CINERA_PLAYER__ -->\n" " must come after <!-- __CINERA_MENUS__ --> and <!-- __CINERA_PLAYER__ -->\n"
"\n" "\n"
" Optional tags available for use in your player template:\n" " Optional tags available for use in your Player Template:\n"
" <!-- __CINERA_TITLE__ -->\n" " <!-- __CINERA_TITLE__ -->\n"
" <!-- __CINERA_VIDEO_ID__ -->\n" " <!-- __CINERA_VIDEO_ID__ -->\n"
"\n" "\n"
...@@ -3232,9 +3242,15 @@ AppendedIdentifier: ...@@ -3232,9 +3242,15 @@ AppendedIdentifier:
HasQuote = TRUE; HasQuote = TRUE;
char *Speaker = Anno->quote.author ? Anno->quote.author : HMML.metadata.stream_username ? HMML.metadata.stream_username : HMML.metadata.member; char *Speaker = Anno->quote.author ? Anno->quote.author : HMML.metadata.stream_username ? HMML.metadata.stream_username : HMML.metadata.member;
bool ShouldFetchQuotes = FALSE;
if(Config.Mode & MODE_NOCACHE || (Config.Edition != EDITION_SINGLE && time(0) - LastQuoteFetch > 60*60))
{
ShouldFetchQuotes = TRUE;
LastQuoteFetch = time(0);
}
if(BuildQuote(&QuoteInfo, if(BuildQuote(&QuoteInfo,
Speaker, Speaker,
Anno->quote.id) == RC_UNFOUND) Anno->quote.id, ShouldFetchQuotes) == RC_UNFOUND)
{ {
LogError(LOG_ERROR, "Quote #%s %d not found: %s:%d", Speaker, Anno->quote.id, Filename, Anno->line); LogError(LOG_ERROR, "Quote #%s %d not found: %s:%d", Speaker, Anno->quote.id, Filename, Anno->line);
Filename[StringLength(Filename) - StringLength(".hmml")] = '\0'; Filename[StringLength(Filename) - StringLength(".hmml")] = '\0';
...@@ -3650,7 +3666,8 @@ AppendedIdentifier: ...@@ -3650,7 +3666,8 @@ AppendedIdentifier:
" <span class=\"help_key\">?</span><h1>Keyboard Navigation</h1>\n" " <span class=\"help_key\">?</span><h1>Keyboard Navigation</h1>\n"
"\n" "\n"
" <h2>Global Keys</h2>\n" " <h2>Global Keys</h2>\n"
" <span class=\"help_key\">W</span>, <span class=\"help_key\">A</span>, <span class=\"help_key\">P</span> / <span class=\"help_key\">S</span>, <span class=\"help_key\">D</span>, <span class=\"help_key\">N</span> <span class=\"help_text\">Jump to previous / next marker</span><br>\n" " <span class=\"help_key\">[</span>, <span class=\"help_key\">&lt;</span> / <span class=\"help_key\">]</span>, <span class=\"help_key\">&gt;</span> <span class=\"help_text\">Jump to previous / next episode</span><br>\n"
" <span class=\"help_key\">W</span>, <span class=\"help_key\">K</span>, <span class=\"help_key\">P</span> / <span class=\"help_key\">S</span>, <span class=\"help_key\">J</span>, <span class=\"help_key\">N</span> <span class=\"help_text\">Jump to previous / next marker</span><br>\n"
" <span class=\"help_key\">t</span> / <span class=\"help_key\">T</span> <span class=\"help_text\">Toggle theatre / SUPERtheatre mode</span><br>\n" " <span class=\"help_key\">t</span> / <span class=\"help_key\">T</span> <span class=\"help_text\">Toggle theatre / SUPERtheatre mode</span><br>\n"
); );
...@@ -3715,7 +3732,7 @@ AppendedIdentifier: ...@@ -3715,7 +3732,7 @@ AppendedIdentifier:
CopyStringToBuffer(&CollationBuffers->Menus, CopyStringToBuffer(&CollationBuffers->Menus,
"\n" "\n"
" <h2>Movement</h2>\n" " <h2>In-Menu Movement</h2>\n"
" <div class=\"help_paragraph\">\n" " <div class=\"help_paragraph\">\n"
" <div class=\"key_block\">\n" " <div class=\"key_block\">\n"
" <div class=\"key_column\" style=\"flex-grow: 1\">\n" " <div class=\"key_column\" style=\"flex-grow: 1\">\n"
...@@ -4784,8 +4801,8 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) ...@@ -4784,8 +4801,8 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
break; break;
} }
index_header Header = *(index_header *)Index->Metadata.Buffer.Ptr; Index->Header = *(index_header *)Index->Metadata.Buffer.Ptr;
Index->Metadata.Buffer.Ptr += sizeof(Header); Index->Metadata.Buffer.Ptr += sizeof(Index->Header);
index_metadata *Prev = { 0 }; index_metadata *Prev = { 0 };
index_metadata *This = { 0 }; index_metadata *This = { 0 };
index_metadata *Next = { 0 }; index_metadata *Next = { 0 };
...@@ -4795,12 +4812,12 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) ...@@ -4795,12 +4812,12 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
{ {
case LINK_INCLUDE: case LINK_INCLUDE:
{ {
for(EntryIndex = 0; EntryIndex < Header.EntryCount; ++EntryIndex) for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
{ {
This = (index_metadata *)Index->Metadata.Buffer.Ptr; This = (index_metadata *)Index->Metadata.Buffer.Ptr;
if(!StringsDiffer(This->BaseFilename, BaseFilename)) if(!StringsDiffer(This->BaseFilename, BaseFilename))
{ {
if(EntryIndex < (Header.EntryCount - 1)) if(EntryIndex < (Index->Header.EntryCount - 1))
{ {
Next = (index_metadata *)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata)); Next = (index_metadata *)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata));
} }
...@@ -4811,18 +4828,14 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType) ...@@ -4811,18 +4828,14 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
} }
} break; } break;
case LINK_EXCLUDE: case LINK_EXCLUDE:
{
if(Index->Header.EntryCount == 1)
{ {
This = (index_metadata *)Index->Metadata.Buffer.Ptr; This = (index_metadata *)Index->Metadata.Buffer.Ptr;
} if(Index->Header.EntryCount != 1)
else
{ {
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
Index->Metadata.Buffer.Ptr += sizeof(index_metadata); Index->Metadata.Buffer.Ptr += sizeof(index_metadata);
Next = (index_metadata *)Index->Metadata.Buffer.Ptr; Next = (index_metadata *)Index->Metadata.Buffer.Ptr;
for(EntryIndex = 1; EntryIndex < Header.EntryCount; ++EntryIndex) for(EntryIndex = 1; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
{ {
Prev = This; Prev = This;
This = Next; This = Next;
...@@ -5892,7 +5905,7 @@ main(int ArgC, char **Args) ...@@ -5892,7 +5905,7 @@ main(int ArgC, char **Args)
} }
char CommandLineArg; char CommandLineArg;
while((CommandLineArg = getopt(ArgC, Args, "a:b:B:c:d:efhi:j:l:m:n:o:p:qr:R:s:t:u:vx:y:")) != -1) while((CommandLineArg = getopt(ArgC, Args, "a:b:B:c:d:efhi:j:l:m:n:o:p:qr:R:s:t:u:vwx:y:")) != -1)
{ {
switch(CommandLineArg) switch(CommandLineArg)
{ {
...@@ -5961,6 +5974,9 @@ main(int ArgC, char **Args) ...@@ -5961,6 +5974,9 @@ main(int ArgC, char **Args)
case 'v': case 'v':
PrintVersions(); PrintVersions();
return RC_SUCCESS; return RC_SUCCESS;
case 'w':
Config.Mode |= MODE_NOCACHE;
break;
case 'x': case 'x':
Config.TemplateIndexLocation = optarg; Config.TemplateIndexLocation = optarg;
break; break;
...@@ -6226,6 +6242,15 @@ main(int ArgC, char **Args) ...@@ -6226,6 +6242,15 @@ main(int ArgC, char **Args)
while(MonitorDirectory(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate, inotifyInstance, WatchDescriptor) != RC_ERROR_FATAL) while(MonitorDirectory(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate, inotifyInstance, WatchDescriptor) != RC_ERROR_FATAL)
{ {
// TODO(matt): Refetch the quotes and rebuild player pages if needed
//
// Every sixty mins, redownload the quotes and, I suppose, SyncIndexWithInput(). But here we still don't even know
// who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe
// postpone this for now, but we will certainly need this to happen
//
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
// the player page(s) accordingly.
sleep(Config.UpdateInterval); sleep(Config.UpdateInterval);
} }
} }
......
...@@ -528,7 +528,7 @@ ...@@ -528,7 +528,7 @@
} }
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent { .cineraPlayerContainer .markers_container > .markers .marker .cineraContent {
display: block; display: inline-block;
font-size: 14px; font-size: 14px;
} }
...@@ -575,7 +575,8 @@ ...@@ -575,7 +575,8 @@
} }
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent .cineraCategories { .cineraPlayerContainer .markers_container > .markers .marker .cineraContent .cineraCategories {
margin: 4px; float: right;
min-height: 1em;
} }
.cineraMenus > .menu > .filter_container .filter_content { .cineraMenus > .menu > .filter_container .filter_content {
......
...@@ -220,6 +220,8 @@ for(var i = 0; i < sourceMenus.length; ++i) ...@@ -220,6 +220,8 @@ for(var i = 0; i < sourceMenus.length; ++i)
}) })
}; };
var prevEpisode = playerContainer.querySelector(".episodeMarker.prev");
var nextEpisode = playerContainer.querySelector(".episodeMarker.next");
var testMarkers = playerContainer.querySelectorAll(".marker"); var testMarkers = playerContainer.querySelectorAll(".marker");
window.addEventListener("blur", function(){ window.addEventListener("blur", function(){
......
...@@ -56,8 +56,6 @@ function Player(htmlContainer, refsCallback) { ...@@ -56,8 +56,6 @@ function Player(htmlContainer, refsCallback) {
Player.initializeYoutube(this.onYoutubeReady.bind(this)); Player.initializeYoutube(this.onYoutubeReady.bind(this));
this.updateSize(); this.updateSize();
this.resume();
} }
// Start playing the video from the current position. // Start playing the video from the current position.
...@@ -68,6 +66,7 @@ Player.prototype.play = function() { ...@@ -68,6 +66,7 @@ Player.prototype.play = function() {
this.youtubePlayer.playVideo(); this.youtubePlayer.playVideo();
} }
this.pauseAfterBuffer = false; this.pauseAfterBuffer = false;
this.resume();
} else { } else {
this.shouldPlay = true; this.shouldPlay = true;
} }
...@@ -119,6 +118,7 @@ Player.prototype.updateSize = function() { ...@@ -119,6 +118,7 @@ Player.prototype.updateSize = function() {
this.markersContainer.style.height = height; this.markersContainer.style.height = height;
if (this.youtubePlayerReady) { if (this.youtubePlayerReady) {
this.youtubePlayer.setSize(Math.floor(width), Math.floor(height)); this.youtubePlayer.setSize(Math.floor(width), Math.floor(height));
this.resume();
} }
} }
...@@ -929,16 +929,30 @@ function handleKey(key) { ...@@ -929,16 +929,30 @@ function handleKey(key) {
} break; } break;
case 'N': case 'N':
case 'D': case 'J':
case 'S': { case 'S': {
player.jumpToNextMarker(); player.jumpToNextMarker();
} break; } break;
case 'P': case 'P':
case 'A': case 'K':
case 'W': { case 'W': {
player.jumpToPrevMarker(); player.jumpToPrevMarker();
} break; } break;
case '[':
case '<': {
if(prevEpisode)
{
location = prevEpisode.href;
}
} break;
case ']':
case '>': {
if(nextEpisode)
{
location = nextEpisode.href;
}
} break;
default: { default: {
gotKey = false; gotKey = false;
} break; } break;
...@@ -1165,6 +1179,22 @@ function resetFade() { ...@@ -1165,6 +1179,22 @@ function resetFade() {
function onRefChanged(ref, element) { function onRefChanged(ref, element) {
if(element.classList.contains("skip")) if(