diff --git a/cinera/cinera.c b/cinera/cinera.c index 9718b87..288d706 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 7, - .Patch = 7 + .Patch = 8 }; #include // NOTE(matt): varargs @@ -1306,6 +1306,7 @@ video node of the entries for which they should be credited." { "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_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." }, { "genre", "This is a setting for the future. We currently only support the \"video\" genre, which is the default." }, { "global_search_dir", "Absolute directory path, where the global search page will be located, collating the search pages of all projects in the Cinera instance." }, { "global_search_template", "Path of a HTML template file relative to the global_templates_dir from which the global search page will be generated." }, @@ -1425,6 +1426,7 @@ typedef enum IDENT_DB_LOCATION, IDENT_DEFAULT_MEDIUM, IDENT_DENY, + IDENT_DENY_BESPOKE_TEMPLATES, IDENT_GENRE, IDENT_GLOBAL_SEARCH_DIR, IDENT_GLOBAL_SEARCH_TEMPLATE, @@ -4640,16 +4642,16 @@ PrintAssetsBlock_(db_block_assets *B, int LineNumber) } char * -ConstructDirectoryPath(db_header_project *P, string *PageLocation, string *EntryOutput) +ConstructDirectoryPath(string *BaseDir, string *PageLocation, string *EntryOutput) { char *Result = 0; - if(P) + if(BaseDir) { - ExtendString0(&Result, Wrap0i(P->BaseDir, sizeof(P->BaseDir))); + ExtendString0(&Result, *BaseDir); } if(PageLocation && PageLocation->Length > 0) { - if(P) + if(BaseDir) { ExtendString0(&Result, Wrap0("/")); } @@ -4665,18 +4667,17 @@ ConstructDirectoryPath(db_header_project *P, string *PageLocation, string *Entry } char * -ConstructHTMLIndexFilePath(db_header_project *P, string *PageLocation, string *EntryOutput) +ConstructHTMLIndexFilePath(string *BaseDir, string *PageLocation, string *EntryOutput) { - char *Result = ConstructDirectoryPath(P, PageLocation, EntryOutput); + char *Result = ConstructDirectoryPath(BaseDir, PageLocation, EntryOutput); ExtendString0(&Result, Wrap0("/index.html")); return Result; } rc -ReadSearchPageIntoBuffer(db_header_project *P, file *File) +ReadSearchPageIntoBuffer(file *File, string *BaseDir, string *SearchLocation) { - string SearchLocationL = Wrap0i(P->SearchLocation, sizeof(P->SearchLocation)); - File->Path = ConstructHTMLIndexFilePath(P, &SearchLocationL, 0); + File->Path = ConstructHTMLIndexFilePath(BaseDir, SearchLocation, 0); return ReadFileIntoBuffer(File); } @@ -4690,11 +4691,9 @@ ReadGlobalSearchPageIntoBuffer(file *File) } rc -ReadPlayerPageIntoBuffer(db_header_project *P, file *File, db_entry *Entry) +ReadPlayerPageIntoBuffer(file *File, string BaseDir, string PlayerLocation, string OutputLocation) { - string EntryOutput = Wrap0i(Entry->OutputLocation, sizeof(Entry->OutputLocation)); - string PlayerLocationL = Wrap0i(P->PlayerLocation, sizeof(P->PlayerLocation)); - File->Path = ConstructHTMLIndexFilePath(P, &PlayerLocationL, &EntryOutput); + File->Path = ConstructHTMLIndexFilePath(&BaseDir, &PlayerLocation, &OutputLocation); return ReadFileIntoBuffer(File); } @@ -4718,7 +4717,10 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum) db_entry *Entry = LocateEntry(Landmark->Project, Landmark->EntryIndex); if(Entry) { - FileReadRC = ReadPlayerPageIntoBuffer(P, &HTML, Entry); + string BaseDir = Wrap0i(P->BaseDir, sizeof(P->BaseDir)); + string PlayerLocation = Wrap0i(P->PlayerLocation, sizeof(P->PlayerLocation)); + string OutputLocation = Wrap0i(Entry->OutputLocation, sizeof(Entry->OutputLocation)); + FileReadRC = ReadPlayerPageIntoBuffer(&HTML, BaseDir, PlayerLocation, OutputLocation); } else { @@ -4737,7 +4739,9 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum) { if(P) { - FileReadRC = ReadSearchPageIntoBuffer(P, &HTML); + string BaseDir = Wrap0i(P->BaseDir, sizeof(P->BaseDir)); + string SearchLocation = Wrap0i(P->SearchLocation, sizeof(P->SearchLocation)); + FileReadRC = ReadSearchPageIntoBuffer(&HTML, &BaseDir, &SearchLocation); } else { @@ -8653,31 +8657,27 @@ DeclaimPlayerBuffers(player_buffers *B) } char * -ConstructIndexFilePath(db_header_project *Project) +ConstructIndexFilePath(string BaseDir, string SearchLocation, string ProjectID) { - string SearchLocation = Wrap0i(Project->SearchLocation, sizeof(Project->SearchLocation)); - char *Result = ConstructDirectoryPath(Project, &SearchLocation, 0); + char *Result = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0); ExtendString0(&Result, Wrap0("/")); - ExtendString0(&Result, Wrap0i(Project->ID, sizeof(Project->ID))); + ExtendString0(&Result, ProjectID); ExtendString0(&Result, ExtensionStrings[EXT_INDEX]); return Result; } void -DeleteSearchPageFromFilesystem(db_header_project *Project) // NOTE(matt): Do we need to handle relocating, like the PlayerPage function? +DeleteSearchPageFromFilesystem(string BaseDir, string SearchLocation, string ProjectID) // NOTE(matt): Do we need to handle relocating, like the PlayerPage function? { - string SearchLocationL = Wrap0i(Project->SearchLocation, sizeof(Project->SearchLocation)); - char *SearchPagePath = ConstructHTMLIndexFilePath(Project, &SearchLocationL, 0); + char *SearchPagePath = ConstructHTMLIndexFilePath(&BaseDir, &SearchLocation, 0); remove(SearchPagePath); Free(SearchPagePath); - char *IndexFilePath = ConstructIndexFilePath(Project); - remove(IndexFilePath); - Free(IndexFilePath); - // TODO(matt): Consider the correctness of this + remove(DB.File.Path); + // TODO(matt): Consider the correctness of this. FreeFile(&DB.File); - char *SearchDirectory = ConstructDirectoryPath(Project, &SearchLocationL, 0); + char *SearchDirectory = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0); remove(SearchDirectory); Free(SearchDirectory); } @@ -8714,10 +8714,9 @@ PrintLineageAndEntry(string Lineage, string EntryID, string EntryTitle, bool App } rc -DeletePlayerPageFromFilesystem(db_header_project *P, string EntryOutput, bool Relocating, bool Echo) +DeletePlayerPageFromFilesystem(string BaseDir, string PlayerLocation, string EntryOutput, bool Relocating, bool Echo) { - string PlayerLocation = Wrap0i(P->PlayerLocation, sizeof(P->PlayerLocation)); - char *OutputDirectoryPath = ConstructDirectoryPath(P, &PlayerLocation, &EntryOutput); + char *OutputDirectoryPath = ConstructDirectoryPath(&BaseDir, &PlayerLocation, &EntryOutput); DIR *PlayerDir; if((PlayerDir = opendir(OutputDirectoryPath))) // There is a directory for the Player, which there probably should be if not for manual intervention @@ -8951,7 +8950,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF if(!HaveErrors) { - if(HMML.metadata.template) + if(!CurrentProject->DenyBespokeTemplates && HMML.metadata.template) { switch(PackTemplate(BespokeTemplate, Wrap0(HMML.metadata.template), TEMPLATE_BESPOKE, CurrentProject)) { @@ -8993,7 +8992,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF string NewOutputLocation = Wrap0i(N->WorkingThis.OutputLocation, sizeof(N->WorkingThis.OutputLocation)); if(StringsDiffer(OldOutputLocation, NewOutputLocation)) { - DeletePlayerPageFromFilesystem(N->Project, OldOutputLocation, FALSE, TRUE); + DeletePlayerPageFromFilesystem(CurrentProject->BaseDir, CurrentProject->PlayerLocation, OldOutputLocation, FALSE, TRUE); } } @@ -10703,23 +10702,24 @@ void InitIndexFile(project *P) { DB.File.Buffer.ID = BID_DATABASE; - DB.File = InitFile(&P->BaseDir, &P->ID, EXT_INDEX); + DB.File.Path = ConstructIndexFilePath(P->BaseDir, P->SearchLocation, P->ID); ReadFileIntoBuffer(&DB.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail? if(!DB.File.Buffer.Location) { - char *BaseDir0 = MakeString0("l", &P->BaseDir); - DIR *OutputDirectoryHandle = opendir(BaseDir0); + string IndexFileDir = StripComponentFromPath(Wrap0(DB.File.Path)); + char *IndexFileDir0 = MakeString0("l", &IndexFileDir); + DIR *OutputDirectoryHandle = opendir(IndexFileDir0); if(!OutputDirectoryHandle) { - if(!MakeDir(P->BaseDir)) + if(!MakeDir(IndexFileDir)) { LogError(LOG_ERROR, "Unable to create directory %.*s: %s", (int)P->BaseDir.Length, P->BaseDir.Base, strerror(errno)); fprintf(stderr, "Unable to create directory %.*s: %s\n", (int)P->BaseDir.Length, P->BaseDir.Base, strerror(errno)); - Free(BaseDir0); + Free(IndexFileDir0); return; }; } - Free(BaseDir0); + Free(IndexFileDir0); closedir(OutputDirectoryHandle); DB.File.Handle = fopen(DB.File.Path, "w"); @@ -11905,7 +11905,7 @@ InsertNeighbourLink(db_header_project *P, db_entry *From, db_entry *To, enum8(li { MEM_TEST_INITIAL(); file HTML = {}; - ReadPlayerPageIntoBuffer(P, &HTML, From); + ReadPlayerPageIntoBuffer(&HTML, Wrap0i(P->BaseDir, sizeof(P->BaseDir)), Wrap0i(P->PlayerLocation, sizeof(P->PlayerLocation)), Wrap0i(From->OutputLocation, sizeof(From->OutputLocation))); MEM_TEST_MID("InsertNeighbourLink1"); if(HTML.Buffer.Location) @@ -12050,7 +12050,7 @@ DeleteNeighbourLinks(neighbourhood *N) } file HTML = {}; - ReadPlayerPageIntoBuffer(N->Project, &HTML, Entry); + ReadPlayerPageIntoBuffer(&HTML, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)), Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)), Wrap0i(Entry->OutputLocation, sizeof(Entry->OutputLocation))); if(HTML.Buffer.Location) { if(!(HTML.Handle = fopen(HTML.Path, "w"))) { FreeFile(&HTML); return RC_ERROR_FILE; }; @@ -12130,7 +12130,7 @@ MarkNextAsFirst(neighbourhood *N) { // TODO(matt): We added some untested logic in here. If things related to the prev / next links fail, we screwed up here file HTML = {}; - ReadPlayerPageIntoBuffer(N->Project, &HTML, N->Next); + ReadPlayerPageIntoBuffer(&HTML, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)), Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)), Wrap0i(N->Next->OutputLocation, sizeof(N->Next->OutputLocation))); if(HTML.Buffer.Location) { buffer Link; @@ -12167,32 +12167,32 @@ MarkNextAsFirst(neighbourhood *N) void MarkPrevAsFinal(neighbourhood *N) { - file File = {}; - ReadPlayerPageIntoBuffer(N->Project, &File, N->Prev); + file HTML = {}; + ReadPlayerPageIntoBuffer(&HTML, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)), Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)), Wrap0i(N->Prev->OutputLocation, sizeof(N->Prev->OutputLocation))); - if(File.Buffer.Location) + if(HTML.Buffer.Location) { - File.Handle = fopen(File.Path, "w"); + HTML.Handle = fopen(HTML.Path, "w"); buffer Link; ClaimBuffer(&Link, BID_LINK, Kilobytes(4)); - fwrite(File.Buffer.Location, N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart, 1, File.Handle); + fwrite(HTML.Buffer.Location, N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart, 1, HTML.Handle); CopyStringToBuffer(&Link, "
You have arrived at the (current) end of %.*s
\n", (int)CurrentProject->Title.Length, CurrentProject->Title.Base); - fwrite(Link.Location, (Link.Ptr - Link.Location), 1, File.Handle); + fwrite(Link.Location, (Link.Ptr - Link.Location), 1, HTML.Handle); - fwrite(File.Buffer.Location + N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart + N->Prev->LinkOffsets.NextEnd, - File.Buffer.Size - (N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart + N->Prev->LinkOffsets.NextEnd), + fwrite(HTML.Buffer.Location + N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart + N->Prev->LinkOffsets.NextEnd, + HTML.Buffer.Size - (N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart + N->Prev->LinkOffsets.NextEnd), 1, - File.Handle); + HTML.Handle); N->Prev->LinkOffsets.NextEnd = Link.Ptr - Link.Location; DeclaimBuffer(&Link); - fclose(File.Handle); + fclose(HTML.Handle); } else { @@ -12200,7 +12200,7 @@ MarkPrevAsFinal(neighbourhood *N) N->Prev->LinkOffsets = Blank; } - FreeFile(&File); + FreeFile(&HTML); } void @@ -12308,7 +12308,7 @@ DeleteFromDB(neighbourhood *N, string BaseFilename) --NewEntryCount; if(NewEntryCount == 0) { - DeleteSearchPageFromFilesystem(N->Project); + DeleteSearchPageFromFilesystem(Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)), Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)), Wrap0i(N->Project->ID, sizeof(N->Project->ID))); DeleteLandmarksForSearch(CurrentProject->Index); UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts); } @@ -12369,6 +12369,10 @@ GenerateFilterOfProjectAndChildren(buffer *Filter, db_header_project *StoredP, p OpenNodeNewLine(Filter, &Filter->IndentLevel, NODE_DIV, 0); AppendStringToBuffer(Filter, Wrap0(" class=\"cineraFilterProject\" data-baseURL=\"")); AppendStringToBuffer(Filter, P->BaseURL); + AppendStringToBuffer(Filter, Wrap0("\" data-searchLocation=\"")); + AppendStringToBuffer(Filter, P->SearchLocation); + AppendStringToBuffer(Filter, Wrap0("\" data-playerLocation=\"")); + AppendStringToBuffer(Filter, P->PlayerLocation); AppendStringToBuffer(Filter, Wrap0("\">")); OpenNodeNewLine(Filter, &Filter->IndentLevel, NODE_SPAN, 0); @@ -12406,6 +12410,8 @@ GenerateIndexOfProjectAndChildren(buffer *Index, db_header_project *StoredP, pro AppendStringToBuffer(Index, P->ID); AppendStringToBuffer(Index, Wrap0("\" data-baseURL=\"")); AppendStringToBuffer(Index, P->BaseURL); + AppendStringToBuffer(Index, Wrap0("\" data-searchLocation=\"")); + AppendStringToBuffer(Index, P->SearchLocation); AppendStringToBuffer(Index, Wrap0("\" data-playerLocation=\"")); AppendStringToBuffer(Index, P->PlayerLocation); AppendStringToBuffer(Index, Wrap0("\">")); @@ -12909,9 +12915,10 @@ int GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *PlayerTemplate, string OutputLocation, bool Reinserting) { MEM_TEST_INITIAL(); - string PlayerLocationL = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); MEM_TEST_MID("GeneratePlayerPage1"); - char *PlayerPath = ConstructDirectoryPath(N->Project, &PlayerLocationL, &OutputLocation); + string BaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)); + string PlayerLocation = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); + char *PlayerPath = ConstructDirectoryPath(&BaseDir, &PlayerLocation, &OutputLocation); MEM_TEST_MID("GeneratePlayerPage2"); DIR *OutputDirectoryHandle; @@ -12966,8 +12973,9 @@ GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *Player rc GenerateSearchPage(neighbourhood *N, buffers *CollationBuffers, db_header_project *StoredP, project *P) { - string SearchLocationL = Wrap0i(StoredP->SearchLocation, sizeof(StoredP->SearchLocation)); - char *SearchPath = ConstructDirectoryPath(StoredP, &SearchLocationL, 0); + string BaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)); + string SearchLocation = Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)); + char *SearchPath = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0); DIR *OutputDirectoryHandle; if(!(OutputDirectoryHandle = opendir(SearchPath))) // TODO(matt): open() @@ -12994,7 +13002,7 @@ GenerateSearchPage(neighbourhood *N, buffers *CollationBuffers, db_header_projec } case RC_NOOP: { - DeleteSearchPageFromFilesystem(StoredP); + DeleteSearchPageFromFilesystem(BaseDir, SearchLocation, P->ID); DeleteLandmarksForSearch(P->Index); UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts); break; @@ -13093,7 +13101,10 @@ DeleteEntry(neighbourhood *N, string BaseFilename) { LinkNeighbours(N, LINK_EXCLUDE); - DeletePlayerPageFromFilesystem(N->Project, BaseFilename, FALSE, TRUE); + string BaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)); + string PlayerLocation = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); + DeletePlayerPageFromFilesystem(BaseDir, PlayerLocation, BaseFilename, FALSE, TRUE); + UpdateLandmarksForNeighbourhood(N, EDIT_DELETION); return RC_SUCCESS; } @@ -13336,18 +13347,22 @@ rc DeleteDeadDBEntries(neighbourhood *N, bool *Modified) { // TODO(matt): Additionally remove the BaseDir if it changed - bool NewPlayerLocation = FALSE; - bool NewSearchLocation = FALSE; + bool HasNewPlayerLocation = FALSE; + bool HasNewSearchLocation = FALSE; + + // TODO(matt): Here is where the relocation happens. This could be wrong if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))) || StringsDiffer(CurrentProject->PlayerLocation, Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)))) { - string PlayerLocationL = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); - char *OldPlayerDirectory = ConstructDirectoryPath(N->Project, &PlayerLocationL, 0); + string OldBaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)); + string OldPlayerLocation = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); + char *OldPlayerDirectory = ConstructDirectoryPath(&OldBaseDir, &OldPlayerLocation, 0); db_header_project NewProjectHeader = *N->Project; ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir); - char *NewPlayerDirectory = ConstructDirectoryPath(&NewProjectHeader, &CurrentProject->PlayerLocation, 0); + string NewBaseDir = Wrap0i(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir)); + char *NewPlayerDirectory = ConstructDirectoryPath(&NewBaseDir, &CurrentProject->PlayerLocation, 0); printf("%sRelocating Player Page%s from %s to %s%s\n", ColourStrings[CS_REINSERTION], N->Project->EntryCount > 1 ? "s" : "", @@ -13358,29 +13373,35 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified) for(int EntryIndex = 0; EntryIndex < N->Project->EntryCount; ++EntryIndex) { db_entry *This = FirstEntry + EntryIndex; - DeletePlayerPageFromFilesystem(N->Project, Wrap0i(This->OutputLocation, sizeof(This->OutputLocation)), TRUE, TRUE); + string BaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)); + string PlayerLocation = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); + DeletePlayerPageFromFilesystem(BaseDir, PlayerLocation, Wrap0i(This->OutputLocation, sizeof(This->OutputLocation)), TRUE, TRUE); } - if(PlayerLocationL.Length > 0) + if(OldPlayerLocation.Length > 0) { RemoveChildDirectories(Wrap0(OldPlayerDirectory), Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))); } Free(OldPlayerDirectory); ClearCopyStringNoFormat(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation), CurrentProject->PlayerLocation); - NewPlayerLocation = TRUE; + HasNewPlayerLocation = TRUE; } if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))) || StringsDiffer(CurrentProject->SearchLocation, Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)))) { - string SearchLocationL = Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)); - char *OldSearchDirectory = ConstructDirectoryPath(N->Project, &SearchLocationL, 0); + string OldBaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)); + string OldSearchLocation = Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)); + char *OldSearchDirectory = ConstructDirectoryPath(&OldBaseDir, &OldSearchLocation, 0); db_header_project NewProjectHeader = *N->Project; ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir); ClearCopyStringNoFormat(NewProjectHeader.SearchLocation, sizeof(NewProjectHeader.SearchLocation), CurrentProject->SearchLocation); - char *NewSearchDirectory = ConstructDirectoryPath(&NewProjectHeader, &CurrentProject->SearchLocation, 0); + string NewBaseDir = Wrap0i(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir)); + string NewSearchLocation = Wrap0i(NewProjectHeader.SearchLocation, sizeof(NewProjectHeader.SearchLocation)); + + char *NewSearchDirectory = ConstructDirectoryPath(&NewBaseDir, &NewSearchLocation, 0); MakeDir(Wrap0(NewSearchDirectory)); printf("%sRelocating Search Page from %s to %s%s\n", @@ -13392,8 +13413,8 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified) Free(OldSearchPagePath); Free(NewSearchPagePath); - char *OldSearchIndexPath = ConstructIndexFilePath(N->Project); - char *NewSearchIndexPath = ConstructIndexFilePath(&NewProjectHeader); + char *OldSearchIndexPath = ConstructIndexFilePath(OldBaseDir, OldSearchLocation, Wrap0i(N->Project->ID, sizeof(N->Project->ID))); + char *NewSearchIndexPath = ConstructIndexFilePath(NewBaseDir, NewSearchLocation, Wrap0i(N->Project->ID, sizeof(N->Project->ID))); rename(OldSearchIndexPath, NewSearchIndexPath); Free(OldSearchIndexPath); Free(NewSearchIndexPath); @@ -13401,10 +13422,10 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified) Free(NewSearchDirectory); FreeFile(&DB.File); - DB.File = InitFile(&CurrentProject->BaseDir, &CurrentProject->ID, EXT_INDEX); + DB.File.Path = ConstructIndexFilePath(CurrentProject->BaseDir, CurrentProject->SearchLocation, CurrentProject->ID); ReadFileIntoBuffer(&DB.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail? - if(SearchLocationL.Length > 0) + if(OldSearchLocation.Length > 0) { RemoveChildDirectories(Wrap0(OldSearchDirectory), Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))); } @@ -13412,7 +13433,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified) remove(OldSearchDirectory); Free(OldSearchDirectory); ClearCopyStringNoFormat(N->Project->SearchLocation, sizeof(N->Project->SearchLocation), CurrentProject->SearchLocation); - NewSearchLocation = TRUE; + HasNewSearchLocation = TRUE; } if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)))) @@ -13435,7 +13456,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified) *Modified = TRUE; } - if(NewPlayerLocation || NewSearchLocation) + if(HasNewPlayerLocation || HasNewSearchLocation) { if(!(DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"))) { FreeBuffer(&DB.Metadata.File.Buffer); return RC_ERROR_FILE; } ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir); @@ -14113,13 +14134,16 @@ DeleteHTMLFilesOfProject(db_header_project *Project) char *Ptr = (char *)Project; Ptr += sizeof(db_header_project) + sizeof(db_entry) * Project->EntryCount; + string BaseDir = Wrap0i(Project->BaseDir, sizeof(Project->BaseDir)); + string PlayerLocation = Wrap0i(Project->PlayerLocation, sizeof(Project->PlayerLocation)); + db_entry *Entry = LocateFirstEntry(Project); for(int i = 0; i < Project->EntryCount; ++i, ++Entry) { - DeletePlayerPageFromFilesystem(Project, Wrap0i(Entry->OutputLocation, sizeof(Entry->OutputLocation)), FALSE, FALSE); + DeletePlayerPageFromFilesystem(BaseDir, PlayerLocation, Wrap0i(Entry->OutputLocation, sizeof(Entry->OutputLocation)), FALSE, FALSE); } - DeleteSearchPageFromFilesystem(Project); + DeleteSearchPageFromFilesystem(BaseDir, PlayerLocation, Wrap0i(Project->ID, sizeof(Project->ID))); return Ptr; } @@ -14132,7 +14156,9 @@ DeleteHTMLFilesOfProjectAndChildren(db_header_project *Project) { Ptr = DeleteHTMLFilesOfProjectAndChildren(Ptr); } - DeleteSearchPageFromFilesystem(Project); + string BaseDir = Wrap0i(Project->BaseDir, sizeof(Project->BaseDir)); + string SearchLocation = Wrap0i(Project->SearchLocation, sizeof(Project->SearchLocation)); + DeleteSearchPageFromFilesystem(BaseDir, SearchLocation, Wrap0i(Project->ID, sizeof(Project->ID))); return Ptr; } @@ -14437,7 +14463,10 @@ SyncProjects_TopLevel(project_generations *G, project *C, db_block_projects **SP if((*SChild)->ChildCount == 0 && (*SChild)->EntryCount == 0) { - DeleteSearchPageFromFilesystem(*SChild); + string BaseDir = Wrap0i((*SChild)->BaseDir, sizeof((*SChild)->BaseDir)); + string SearchLocation = Wrap0i((*SChild)->SearchLocation, sizeof((*SChild)->SearchLocation)); + string ProjectID = Wrap0i((*SChild)->ID, sizeof((*SChild)->ID)); + DeleteSearchPageFromFilesystem(BaseDir, SearchLocation, ProjectID); DeleteLandmarksForSearch(C->Index); DeleteStaleAssets(); } @@ -14491,7 +14520,11 @@ SyncProjects(project_generations *G, project *C, db_header_project **SParent, db if((*SChild)->ChildCount == 0 && (*SChild)->EntryCount == 0) { - DeleteSearchPageFromFilesystem(*SChild); + string BaseDir = Wrap0i((*SChild)->BaseDir, sizeof((*SChild)->BaseDir)); + string SearchLocation = Wrap0i((*SChild)->SearchLocation, sizeof((*SChild)->SearchLocation)); + string ProjectID = Wrap0i((*SChild)->ID, sizeof((*SChild)->ID)); + DeleteSearchPageFromFilesystem(BaseDir, SearchLocation, ProjectID); + DeleteLandmarksForSearch(C->Index); } diff --git a/cinera/cinera_config.c b/cinera/cinera_config.c index d42454d..83a9ae0 100644 --- a/cinera/cinera_config.c +++ b/cinera/cinera_config.c @@ -521,6 +521,7 @@ typedef struct project string StreamUsername; string VODPlatform; + bool DenyBespokeTemplates; bool SingleBrowserTab; bool IgnorePrivacy; @@ -917,6 +918,7 @@ InitTypeSpecs(void) //// PushTypeSpecField(Root, FT_STRING, IDENT_UNIT, TRUE); PushTypeSpecField(Root, FT_BARE, IDENT_TITLE_LIST_END, TRUE); + PushTypeSpecField(Root, FT_BOOLEAN, IDENT_DENY_BESPOKE_TEMPLATES, TRUE); PushTypeSpecField(Root, FT_BOOLEAN, IDENT_IGNORE_PRIVACY, TRUE); PushTypeSpecField(Root, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, TRUE); PushTypeSpecField(Root, FT_NUMBER, IDENT_PRIVACY_CHECK_INTERVAL, TRUE); @@ -997,6 +999,7 @@ InitTypeSpecs(void) PushTypeSpecField(Project, FT_BARE, IDENT_TITLE_LIST_END, TRUE); // NOTE(matt): Modes + PushTypeSpecField(Project, FT_BOOLEAN, IDENT_DENY_BESPOKE_TEMPLATES, TRUE); PushTypeSpecField(Project, FT_BOOLEAN, IDENT_IGNORE_PRIVACY, TRUE); PushTypeSpecField(Project, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, TRUE); // @@ -3377,6 +3380,8 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc config_bool_pair *This = ProjectTree->BoolPairs + i; switch(This->Key) { + case IDENT_DENY_BESPOKE_TEMPLATES: + { P->DenyBespokeTemplates = This->Value; } break; case IDENT_IGNORE_PRIVACY: { P->IgnorePrivacy = This->Value; } break; case IDENT_SINGLE_BROWSER_TAB: diff --git a/cinera/cinera_search.js b/cinera/cinera_search.js index df5b460..49ed393 100644 --- a/cinera/cinera_search.js +++ b/cinera/cinera_search.js @@ -34,10 +34,11 @@ function hideEntriesOfProject(ProjectElement) ProjectElement.classList.add("off"); } var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value; + var searchLocation = ProjectElement.attributes.getNamedItem("data-searchLocation").value; for(var i = 0; i < projects.length; ++i) { var ThisProject = projects[i]; - if(ThisProject.baseURL === baseURL) + if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation) { ThisProject.filteredOut = true; if(ThisProject.entriesContainer != null) @@ -56,10 +57,11 @@ function showEntriesOfProject(ProjectElement) ProjectElement.classList.remove("off"); } var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value; + var searchLocation = ProjectElement.attributes.getNamedItem("data-searchLocation").value; for(var i = 0; i < projects.length; ++i) { var ThisProject = projects[i]; - if(ThisProject.baseURL === baseURL) + if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation) { ThisProject.filteredOut = false; if(ThisProject.entriesContainer != null) @@ -71,7 +73,7 @@ function showEntriesOfProject(ProjectElement) } } -function hideProjectSearchResults(baseURL) +function hideProjectSearchResults(baseURL, playerLocation) { var cineraResults = document.getElementById("cineraResults"); if(cineraResults) @@ -80,7 +82,8 @@ function hideProjectSearchResults(baseURL) for(var i = 0; i < cineraResultsProjects.length; ++i) { var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value; - if(baseURL === resultBaseURL) + var resultPlayerLocation = cineraResultsProjects[i].attributes.getNamedItem("data-playerLocation").value; + if(baseURL === resultBaseURL && playerLocation === resultPlayerLocation) { cineraResultsProjects[i].style.display = "none"; return; @@ -89,7 +92,7 @@ function hideProjectSearchResults(baseURL) } } -function showProjectSearchResults(baseURL) +function showProjectSearchResults(baseURL, playerLocation) { var cineraResults = document.getElementById("cineraResults"); if(cineraResults) @@ -98,7 +101,8 @@ function showProjectSearchResults(baseURL) for(var i = 0; i < cineraResultsProjects.length; ++i) { var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value; - if(baseURL === resultBaseURL) + var resultPlayerLocation = cineraResultsProjects[i].attributes.getNamedItem("data-playerLocation").value; + if(baseURL === resultBaseURL && playerLocation === resultPlayerLocation) { cineraResultsProjects[i].style.display = "flex"; return; @@ -110,6 +114,7 @@ function showProjectSearchResults(baseURL) function toggleEntriesOfProjectAndChildren(ProjectFilterElement) { var baseURL = ProjectFilterElement.attributes.getNamedItem("data-baseURL").value; + var searchLocation = ProjectFilterElement.attributes.getNamedItem("data-searchLocation").value; var shouldShow = ProjectFilterElement.classList.contains("off"); if(shouldShow) { @@ -125,7 +130,8 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement) for(var i = 0; i < projects.length; ++i) { var ThisProject = projects[i]; - if(ThisProject.baseURL === baseURL) + + if(ThisProject.baseURL === baseURL && ThisProject.searchLocation === searchLocation) { if(shouldShow) { @@ -135,7 +141,7 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement) { ThisProject.entriesContainer.style.display = "flex"; } - showProjectSearchResults(projects[i].baseURL); + showProjectSearchResults(ThisProject.baseURL, ThisProject.playerLocation); } else { @@ -145,7 +151,7 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement) { ThisProject.entriesContainer.style.display = "none"; } - hideProjectSearchResults(ThisProject.baseURL); + hideProjectSearchResults(ThisProject.baseURL, ThisProject.playerLocation); } } } @@ -155,17 +161,17 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement) for(var j = 0; j < indexChildFilterProjects.length; ++j) { var ThisElement = indexChildFilterProjects[j]; + var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value; + var playerLocation = ThisElement.attributes.getNamedItem("data-playerLocation").value; if(shouldShow) { - var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value; showEntriesOfProject(ThisElement); - showProjectSearchResults(baseURL); + showProjectSearchResults(baseURL, playerLocation); } else { - var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value; hideEntriesOfProject(ThisElement); - hideProjectSearchResults(baseURL); + hideProjectSearchResults(baseURL, playerLocation); } } } @@ -280,14 +286,17 @@ function prepareProjects() { var ID = projectsContainer[i].attributes.getNamedItem("data-project").value; var baseURL = projectsContainer[i].attributes.getNamedItem("data-baseURL").value; + var searchLocation = projectsContainer[i].attributes.getNamedItem("data-searchLocation").value; var playerLocation = projectsContainer[i].attributes.getNamedItem("data-playerLocation").value; var theme = projectsContainer[i].classList.item(1); projects[i] = { baseURL: baseURL, + searchLocation: searchLocation, + playerLocation: playerLocation, playerURLPrefix: (baseURL ? baseURL + "/" : "") + (playerLocation ? playerLocation + "/" : ""), - indexLocation: (baseURL ? baseURL + "/" : "") + ID + ".index", + indexLocation: (baseURL ? baseURL + "/" : "") + (searchLocation ? searchLocation + "/" : "") + ID + ".index", projectTitleElement: projectsContainer[i].querySelector(":scope > .cineraProjectTitle"), entriesContainer: projectsContainer[i].querySelector(":scope > .cineraIndexEntries"), dayContainerPrototype: dayContainerPrototype.cloneNode(true), @@ -529,6 +538,7 @@ function renderResults() { if(projects[i].playerURLPrefix === episode.playerURLPrefix) { projectContainer.setAttribute("data-baseURL", projects[i].baseURL); + projectContainer.setAttribute("data-playerLocation", projects[i].playerLocation); if(projects[i].filteredOut) { projectContainer.style.display = "none";