cinera.c: Enable default closed captions
This commit adds support for configurably enabling closed captions by default. Set the "default_cc_lang" in a config file, or "cc_lang" in the [video] node of an .hmml file. Once set, videos which contain captions for this langage will be initialised with these captions enabled. New config setting: default_cc_lang New [video] node field: cc_lang
This commit is contained in:
parent
554f7393ff
commit
6b09247cd2
|
@ -23,7 +23,7 @@ typedef struct
|
|||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 10,
|
||||
.Patch = 19
|
||||
.Patch = 20
|
||||
};
|
||||
|
||||
#define __USE_XOPEN2K8 // NOTE(matt): O_NOFOLLOW
|
||||
|
@ -1451,6 +1451,7 @@ file credits this person for the entire project, but indexers may \"uncredit\" p
|
|||
file credits this person for the entire project, but indexers may \"uncredit\" people in the [video] node of a HMML file." },
|
||||
{ "css_path", "Path relative to assets_root_dir and assets_root_url where CSS files are located." },
|
||||
{ "db_location", "Absolute file path where the database file resides. If you run multiple instances of Cinera on the same machine, please ensure this db_location differs between them." },
|
||||
{ "default_cc_lang", "The ISO 639-1 language code of the closed captions to enable by default. May be overridden by setting the cc_lang in the video node of an HMML file." },
|
||||
{ "default_medium", "The ID of a medium (see also medium) which will be the default for the project. May be overridden by setting the medium in the video node of an HMML file." },
|
||||
{ "deny", "See allow." },
|
||||
{ "deny_bespoke_templates", "Indexers may use the \"template\" attribute in the video node of an .hmml file to set a bespoke template for that entry, superseding any configured player_template. Setting \"deny_bespoke_templates\" to true prevents this." },
|
||||
|
@ -1586,6 +1587,7 @@ typedef enum
|
|||
IDENT_CREDIT,
|
||||
IDENT_CSS_PATH,
|
||||
IDENT_DB_LOCATION,
|
||||
IDENT_DEFAULT_CC_LANG,
|
||||
IDENT_DEFAULT_MEDIUM,
|
||||
IDENT_DENY,
|
||||
IDENT_DENY_BESPOKE_TEMPLATES,
|
||||
|
@ -1963,18 +1965,14 @@ ConfigError(string *Filename, uint64_t LineNumber, severity Severity, char *Mess
|
|||
|
||||
void
|
||||
ConfigErrorField(string *Filename, uint64_t LineNumber, severity Severity, config_identifier_id FieldID,
|
||||
char *Message, string *Received)
|
||||
string *Received, char *Message)
|
||||
{
|
||||
ErrorFilenameAndLineNumber(Filename, LineNumber, Severity, ED_CONFIG);
|
||||
fprintf(stderr,
|
||||
"Faulty %s%s%s %s",
|
||||
"%s%s%s value %s%.*s%s %s\n",
|
||||
ColourStrings[CS_YELLOW_BOLD], ConfigIdentifiers[FieldID].String, ColourStrings[CS_END],
|
||||
ColourStrings[CS_MAGENTA_BOLD], (int)Received->Length, Received->Base, ColourStrings[CS_END],
|
||||
Message);
|
||||
if(Received)
|
||||
{
|
||||
PrintStringC(CS_MAGENTA_BOLD, *Received);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2139,6 +2137,25 @@ IndexingErrorClash(string *Filename, uint64_t LineNumber, severity Severity, cha
|
|||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
PrintValidLanguageCodeChars(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
" Valid characters:\n"
|
||||
" a to z\n"
|
||||
" A to Z\n"
|
||||
" 0 to 9\n"
|
||||
" - (hyphen)\n");
|
||||
}
|
||||
|
||||
void
|
||||
IndexingErrorInvalidLanguageCode(string *Filename, uint64_t LineNumber, char *Key, string Received)
|
||||
{
|
||||
ErrorFilenameAndLineNumber(Filename, LineNumber, S_ERROR, ED_INDEXING);
|
||||
fprintf(stderr, "%s value %s%.*s%s contains invalid character(s)\n",
|
||||
Key, ColourStrings[CS_MAGENTA_BOLD], (int)Received.Length, Received.Base, ColourStrings[CS_END]);
|
||||
}
|
||||
|
||||
void
|
||||
IndexingErrorInvalidSubstring(string *Filename, uint64_t LineNumber, char *Key, string Received, string InvalidSubstring)
|
||||
{
|
||||
|
@ -2481,6 +2498,23 @@ IsValidIdentifierCharacter(char C)
|
|||
return ((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || C == '_' || C == '-');
|
||||
}
|
||||
|
||||
bool
|
||||
IsValidLanguageCode(string S)
|
||||
{
|
||||
// TODO(matt): Add an upper limit to the length
|
||||
bool Result = TRUE;
|
||||
for(int i = 0; i < S.Length; ++i)
|
||||
{
|
||||
char C = S.Base[i];
|
||||
if(!((C >= '0' && C <= '9') || (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || C == '-'))
|
||||
{
|
||||
Result = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool
|
||||
IsNumber(char C)
|
||||
{
|
||||
|
@ -11054,6 +11088,18 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
}
|
||||
}
|
||||
|
||||
string CCLang = CurrentProject->DefaultCCLang;
|
||||
if(HMML.metadata.cc_lang)
|
||||
{
|
||||
CCLang = Wrap0(HMML.metadata.cc_lang);
|
||||
if(!IsValidLanguageCode(CCLang))
|
||||
{
|
||||
IndexingErrorInvalidLanguageCode(&FilepathL, 0, "cc_lang", CCLang);
|
||||
PrintValidLanguageCodeChars();
|
||||
Result = RC_ERROR_HMML;
|
||||
}
|
||||
}
|
||||
|
||||
string OutputLocation = {};
|
||||
if(!HMML.metadata.output)
|
||||
{
|
||||
|
@ -11230,8 +11276,17 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
|
||||
CopyStringToBuffer(&PlayerBuffers.Main,
|
||||
"<div class=\"cineraPlayerContainer\">\n"
|
||||
" <div class=\"video_container\" data-platform=\"%s\" data-videoId=\"%s\"></div>\n"
|
||||
" <div class=\"markers_container %.*s\">\n", VODPlatformStrings[CollationBuffers->VODPlatform], HMML.metadata.id, (int)CurrentProject->Theme.Length, CurrentProject->Theme.Base);
|
||||
" <div class=\"video_container\" data-platform=\"%s\" data-videoId=\"%s\"", VODPlatformStrings[CollationBuffers->VODPlatform], HMML.metadata.id);
|
||||
|
||||
if(CCLang.Length > 0)
|
||||
{
|
||||
CopyStringToBuffer(&PlayerBuffers.Main,
|
||||
" data-ccLang=\"%.*s\"", (int)CCLang.Length, CCLang.Base);
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&PlayerBuffers.Main,
|
||||
"></div>\n"
|
||||
" <div class=\"markers_container %.*s\">\n", (int)CurrentProject->Theme.Length, CurrentProject->Theme.Base);
|
||||
|
||||
if(N)
|
||||
{
|
||||
|
|
|
@ -526,6 +526,7 @@ typedef struct project
|
|||
string TemplatesDir;
|
||||
string SearchTemplatePath;
|
||||
string PlayerTemplatePath;
|
||||
string DefaultCCLang;
|
||||
|
||||
string BaseDir;
|
||||
string BaseURL;
|
||||
|
@ -918,6 +919,7 @@ InitTypeSpecs(void)
|
|||
PushTypeSpecField(Root, FT_STRING, IDENT_COHOST, FALSE);
|
||||
PushTypeSpecField(Root, FT_STRING, IDENT_CSS_PATH, TRUE);
|
||||
PushTypeSpecField(Root, FT_STRING, IDENT_DB_LOCATION, TRUE);
|
||||
PushTypeSpecField(Root, FT_STRING, IDENT_DEFAULT_CC_LANG, TRUE);
|
||||
PushTypeSpecField(Root, FT_STRING, IDENT_DEFAULT_MEDIUM, TRUE);
|
||||
PushTypeSpecField(Root, FT_STRING, IDENT_GENRE, TRUE);
|
||||
PushTypeSpecField(Root, FT_STRING, IDENT_GLOBAL_SEARCH_DIR, TRUE);
|
||||
|
@ -1018,6 +1020,7 @@ InitTypeSpecs(void)
|
|||
config_type_spec *Project = PushTypeSpec(&Result, IDENT_PROJECT, TRUE);
|
||||
PushTypeSpecField(Project, FT_STRING, IDENT_BASE_DIR, TRUE);
|
||||
PushTypeSpecField(Project, FT_STRING, IDENT_BASE_URL, TRUE);
|
||||
PushTypeSpecField(Project, FT_STRING, IDENT_DEFAULT_CC_LANG, TRUE);
|
||||
PushTypeSpecField(Project, FT_STRING, IDENT_DEFAULT_MEDIUM, TRUE);
|
||||
PushTypeSpecField(Project, FT_STRING, IDENT_GENRE, TRUE);
|
||||
PushTypeSpecField(Project, FT_STRING, IDENT_HMML_DIR, TRUE);
|
||||
|
@ -3491,16 +3494,16 @@ PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope
|
|||
if(QuotemarkCount == 1)
|
||||
{
|
||||
string Filepath = Wrap0(Pair->Position.Filename);
|
||||
ConfigErrorField(&Filepath, Pair->Position.LineNumber, S_ERROR, IDENT_NAME,
|
||||
"contains unpaired quotation mark: ", &This->Name);
|
||||
ConfigErrorField(&Filepath, Pair->Position.LineNumber, S_ERROR, IDENT_NAME, &This->Name,
|
||||
"contains unpaired quotation mark");
|
||||
PushError(E, S_ERROR, 0, Pair->Key);
|
||||
NamingError = TRUE;
|
||||
}
|
||||
else if(QuotemarkCount > 2)
|
||||
{
|
||||
string Filepath = Wrap0(Pair->Position.Filename);
|
||||
ConfigErrorField(&Filepath, Pair->Position.LineNumber, S_ERROR, IDENT_NAME,
|
||||
"contains more than one pair of quotation marks: ", &This->Name);
|
||||
ConfigErrorField(&Filepath, Pair->Position.LineNumber, S_ERROR, IDENT_NAME, &This->Name,
|
||||
"contains more than one pair of quotation marks");
|
||||
PushError(E, S_ERROR, 0, Pair->Key);
|
||||
NamingError = TRUE;
|
||||
}
|
||||
|
@ -3744,6 +3747,17 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
|
|||
switch(This->Key)
|
||||
{
|
||||
// NOTE(matt): String
|
||||
case IDENT_DEFAULT_CC_LANG:
|
||||
{
|
||||
P->DefaultCCLang = ResolveString(C, E, ProjectTree, This, FALSE);
|
||||
if(!IsValidLanguageCode(P->DefaultCCLang))
|
||||
{
|
||||
ConfigErrorField(&Filepath, This->Position.LineNumber, S_ERROR, This->Key, &P->DefaultCCLang,
|
||||
"contains invalid character(s)");
|
||||
PrintValidLanguageCodeChars();
|
||||
PushError(E, S_ERROR, 0, This->Key);
|
||||
}
|
||||
} break;
|
||||
case IDENT_DEFAULT_MEDIUM:
|
||||
{ P->DefaultMedium = GetMediumFromProject(P, This->String); } break;
|
||||
case IDENT_HMML_DIR:
|
||||
|
@ -4801,6 +4815,7 @@ PrintProject(config *C, project *P, typography *T, int Ancestors, int Indentatio
|
|||
|
||||
TypesetPair(T, Generation, IDENT_TITLE, P->Title, AvailableColumns);
|
||||
TypesetPair(T, Generation, IDENT_HTML_TITLE, P->HTMLTitle, AvailableColumns);
|
||||
TypesetPair(T, Generation, IDENT_DEFAULT_CC_LANG, P->DefaultCCLang.Length ? P->DefaultCCLang : EmptyString(), AvailableColumns);
|
||||
TypesetPair(T, Generation, IDENT_DEFAULT_MEDIUM, P->DefaultMedium ? P->DefaultMedium->ID : EmptyString(), AvailableColumns);
|
||||
|
||||
TypesetPair(T, Generation, IDENT_HMML_DIR, P->HMMLDir, AvailableColumns);
|
||||
|
|
|
@ -965,10 +965,19 @@ Player.prototype.onPlatformReady = function() {
|
|||
{
|
||||
this.videoContainer.style.position = "relative";
|
||||
this.videoContainer.style.alignSelf = "unset";
|
||||
this.platformPlayer = new Vimeo.Player(platformPlayerDiv.id, {
|
||||
|
||||
var CallData = {
|
||||
id: this.videoContainer.getAttribute("data-videoId"),
|
||||
title: false,
|
||||
});
|
||||
};
|
||||
var CCLang = this.videoContainer.getAttribute("data-ccLang");
|
||||
if(CCLang != null)
|
||||
{
|
||||
CallData.texttrack = CCLang;
|
||||
}
|
||||
|
||||
this.platformPlayer = new Vimeo.Player(platformPlayerDiv.id, CallData);
|
||||
|
||||
this.platformPlayer.ready()
|
||||
.then(this.onPlatformPlayerReady.bind(this));
|
||||
this.platformPlayer.on("playbackratechange", this.onVimeoPlayerPlaybackRateChange.bind(this));
|
||||
|
@ -980,7 +989,7 @@ Player.prototype.onPlatformReady = function() {
|
|||
} break;
|
||||
case vod_platform.YOUTUBE:
|
||||
{
|
||||
this.platformPlayer = new YT.Player(platformPlayerDiv.id, {
|
||||
var CallData = {
|
||||
videoId: this.videoContainer.getAttribute("data-videoId"),
|
||||
width: this.videoContainer.offsetWidth,
|
||||
height: this.videoContainer.offsetWidth / 16 * 9,
|
||||
|
@ -990,7 +999,15 @@ Player.prototype.onPlatformReady = function() {
|
|||
"onStateChange": this.onYouTubePlayerStateChange.bind(this),
|
||||
"onPlaybackRateChange": this.onYouTubePlayerPlaybackRateChange.bind(this)
|
||||
}
|
||||
});
|
||||
};
|
||||
var CCLang = this.videoContainer.getAttribute("data-ccLang");
|
||||
if(CCLang != null)
|
||||
{
|
||||
CallData.cc_lang_pref = CCLang;
|
||||
CallData.cc_load_policy = 1;
|
||||
}
|
||||
|
||||
this.platformPlayer = new YT.Player(platformPlayerDiv.id, CallData);
|
||||
} break;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@ typedef struct {
|
|||
char* template;
|
||||
char* medium;
|
||||
char* number;
|
||||
char* cc_lang;
|
||||
|
||||
HMML_Credit* credits;
|
||||
size_t credit_count;
|
||||
|
@ -737,6 +738,7 @@ static void _hmml_parse_video(struct _hmml_parser* p)
|
|||
{ HSTR("medium") , &p->out.metadata.medium },
|
||||
{ HSTR("number") , &p->out.metadata.number },
|
||||
{ HSTR("output") , &p->out.metadata.output },
|
||||
{ HSTR("cc_lang") , &p->out.metadata.cc_lang },
|
||||
};
|
||||
|
||||
for(;;) {
|
||||
|
@ -822,7 +824,7 @@ void hmml_free(HMML_Output* out)
|
|||
}
|
||||
|
||||
const struct HMML_Version hmml_version = {
|
||||
2, 0, 13
|
||||
2, 0, 14
|
||||
};
|
||||
|
||||
#undef HSTX
|
||||
|
|
Loading…
Reference in New Issue