cinera.c: Bespoke template in Single Edition
Also fail gracefully if supplied with an .hmml file containing an incomplete [video] node, or a template containing tags whose buffers cannot be populated
This commit is contained in:
parent
8f37ce0b76
commit
c1d6c87746
205
cinera/cinera.c
205
cinera/cinera.c
|
@ -14,7 +14,7 @@ typedef struct
|
|||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 5,
|
||||
.Patch = 17
|
||||
.Patch = 18
|
||||
};
|
||||
|
||||
// TODO(matt): Copy in the DB 3 stuff from cinera_working.c
|
||||
|
@ -225,6 +225,8 @@ typedef struct
|
|||
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;
|
||||
|
@ -758,19 +760,64 @@ enum
|
|||
TEMPLATE_BESPOKE
|
||||
} templates;
|
||||
|
||||
char *
|
||||
GetDirectoryPath(char *Filepath)
|
||||
{
|
||||
char *Ptr = Filepath + StringLength(Filepath) - 1;
|
||||
while(Ptr > Filepath && *Ptr != '/')
|
||||
{
|
||||
--Ptr;
|
||||
}
|
||||
if(Ptr == Filepath)
|
||||
{
|
||||
*Ptr++ = '.';
|
||||
}
|
||||
*Ptr = '\0';
|
||||
return Filepath;
|
||||
}
|
||||
|
||||
char *
|
||||
GetBaseFilename(char *Filepath,
|
||||
char *Extension // Including the "."
|
||||
// Pass 0 to retain the whole file path, only without its parent directories
|
||||
)
|
||||
{
|
||||
char *BaseFilename = Filepath + StringLength(Filepath) - 1;
|
||||
while(BaseFilename > Filepath && *BaseFilename != '/')
|
||||
{
|
||||
--BaseFilename;
|
||||
}
|
||||
if(*BaseFilename == '/')
|
||||
{
|
||||
++BaseFilename;
|
||||
}
|
||||
BaseFilename[StringLength(BaseFilename) - StringLength(Extension)] = '\0';
|
||||
return BaseFilename;
|
||||
}
|
||||
|
||||
void
|
||||
ConstructTemplatePath(template *Template, int TemplateType)
|
||||
{
|
||||
// TODO(matt): Consider just straight up having the TemplateDir relative to the ProjectDir...
|
||||
// NOTE(matt): Bespoke template paths are set relative to:
|
||||
// in Project Edition: ProjectDir
|
||||
// in Single Edition: Parent directory of .hmml file
|
||||
|
||||
if(Template->Metadata.Filename[0] != '/')
|
||||
{
|
||||
char Temp[256];
|
||||
CopyString(Temp, Template->Metadata.Filename);
|
||||
char *Ptr = Template->Metadata.Filename;
|
||||
if(TemplateType == TEMPLATE_BESPOKE)
|
||||
{
|
||||
if(Config.Edition == EDITION_SINGLE)
|
||||
{
|
||||
Ptr += CopyString(Ptr, "%s/", GetDirectoryPath(Config.SingleHMMLFilePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
Ptr += CopyString(Ptr, "%s/", Config.ProjectDir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Ptr += CopyString(Ptr, "%s/", Config.TemplatesDir);
|
||||
|
@ -1633,10 +1680,10 @@ BuildQuote(quote_info *Info, char *Speaker, int ID)
|
|||
|
||||
int CacheSize = QuoteStaging.Ptr - QuoteStaging.Location;
|
||||
QuoteStaging.Ptr = QuoteStaging.Location;
|
||||
if(SearchQuotes(&QuoteStaging, CacheSize, Info, ID) == 1)
|
||||
if(SearchQuotes(&QuoteStaging, CacheSize, Info, ID) == RC_UNFOUND)
|
||||
{
|
||||
FreeBuffer(&QuoteStaging);
|
||||
return 1;
|
||||
return RC_UNFOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1645,14 +1692,14 @@ BuildQuote(quote_info *Info, char *Speaker, int ID)
|
|||
CurlQuotes(&QuoteStaging, QuotesURL);
|
||||
int CacheSize = QuoteStaging.Ptr - QuoteStaging.Location;
|
||||
QuoteStaging.Ptr = QuoteStaging.Location;
|
||||
if(SearchQuotes(&QuoteStaging, CacheSize, Info, ID) == 1)
|
||||
if(SearchQuotes(&QuoteStaging, CacheSize, Info, ID) == RC_UNFOUND)
|
||||
{
|
||||
FreeBuffer(&QuoteStaging);
|
||||
return 1;
|
||||
return RC_UNFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return RC_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -2176,6 +2223,8 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
RewindBuffer(&CollationBuffers->ScriptPlayer);
|
||||
RewindBuffer(&CollationBuffers->IncludesIndex);
|
||||
RewindBuffer(&CollationBuffers->ScriptIndex);
|
||||
*CollationBuffers->Title = '\0';
|
||||
*CollationBuffers->ProjectName = '\0';
|
||||
|
||||
char Filepath[256];
|
||||
if(Config.Edition == EDITION_PROJECT)
|
||||
|
@ -2200,9 +2249,58 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
|
||||
if(HMML.well_formed)
|
||||
{
|
||||
char *BaseFilename = GetBaseFilename(Filename, ".hmml");
|
||||
if(!HMML.metadata.title)
|
||||
{
|
||||
fprintf(stderr, "Please set the title attribute in the [video] node of your .hmml file\n");
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s\n", BaseFilename);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_HMML;
|
||||
}
|
||||
CopyString(CollationBuffers->Title, HMML.metadata.title);
|
||||
|
||||
if(!HMML.metadata.member)
|
||||
{
|
||||
fprintf(stderr, "Please set the member attribute in the [video] node of your .hmml file\n");
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", BaseFilename, HMML.metadata.title);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_HMML;
|
||||
}
|
||||
|
||||
if(!HMML.metadata.project && !StringsDiffer(Config.Theme, ""))
|
||||
{
|
||||
fprintf(stderr, "Unable to determine which theme to apply to the HTML\n"
|
||||
"Please set at least one of:\n"
|
||||
"\t1. project attribute in the [video] node of your .hmml file\n"
|
||||
"\t2. ProjectID on the command line with -p\n"
|
||||
"\t3. Style on the command line with -s\n"
|
||||
);
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", BaseFilename, HMML.metadata.title);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_HMML;
|
||||
}
|
||||
|
||||
if(!HMML.metadata.id)
|
||||
{
|
||||
fprintf(stderr, "Please set the id attribute in the [video] node of your .hmml file\n");
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", BaseFilename, HMML.metadata.title);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_HMML;
|
||||
}
|
||||
CopyString(CollationBuffers->VideoID, HMML.metadata.id);
|
||||
|
||||
buffer URLPlayer;
|
||||
ClaimBuffer(&URLPlayer, "URLPlayer", 2048);
|
||||
ConstructPlayerURL(&URLPlayer, BaseFilename);
|
||||
CopyString(CollationBuffers->URLPlayer, URLPlayer.Location);
|
||||
DeclaimBuffer(&URLPlayer);
|
||||
|
||||
for(int ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
|
||||
{
|
||||
if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
|
||||
if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID,
|
||||
Config.Edition == EDITION_SINGLE && HMML.metadata.project ?
|
||||
HMML.metadata.project :
|
||||
Config.ProjectID))
|
||||
{
|
||||
CopyString(CollationBuffers->ProjectName, ProjectInfo[ProjectIndex].FullName);
|
||||
break;
|
||||
|
@ -2218,8 +2316,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
}
|
||||
else
|
||||
{
|
||||
Filename[StringLength(Filename) - StringLength(".hmml")] = '\0';
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", Filename, HMML.metadata.title);
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", BaseFilename, HMML.metadata.title);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_HMML;
|
||||
}
|
||||
|
@ -2233,8 +2330,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
case RC_INVALID_TEMPLATE: // Invalid template
|
||||
case RC_ERROR_FILE: // Could not load template
|
||||
case RC_ERROR_MEMORY: // Could not allocate memory for template
|
||||
Filename[StringLength(Filename) - StringLength(".hmml")] = '\0';
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", Filename, HMML.metadata.title);
|
||||
fprintf(stderr, "\e[1;31mSkipping\e[0m %s - %s\n", BaseFilename, HMML.metadata.title);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_HMML;
|
||||
case RC_SUCCESS:
|
||||
|
@ -2242,22 +2338,6 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
}
|
||||
}
|
||||
|
||||
CopyString(CollationBuffers->Title, HMML.metadata.title);
|
||||
buffer URLPlayer;
|
||||
ClaimBuffer(&URLPlayer, "URLPlayer", 2048);
|
||||
char *Ptr = Filename;
|
||||
Ptr += (StringLength(Filename) - StringLength(".hmml"));
|
||||
if(!(StringsDiffer(Ptr, ".hmml")))
|
||||
{
|
||||
*Ptr = '\0';
|
||||
ConstructPlayerURL(&URLPlayer, Filename);
|
||||
*Ptr = '.';
|
||||
}
|
||||
|
||||
CopyString(CollationBuffers->URLPlayer, URLPlayer.Location);
|
||||
DeclaimBuffer(&URLPlayer);
|
||||
CopyString(CollationBuffers->VideoID, HMML.metadata.id);
|
||||
|
||||
#if DEBUG
|
||||
printf(
|
||||
"================================================================================\n"
|
||||
|
@ -2346,20 +2426,19 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("\n\n --- Entering Annotations Loop ---\n\n\n\n");
|
||||
#endif
|
||||
|
||||
if(Config.Edition != EDITION_SINGLE)
|
||||
{
|
||||
RewindBuffer(&CollationBuffers->Search);
|
||||
char *FilenamePtr = Filename;
|
||||
FilenamePtr += StringLength(Filename) - StringLength(".hmml");
|
||||
*FilenamePtr = '\0';
|
||||
CopyStringToBuffer(&CollationBuffers->Search, "name: \"%s\"\n"
|
||||
"title: \"", Filename);
|
||||
*FilenamePtr = '.';
|
||||
"title: \"", BaseFilename);
|
||||
CopyStringToBufferJSONSafe(&CollationBuffers->Search, HMML.metadata.title);
|
||||
CopyStringToBuffer(&CollationBuffers->Search, "\"\n"
|
||||
"markers:\n");
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("\n\n --- Entering Annotations Loop ---\n\n\n\n");
|
||||
#endif
|
||||
|
||||
for(int AnnotationIndex = 0; AnnotationIndex < HMML.annotation_count; ++AnnotationIndex)
|
||||
{
|
||||
|
@ -2711,14 +2790,16 @@ AppendedIdentifier:
|
|||
char *Speaker = Anno->quote.author ? Anno->quote.author : HMML.metadata.stream_username ? HMML.metadata.stream_username : HMML.metadata.member;
|
||||
if(BuildQuote(&QuoteInfo,
|
||||
Speaker,
|
||||
Anno->quote.id) == 1)
|
||||
Anno->quote.id) == RC_UNFOUND)
|
||||
{
|
||||
LogError(LOG_ERROR, "Quote #%s %d not found: %s:%d", Speaker, Anno->quote.id, Filename, Anno->line);
|
||||
fprintf(stderr, "%s:%d: Quote #%s %d not found. Skipping this file...\n",
|
||||
Filename,
|
||||
Anno->line,
|
||||
Filename[StringLength(Filename) - StringLength(".hmml")] = '\0';
|
||||
|
||||
fprintf(stderr, "Quote #%s %d not found\n"
|
||||
"\e[1;31mSkipping\e[0m %s - %s\n",
|
||||
Speaker,
|
||||
Anno->quote.id);
|
||||
Anno->quote.id,
|
||||
BaseFilename, HMML.metadata.title);
|
||||
hmml_free(&HMML);
|
||||
return RC_ERROR_QUOTE;
|
||||
}
|
||||
|
@ -3486,7 +3567,15 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
|
|||
switch(Template->Metadata.Tag[i].TagCode)
|
||||
{
|
||||
case TAG_PROJECT:
|
||||
if(CollationBuffers->ProjectName[0] == '\0')
|
||||
{
|
||||
fprintf(stderr, "Template contains a <!-- __CINERA_PROJECT --> tag\n"
|
||||
"Skipping just this tag, because we do not know the project's full name\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyStringToBuffer(&Output, CollationBuffers->ProjectName);
|
||||
}
|
||||
break;
|
||||
case TAG_TITLE:
|
||||
CopyStringToBuffer(&Output, CollationBuffers->Title);
|
||||
|
@ -3498,7 +3587,16 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
|
|||
CopyStringToBuffer(&Output, CollationBuffers->VideoID);
|
||||
break;
|
||||
case TAG_INDEX:
|
||||
if(Config.Edition == EDITION_SINGLE)
|
||||
{
|
||||
fprintf(stderr, "Template contains a <!-- __CINERA_INDEX --> tag\n"
|
||||
"Skipping just this tag, because an index cannot be generated for inclusion in a\n"
|
||||
"bespoke template in Single Edition\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyBuffer(&Output, &CollationBuffers->Index);
|
||||
}
|
||||
break;
|
||||
case TAG_INCLUDES:
|
||||
CopyBuffer(&Output, PageType == PAGE_PLAYER ? &CollationBuffers->IncludesPlayer : &CollationBuffers->IncludesIndex);
|
||||
|
@ -4973,7 +5071,6 @@ main(int ArgC, char **Args)
|
|||
if(ClaimBuffer(&CollationBuffers.IncludesIndex, "IncludesIndex", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
|
||||
if(ClaimBuffer(&CollationBuffers.Search, "Search", Kilobytes(32)) == RC_ARENA_FULL) { goto RIP; };
|
||||
if(ClaimBuffer(&CollationBuffers.ScriptIndex, "ScriptIndex", 256) == RC_ARENA_FULL) { goto RIP; };
|
||||
*CollationBuffers.Title = '\0';
|
||||
|
||||
// NOTE(matt): Templating
|
||||
//
|
||||
|
@ -5127,6 +5224,12 @@ NextFile:
|
|||
// TODO(matt): Just change the default output location so all these guys won't overwrite each other
|
||||
for(int FileIndex = optind; FileIndex < ArgC; ++FileIndex)
|
||||
{
|
||||
bool HasBespokeTemplate = FALSE;
|
||||
char *Ptr = Args[FileIndex];
|
||||
Ptr += (StringLength(Args[FileIndex]) - StringLength(".hmml"));
|
||||
if(!(StringsDiffer(Ptr, ".hmml")))
|
||||
{
|
||||
CopyString(Config.SingleHMMLFilePath, Args[FileIndex]);
|
||||
switch(HMMLToBuffers(&CollationBuffers, &BespokeTemplate, Args[FileIndex]))
|
||||
{
|
||||
// TODO(matt): Actually sort out the fatality of these cases, once we are always-on
|
||||
|
@ -5142,20 +5245,32 @@ NextFile:
|
|||
case RC_SUCCESS:
|
||||
break;
|
||||
};
|
||||
switch(BuffersToHTML(&CollationBuffers, PlayerTemplate, 0, PAGE_PLAYER))
|
||||
|
||||
HasBespokeTemplate = StringsDiffer(BespokeTemplate->Metadata.Filename, "");
|
||||
|
||||
switch(BuffersToHTML(&CollationBuffers,
|
||||
HasBespokeTemplate ? BespokeTemplate : PlayerTemplate,
|
||||
0,
|
||||
PAGE_PLAYER))
|
||||
{
|
||||
// TODO(matt): Actually sort out the fatality of these cases, once we are always-on
|
||||
case RC_INVALID_TEMPLATE:
|
||||
LogError(LOG_ERROR, "Invalid player template: %s", PlayerTemplate->Metadata.Filename);
|
||||
if(HasBespokeTemplate) { DeclaimTemplate(BespokeTemplate); }
|
||||
if(FileIndex < (ArgC - 1)) { goto NextFile; }
|
||||
case RC_ERROR_MEMORY:
|
||||
case RC_ERROR_FILE:
|
||||
case RC_ARENA_FULL:
|
||||
goto RIP;
|
||||
case RC_SUCCESS:
|
||||
#if 0
|
||||
fprintf(stdout, "\e[1;32mWritten\e[0m %s\n", HasBespokeTemplate ? Config.OutIntegratedLocation : Config.OutLocation);
|
||||
#endif
|
||||
if(HasBespokeTemplate) { DeclaimTemplate(BespokeTemplate); }
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(StringsDiffer(PlayerTemplate->Metadata.Filename, ""))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue