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
This commit is contained in:
parent
2cac3ed03b
commit
e7aefbada0
188
README.md
188
README.md
|
@ -45,22 +45,16 @@ directory. Typical operation will involve setting these flags:
|
|||
-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
|
||||
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)
|
||||
-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
|
||||
-t Player Template Location
|
||||
-x Index Template Location
|
||||
|
||||
#### Integration
|
||||
|
||||
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
|
||||
-B Output Base URL, corresponding to the Output Base Directory
|
||||
-t Template Directory
|
||||
-x Index Template Location, relative to Template Directory
|
||||
-y Player Template Location, relative to Template Directory
|
||||
|
||||
#### Templates
|
||||
|
||||
|
@ -76,60 +70,128 @@ Valid tags:
|
|||
- `<!-- __CINERA_INDEX__ -->` _the table of contents, and search functionality_
|
||||
|
||||
*Player Template*
|
||||
- `<!-- __CINERA_INCLUDES__ -->` _the necessary `.css` and `.js` files, and charset setting_
|
||||
- `<!-- __CINERA_MENUS__ -->` _ _the menu bar that typically appears above the player in my samples_
|
||||
- `<!-- __CINERA_INCLUDES__ -->` _the necessary `.css` and `.js` files, and
|
||||
charset setting_
|
||||
- `<!-- __CINERA_MENUS__ -->` _ _the menu bar that typically appears above the
|
||||
player in my samples_
|
||||
- `<!-- __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
|
||||
|
||||
Usage: ./cinera [option(s)] filename(s)
|
||||
Usage: ./cinera [option(s)] filename(s)
|
||||
|
||||
Options:
|
||||
Paths:
|
||||
-r <root directory>
|
||||
Override default root directory (".")
|
||||
-u <root URL>
|
||||
Override default root URL ("")
|
||||
-b <base output directory>
|
||||
Override project's default base output directory (".")
|
||||
-c <CSS directory path>
|
||||
Override default CSS directory (""), relative to root
|
||||
-i <images directory path>
|
||||
Override default images directory (""), relative to root
|
||||
-j <JS directory path>
|
||||
Override default JS directory (""), relative to root
|
||||
-t <player template location>
|
||||
Override default player template location ("template_player.html"), relative to root
|
||||
and automatically enable integration
|
||||
-x <index template location>
|
||||
Override default index template location ("template_index.html"), relative to root
|
||||
and automatically enable integration
|
||||
Options:
|
||||
Paths: (advisedly universal, but may be set per-(sub)project as required)
|
||||
-r <root directory>
|
||||
Override default root directory (".")
|
||||
-R <root URL>
|
||||
Override default root URL ("")
|
||||
IMPORTANT: -r and -R must correspond to the same location
|
||||
UNSUPPORTED: If you move files from RootDir, the RootURL should
|
||||
correspond to the resulting location
|
||||
|
||||
-o <output location>
|
||||
Override default output player location for SINGLE_EDITION ("out.html")
|
||||
-d <project directory>
|
||||
Override default project directory (".")
|
||||
-c <CSS directory path>
|
||||
Override default CSS directory (""), relative to root
|
||||
-i <images directory path>
|
||||
Override default images directory (""), relative to root
|
||||
-j <JS directory path>
|
||||
Override default JS directory (""), relative to root
|
||||
|
||||
-f
|
||||
Force integration with an incomplete template
|
||||
-p <project ID>
|
||||
Set the project ID, corresponding to the "project" field in the HMML files
|
||||
-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>
|
||||
Override default log level (0), where n is from 0 (terse) to 7 (verbose)
|
||||
-m <default medium>
|
||||
Override default default medium ("programming")
|
||||
-U <seconds>
|
||||
Override default update interval ("4")
|
||||
Project Settings:
|
||||
-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>
|
||||
Set index template file path, either absolute or relative to
|
||||
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>
|
||||
Override default output player location ("out.html")
|
||||
|
||||
-e
|
||||
Display (examine) index file and exit
|
||||
-f
|
||||
Force integration with an incomplete template
|
||||
-w
|
||||
Force quote cache rebuild (memory aid: "wget")
|
||||
|
||||
-l <n>
|
||||
Override default log level (0), where n is from 0 (terse) to 7 (verbose)
|
||||
-u <seconds>
|
||||
Override default update interval (4)
|
||||
-v
|
||||
display version and exit
|
||||
-h
|
||||
display this help
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
CINERA_MODE=INTEGRATE
|
||||
Enable integration
|
||||
Display version and exit
|
||||
-h
|
||||
Display this help
|
||||
|
|
165
cinera/cinera.c
165
cinera/cinera.c
|
@ -14,7 +14,7 @@ typedef struct
|
|||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 5,
|
||||
.Patch = 35
|
||||
.Patch = 36
|
||||
};
|
||||
|
||||
// TODO(matt): Copy in the DB 3 stuff from cinera_working.c
|
||||
|
@ -83,6 +83,7 @@ enum
|
|||
{
|
||||
MODE_ONESHOT = 1 << 0,
|
||||
MODE_EXAMINE = 1 << 1,
|
||||
MODE_NOCACHE = 1 << 2,
|
||||
} modes;
|
||||
|
||||
enum
|
||||
|
@ -114,6 +115,55 @@ typedef struct
|
|||
int Size;
|
||||
} 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
|
||||
{
|
||||
char *Location;
|
||||
|
@ -308,53 +358,6 @@ typedef struct
|
|||
buffer Buffer;
|
||||
} 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
|
||||
|
||||
typedef struct
|
||||
|
@ -1735,6 +1738,7 @@ CurlIntoBuffer(char *InPtr, size_t CharLength, size_t Chars, char **OutputPtr)
|
|||
void
|
||||
CurlQuotes(buffer *QuoteStaging, char *QuotesURL)
|
||||
{
|
||||
fprintf(stderr, "\e[0;35mFetching\e[0m quotes: %s\n", QuotesURL);
|
||||
CURL *curl = curl_easy_init();
|
||||
if(curl) {
|
||||
CURLcode res;
|
||||
|
@ -1800,14 +1804,18 @@ SearchQuotes(buffer *QuoteStaging, int CacheSize, quote_info *Info, int ID)
|
|||
}
|
||||
|
||||
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];
|
||||
CopyString(QuoteCacheDir, "%s/quotes", Config.CacheDir);
|
||||
char QuoteCachePath[256];
|
||||
CopyString(QuoteCachePath, "%s/%s", QuoteCacheDir, Speaker);
|
||||
|
||||
if(ShouldFetchQuotes)
|
||||
{
|
||||
remove(QuoteCachePath);
|
||||
}
|
||||
|
||||
FILE *QuoteCache;
|
||||
char QuotesURL[256];
|
||||
// TODO(matt): Make the URL configurable
|
||||
|
@ -1819,7 +1827,7 @@ BuildQuote(quote_info *Info, char *Speaker, int ID)
|
|||
if(MakeDir(QuoteCacheDir) == RC_SUCCESS)
|
||||
{
|
||||
CacheAvailable = TRUE;
|
||||
};
|
||||
}
|
||||
if(!(QuoteCache = fopen(QuoteCachePath, "a+")))
|
||||
{
|
||||
fprintf(stderr, "Unable to open quote cache %s: %s\n", QuoteCachePath, strerror(errno));
|
||||
|
@ -2103,6 +2111,8 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
|
|||
" Display (examine) index file and exit\n"
|
||||
" -f\n"
|
||||
" Force integration with an incomplete template\n"
|
||||
" -w\n"
|
||||
" Force quote cache rebuild \e[1;30m(memory aid: \"wget\")\e[0m\n"
|
||||
"\n"
|
||||
" -l <n>\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)
|
|||
" Display this help\n"
|
||||
"\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"
|
||||
" to put inside your own <head></head>\n"
|
||||
" <!-- __CINERA_INDEX__ -->\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"
|
||||
" to put inside your own <head></head>\n"
|
||||
" <!-- __CINERA_MENUS__ -->\n"
|
||||
|
@ -2128,7 +2138,7 @@ PrintUsage(char *BinaryLocation, config *DefaultConfig)
|
|||
" <!-- __CINERA_SCRIPT__ -->\n"
|
||||
" must come after <!-- __CINERA_MENUS__ --> and <!-- __CINERA_PLAYER__ -->\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_VIDEO_ID__ -->\n"
|
||||
"\n"
|
||||
|
@ -3232,9 +3242,15 @@ AppendedIdentifier:
|
|||
HasQuote = TRUE;
|
||||
|
||||
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,
|
||||
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);
|
||||
Filename[StringLength(Filename) - StringLength(".hmml")] = '\0';
|
||||
|
@ -3650,7 +3666,8 @@ AppendedIdentifier:
|
|||
" <span class=\"help_key\">?</span><h1>Keyboard Navigation</h1>\n"
|
||||
"\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\"><</span> / <span class=\"help_key\">]</span>, <span class=\"help_key\">></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"
|
||||
);
|
||||
|
||||
|
@ -3715,7 +3732,7 @@ AppendedIdentifier:
|
|||
|
||||
CopyStringToBuffer(&CollationBuffers->Menus,
|
||||
"\n"
|
||||
" <h2>Movement</h2>\n"
|
||||
" <h2>In-Menu Movement</h2>\n"
|
||||
" <div class=\"help_paragraph\">\n"
|
||||
" <div class=\"key_block\">\n"
|
||||
" <div class=\"key_column\" style=\"flex-grow: 1\">\n"
|
||||
|
@ -4784,8 +4801,8 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
|||
break;
|
||||
}
|
||||
|
||||
index_header Header = *(index_header *)Index->Metadata.Buffer.Ptr;
|
||||
Index->Metadata.Buffer.Ptr += sizeof(Header);
|
||||
Index->Header = *(index_header *)Index->Metadata.Buffer.Ptr;
|
||||
Index->Metadata.Buffer.Ptr += sizeof(Index->Header);
|
||||
index_metadata *Prev = { 0 };
|
||||
index_metadata *This = { 0 };
|
||||
index_metadata *Next = { 0 };
|
||||
|
@ -4795,12 +4812,12 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
|||
{
|
||||
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;
|
||||
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));
|
||||
}
|
||||
|
@ -4812,17 +4829,13 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
|||
} break;
|
||||
case LINK_EXCLUDE:
|
||||
{
|
||||
if(Index->Header.EntryCount == 1)
|
||||
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
if(Index->Header.EntryCount != 1)
|
||||
{
|
||||
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
Index->Metadata.Buffer.Ptr += sizeof(index_metadata);
|
||||
Next = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
|
||||
for(EntryIndex = 1; EntryIndex < Header.EntryCount; ++EntryIndex)
|
||||
for(EntryIndex = 1; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
|
||||
{
|
||||
Prev = This;
|
||||
This = Next;
|
||||
|
@ -5892,7 +5905,7 @@ main(int ArgC, char **Args)
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -5961,6 +5974,9 @@ main(int ArgC, char **Args)
|
|||
case 'v':
|
||||
PrintVersions();
|
||||
return RC_SUCCESS;
|
||||
case 'w':
|
||||
Config.Mode |= MODE_NOCACHE;
|
||||
break;
|
||||
case 'x':
|
||||
Config.TemplateIndexLocation = optarg;
|
||||
break;
|
||||
|
@ -6226,6 +6242,15 @@ main(int ArgC, char **Args)
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -528,7 +528,7 @@
|
|||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent {
|
||||
display: block;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
@ -575,7 +575,8 @@
|
|||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent .cineraCategories {
|
||||
margin: 4px;
|
||||
float: right;
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu > .filter_container .filter_content {
|
||||
|
|
|
@ -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");
|
||||
|
||||
window.addEventListener("blur", function(){
|
||||
|
|
|
@ -56,8 +56,6 @@ function Player(htmlContainer, refsCallback) {
|
|||
|
||||
Player.initializeYoutube(this.onYoutubeReady.bind(this));
|
||||
this.updateSize();
|
||||
|
||||
this.resume();
|
||||
}
|
||||
|
||||
// Start playing the video from the current position.
|
||||
|
@ -68,6 +66,7 @@ Player.prototype.play = function() {
|
|||
this.youtubePlayer.playVideo();
|
||||
}
|
||||
this.pauseAfterBuffer = false;
|
||||
this.resume();
|
||||
} else {
|
||||
this.shouldPlay = true;
|
||||
}
|
||||
|
@ -119,6 +118,7 @@ Player.prototype.updateSize = function() {
|
|||
this.markersContainer.style.height = height;
|
||||
if (this.youtubePlayerReady) {
|
||||
this.youtubePlayer.setSize(Math.floor(width), Math.floor(height));
|
||||
this.resume();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -929,16 +929,30 @@ function handleKey(key) {
|
|||
} break;
|
||||
|
||||
case 'N':
|
||||
case 'D':
|
||||
case 'J':
|
||||
case 'S': {
|
||||
player.jumpToNextMarker();
|
||||
} break;
|
||||
|
||||
case 'P':
|
||||
case 'A':
|
||||
case 'K':
|
||||
case 'W': {
|
||||
player.jumpToPrevMarker();
|
||||
} break;
|
||||
case '[':
|
||||
case '<': {
|
||||
if(prevEpisode)
|
||||
{
|
||||
location = prevEpisode.href;
|
||||
}
|
||||
} break;
|
||||
case ']':
|
||||
case '>': {
|
||||
if(nextEpisode)
|
||||
{
|
||||
location = nextEpisode.href;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
gotKey = false;
|
||||
} break;
|
||||
|
@ -1165,6 +1179,22 @@ function resetFade() {
|
|||
function onRefChanged(ref, element) {
|
||||
if(element.classList.contains("skip"))
|
||||
{
|
||||
var filterState;
|
||||
var ErrorCount = 0;
|
||||
if(!filter) { console.log("Missing filter_container div"); ErrorCount++; }
|
||||
if(!filterState) { console.log("Missing filterState object"); ErrorCount++; }
|
||||
if(ErrorCount > 0)
|
||||
{
|
||||
switch(ErrorCount)
|
||||
{
|
||||
case 1:
|
||||
{ console.log("This should have been generated by Cinera along with the following element containing the \"skip\" class:"); } break;
|
||||
default:
|
||||
{ console.log("These should have been generated by Cinera along with the following element containing the \"skip\" class:"); } break;
|
||||
}
|
||||
console.log(element); return;
|
||||
}
|
||||
|
||||
if(!filter.classList.contains("responsible"))
|
||||
{
|
||||
filter.classList.add("responsible");
|
||||
|
|
Binary file not shown.
|
@ -1,108 +0,0 @@
|
|||
#ifndef HMML_H_
|
||||
#define HMML_H_
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Data structures
|
||||
|
||||
typedef struct {
|
||||
char* member;
|
||||
char* stream_platform;
|
||||
char* stream_username;
|
||||
char* project;
|
||||
char* title;
|
||||
char* vod_platform;
|
||||
char* id;
|
||||
|
||||
char** co_hosts;
|
||||
size_t co_host_count;
|
||||
|
||||
char** guests;
|
||||
size_t guest_count;
|
||||
|
||||
char** annotators;
|
||||
size_t annotator_count;
|
||||
|
||||
char* template;
|
||||
char* medium;
|
||||
|
||||
} HMML_VideoMetaData;
|
||||
|
||||
typedef struct {
|
||||
char* site;
|
||||
char* page;
|
||||
char* url;
|
||||
char* title;
|
||||
char* article;
|
||||
char* author;
|
||||
char* editor;
|
||||
char* publisher;
|
||||
char* isbn;
|
||||
int offset;
|
||||
} HMML_Reference;
|
||||
|
||||
typedef enum {
|
||||
HMML_CATEGORY,
|
||||
HMML_MEMBER,
|
||||
HMML_PROJECT,
|
||||
|
||||
HMML_MARKER_COUNT,
|
||||
} HMML_MarkerType;
|
||||
|
||||
typedef struct {
|
||||
HMML_MarkerType type;
|
||||
char* marker;
|
||||
char* parameter;
|
||||
char* episode;
|
||||
int offset;
|
||||
} HMML_Marker;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
char* author;
|
||||
} HMML_Quote;
|
||||
|
||||
typedef struct {
|
||||
int line;
|
||||
char* time;
|
||||
char* text;
|
||||
char* author;
|
||||
|
||||
HMML_Reference* references;
|
||||
size_t reference_count;
|
||||
|
||||
HMML_Marker* markers;
|
||||
size_t marker_count;
|
||||
|
||||
HMML_Quote quote;
|
||||
bool is_quote;
|
||||
} HMML_Annotation;
|
||||
|
||||
typedef struct {
|
||||
int line;
|
||||
char* message;
|
||||
} HMML_Error;
|
||||
|
||||
typedef struct {
|
||||
bool well_formed;
|
||||
HMML_VideoMetaData metadata;
|
||||
HMML_Annotation* annotations;
|
||||
size_t annotation_count;
|
||||
HMML_Error error;
|
||||
} HMML_Output;
|
||||
|
||||
// Functions
|
||||
|
||||
HMML_Output hmml_parse_file (FILE* file);
|
||||
void hmml_dump (HMML_Output* output);
|
||||
void hmml_free (HMML_Output* output);
|
||||
|
||||
// Version
|
||||
|
||||
extern const struct HMML_Version {
|
||||
int Major, Minor, Patch;
|
||||
} hmml_version;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue