Fix search_ and player_location related bugs

On the search pages use the search_location and player_location, in
addition to the base_url, to associate filter and index entries, such
that the filter actually works.

Fix the .index file location for projects with a search_location. As
this is now consistent, we happen to fix a crash that happened when
changing the search_location.

New config option:

    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.
This commit is contained in:
Matt Mascarenhas 2020-05-17 02:04:26 +01:00
parent e2ea8fdaf3
commit 9dfdc117be
3 changed files with 144 additions and 96 deletions

View File

@ -23,7 +23,7 @@ typedef struct
version CINERA_APP_VERSION = { version CINERA_APP_VERSION = {
.Major = 0, .Major = 0,
.Minor = 7, .Minor = 7,
.Patch = 7 .Patch = 8
}; };
#include <stdarg.h> // NOTE(matt): varargs #include <stdarg.h> // 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." }, { "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." }, { "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", "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." }, { "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_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." }, { "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_DB_LOCATION,
IDENT_DEFAULT_MEDIUM, IDENT_DEFAULT_MEDIUM,
IDENT_DENY, IDENT_DENY,
IDENT_DENY_BESPOKE_TEMPLATES,
IDENT_GENRE, IDENT_GENRE,
IDENT_GLOBAL_SEARCH_DIR, IDENT_GLOBAL_SEARCH_DIR,
IDENT_GLOBAL_SEARCH_TEMPLATE, IDENT_GLOBAL_SEARCH_TEMPLATE,
@ -4640,16 +4642,16 @@ PrintAssetsBlock_(db_block_assets *B, int LineNumber)
} }
char * char *
ConstructDirectoryPath(db_header_project *P, string *PageLocation, string *EntryOutput) ConstructDirectoryPath(string *BaseDir, string *PageLocation, string *EntryOutput)
{ {
char *Result = 0; char *Result = 0;
if(P) if(BaseDir)
{ {
ExtendString0(&Result, Wrap0i(P->BaseDir, sizeof(P->BaseDir))); ExtendString0(&Result, *BaseDir);
} }
if(PageLocation && PageLocation->Length > 0) if(PageLocation && PageLocation->Length > 0)
{ {
if(P) if(BaseDir)
{ {
ExtendString0(&Result, Wrap0("/")); ExtendString0(&Result, Wrap0("/"));
} }
@ -4665,18 +4667,17 @@ ConstructDirectoryPath(db_header_project *P, string *PageLocation, string *Entry
} }
char * 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")); ExtendString0(&Result, Wrap0("/index.html"));
return Result; return Result;
} }
rc 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(BaseDir, SearchLocation, 0);
File->Path = ConstructHTMLIndexFilePath(P, &SearchLocationL, 0);
return ReadFileIntoBuffer(File); return ReadFileIntoBuffer(File);
} }
@ -4690,11 +4691,9 @@ ReadGlobalSearchPageIntoBuffer(file *File)
} }
rc 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)); File->Path = ConstructHTMLIndexFilePath(&BaseDir, &PlayerLocation, &OutputLocation);
string PlayerLocationL = Wrap0i(P->PlayerLocation, sizeof(P->PlayerLocation));
File->Path = ConstructHTMLIndexFilePath(P, &PlayerLocationL, &EntryOutput);
return ReadFileIntoBuffer(File); return ReadFileIntoBuffer(File);
} }
@ -4718,7 +4717,10 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum)
db_entry *Entry = LocateEntry(Landmark->Project, Landmark->EntryIndex); db_entry *Entry = LocateEntry(Landmark->Project, Landmark->EntryIndex);
if(Entry) 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 else
{ {
@ -4737,7 +4739,9 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum)
{ {
if(P) 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 else
{ {
@ -8653,31 +8657,27 @@ DeclaimPlayerBuffers(player_buffers *B)
} }
char * char *
ConstructIndexFilePath(db_header_project *Project) ConstructIndexFilePath(string BaseDir, string SearchLocation, string ProjectID)
{ {
string SearchLocation = Wrap0i(Project->SearchLocation, sizeof(Project->SearchLocation)); char *Result = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0);
char *Result = ConstructDirectoryPath(Project, &SearchLocation, 0);
ExtendString0(&Result, Wrap0("/")); ExtendString0(&Result, Wrap0("/"));
ExtendString0(&Result, Wrap0i(Project->ID, sizeof(Project->ID))); ExtendString0(&Result, ProjectID);
ExtendString0(&Result, ExtensionStrings[EXT_INDEX]); ExtendString0(&Result, ExtensionStrings[EXT_INDEX]);
return Result; return Result;
} }
void 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(&BaseDir, &SearchLocation, 0);
char *SearchPagePath = ConstructHTMLIndexFilePath(Project, &SearchLocationL, 0);
remove(SearchPagePath); remove(SearchPagePath);
Free(SearchPagePath); Free(SearchPagePath);
char *IndexFilePath = ConstructIndexFilePath(Project); remove(DB.File.Path);
remove(IndexFilePath); // TODO(matt): Consider the correctness of this.
Free(IndexFilePath);
// TODO(matt): Consider the correctness of this
FreeFile(&DB.File); FreeFile(&DB.File);
char *SearchDirectory = ConstructDirectoryPath(Project, &SearchLocationL, 0); char *SearchDirectory = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0);
remove(SearchDirectory); remove(SearchDirectory);
Free(SearchDirectory); Free(SearchDirectory);
} }
@ -8714,10 +8714,9 @@ PrintLineageAndEntry(string Lineage, string EntryID, string EntryTitle, bool App
} }
rc 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(&BaseDir, &PlayerLocation, &EntryOutput);
char *OutputDirectoryPath = ConstructDirectoryPath(P, &PlayerLocation, &EntryOutput);
DIR *PlayerDir; DIR *PlayerDir;
if((PlayerDir = opendir(OutputDirectoryPath))) // There is a directory for the Player, which there probably should be if not for manual intervention 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(!HaveErrors)
{ {
if(HMML.metadata.template) if(!CurrentProject->DenyBespokeTemplates && HMML.metadata.template)
{ {
switch(PackTemplate(BespokeTemplate, Wrap0(HMML.metadata.template), TEMPLATE_BESPOKE, CurrentProject)) 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)); string NewOutputLocation = Wrap0i(N->WorkingThis.OutputLocation, sizeof(N->WorkingThis.OutputLocation));
if(StringsDiffer(OldOutputLocation, NewOutputLocation)) 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) InitIndexFile(project *P)
{ {
DB.File.Buffer.ID = BID_DATABASE; 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? ReadFileIntoBuffer(&DB.File); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
if(!DB.File.Buffer.Location) if(!DB.File.Buffer.Location)
{ {
char *BaseDir0 = MakeString0("l", &P->BaseDir); string IndexFileDir = StripComponentFromPath(Wrap0(DB.File.Path));
DIR *OutputDirectoryHandle = opendir(BaseDir0); char *IndexFileDir0 = MakeString0("l", &IndexFileDir);
DIR *OutputDirectoryHandle = opendir(IndexFileDir0);
if(!OutputDirectoryHandle) 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)); 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)); fprintf(stderr, "Unable to create directory %.*s: %s\n", (int)P->BaseDir.Length, P->BaseDir.Base, strerror(errno));
Free(BaseDir0); Free(IndexFileDir0);
return; return;
}; };
} }
Free(BaseDir0); Free(IndexFileDir0);
closedir(OutputDirectoryHandle); closedir(OutputDirectoryHandle);
DB.File.Handle = fopen(DB.File.Path, "w"); 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(); MEM_TEST_INITIAL();
file HTML = {}; 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"); MEM_TEST_MID("InsertNeighbourLink1");
if(HTML.Buffer.Location) if(HTML.Buffer.Location)
@ -12050,7 +12050,7 @@ DeleteNeighbourLinks(neighbourhood *N)
} }
file HTML = {}; 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.Buffer.Location)
{ {
if(!(HTML.Handle = fopen(HTML.Path, "w"))) { FreeFile(&HTML); return RC_ERROR_FILE; }; 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 // TODO(matt): We added some untested logic in here. If things related to the prev / next links fail, we screwed up here
file HTML = {}; 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) if(HTML.Buffer.Location)
{ {
buffer Link; buffer Link;
@ -12167,32 +12167,32 @@ MarkNextAsFirst(neighbourhood *N)
void void
MarkPrevAsFinal(neighbourhood *N) MarkPrevAsFinal(neighbourhood *N)
{ {
file File = {}; file HTML = {};
ReadPlayerPageIntoBuffer(N->Project, &File, N->Prev); 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; buffer Link;
ClaimBuffer(&Link, BID_LINK, Kilobytes(4)); 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, CopyStringToBuffer(&Link,
" <div class=\"episodeMarker last\"><div>&#8226;</div><div>You have arrived at the (current) end of <cite>%.*s</cite></div><div>&#8226;</div></div>\n", (int)CurrentProject->Title.Length, CurrentProject->Title.Base); " <div class=\"episodeMarker last\"><div>&#8226;</div><div>You have arrived at the (current) end of <cite>%.*s</cite></div><div>&#8226;</div></div>\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, fwrite(HTML.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), HTML.Buffer.Size - (N->Prev->LinkOffsets.PrevStart + N->Prev->LinkOffsets.PrevEnd + N->Prev->LinkOffsets.NextStart + N->Prev->LinkOffsets.NextEnd),
1, 1,
File.Handle); HTML.Handle);
N->Prev->LinkOffsets.NextEnd = Link.Ptr - Link.Location; N->Prev->LinkOffsets.NextEnd = Link.Ptr - Link.Location;
DeclaimBuffer(&Link); DeclaimBuffer(&Link);
fclose(File.Handle); fclose(HTML.Handle);
} }
else else
{ {
@ -12200,7 +12200,7 @@ MarkPrevAsFinal(neighbourhood *N)
N->Prev->LinkOffsets = Blank; N->Prev->LinkOffsets = Blank;
} }
FreeFile(&File); FreeFile(&HTML);
} }
void void
@ -12308,7 +12308,7 @@ DeleteFromDB(neighbourhood *N, string BaseFilename)
--NewEntryCount; --NewEntryCount;
if(NewEntryCount == 0) 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); DeleteLandmarksForSearch(CurrentProject->Index);
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts); UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
} }
@ -12369,6 +12369,10 @@ GenerateFilterOfProjectAndChildren(buffer *Filter, db_header_project *StoredP, p
OpenNodeNewLine(Filter, &Filter->IndentLevel, NODE_DIV, 0); OpenNodeNewLine(Filter, &Filter->IndentLevel, NODE_DIV, 0);
AppendStringToBuffer(Filter, Wrap0(" class=\"cineraFilterProject\" data-baseURL=\"")); AppendStringToBuffer(Filter, Wrap0(" class=\"cineraFilterProject\" data-baseURL=\""));
AppendStringToBuffer(Filter, P->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("\">")); AppendStringToBuffer(Filter, Wrap0("\">"));
OpenNodeNewLine(Filter, &Filter->IndentLevel, NODE_SPAN, 0); 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, P->ID);
AppendStringToBuffer(Index, Wrap0("\" data-baseURL=\"")); AppendStringToBuffer(Index, Wrap0("\" data-baseURL=\""));
AppendStringToBuffer(Index, P->BaseURL); AppendStringToBuffer(Index, P->BaseURL);
AppendStringToBuffer(Index, Wrap0("\" data-searchLocation=\""));
AppendStringToBuffer(Index, P->SearchLocation);
AppendStringToBuffer(Index, Wrap0("\" data-playerLocation=\"")); AppendStringToBuffer(Index, Wrap0("\" data-playerLocation=\""));
AppendStringToBuffer(Index, P->PlayerLocation); AppendStringToBuffer(Index, P->PlayerLocation);
AppendStringToBuffer(Index, Wrap0("\">")); AppendStringToBuffer(Index, Wrap0("\">"));
@ -12909,9 +12915,10 @@ int
GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *PlayerTemplate, string OutputLocation, bool Reinserting) GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *PlayerTemplate, string OutputLocation, bool Reinserting)
{ {
MEM_TEST_INITIAL(); MEM_TEST_INITIAL();
string PlayerLocationL = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation));
MEM_TEST_MID("GeneratePlayerPage1"); 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"); MEM_TEST_MID("GeneratePlayerPage2");
DIR *OutputDirectoryHandle; DIR *OutputDirectoryHandle;
@ -12966,8 +12973,9 @@ GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *Player
rc rc
GenerateSearchPage(neighbourhood *N, buffers *CollationBuffers, db_header_project *StoredP, project *P) GenerateSearchPage(neighbourhood *N, buffers *CollationBuffers, db_header_project *StoredP, project *P)
{ {
string SearchLocationL = Wrap0i(StoredP->SearchLocation, sizeof(StoredP->SearchLocation)); string BaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir));
char *SearchPath = ConstructDirectoryPath(StoredP, &SearchLocationL, 0); string SearchLocation = Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation));
char *SearchPath = ConstructDirectoryPath(&BaseDir, &SearchLocation, 0);
DIR *OutputDirectoryHandle; DIR *OutputDirectoryHandle;
if(!(OutputDirectoryHandle = opendir(SearchPath))) // TODO(matt): open() if(!(OutputDirectoryHandle = opendir(SearchPath))) // TODO(matt): open()
@ -12994,7 +13002,7 @@ GenerateSearchPage(neighbourhood *N, buffers *CollationBuffers, db_header_projec
} }
case RC_NOOP: case RC_NOOP:
{ {
DeleteSearchPageFromFilesystem(StoredP); DeleteSearchPageFromFilesystem(BaseDir, SearchLocation, P->ID);
DeleteLandmarksForSearch(P->Index); DeleteLandmarksForSearch(P->Index);
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts); UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
break; break;
@ -13093,7 +13101,10 @@ DeleteEntry(neighbourhood *N, string BaseFilename)
{ {
LinkNeighbours(N, LINK_EXCLUDE); 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); UpdateLandmarksForNeighbourhood(N, EDIT_DELETION);
return RC_SUCCESS; return RC_SUCCESS;
} }
@ -13336,18 +13347,22 @@ rc
DeleteDeadDBEntries(neighbourhood *N, bool *Modified) DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
{ {
// TODO(matt): Additionally remove the BaseDir if it changed // TODO(matt): Additionally remove the BaseDir if it changed
bool NewPlayerLocation = FALSE; bool HasNewPlayerLocation = FALSE;
bool NewSearchLocation = 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))) || if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))) ||
StringsDiffer(CurrentProject->PlayerLocation, Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)))) StringsDiffer(CurrentProject->PlayerLocation, Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation))))
{ {
string PlayerLocationL = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation)); string OldBaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir));
char *OldPlayerDirectory = ConstructDirectoryPath(N->Project, &PlayerLocationL, 0); string OldPlayerLocation = Wrap0i(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation));
char *OldPlayerDirectory = ConstructDirectoryPath(&OldBaseDir, &OldPlayerLocation, 0);
db_header_project NewProjectHeader = *N->Project; db_header_project NewProjectHeader = *N->Project;
ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir); 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", printf("%sRelocating Player Page%s from %s to %s%s\n",
ColourStrings[CS_REINSERTION], N->Project->EntryCount > 1 ? "s" : "", 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) for(int EntryIndex = 0; EntryIndex < N->Project->EntryCount; ++EntryIndex)
{ {
db_entry *This = FirstEntry + 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))); RemoveChildDirectories(Wrap0(OldPlayerDirectory), Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)));
} }
Free(OldPlayerDirectory); Free(OldPlayerDirectory);
ClearCopyStringNoFormat(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation), CurrentProject->PlayerLocation); 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))) || if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))) ||
StringsDiffer(CurrentProject->SearchLocation, Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)))) StringsDiffer(CurrentProject->SearchLocation, Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation))))
{ {
string SearchLocationL = Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation)); string OldBaseDir = Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir));
char *OldSearchDirectory = ConstructDirectoryPath(N->Project, &SearchLocationL, 0); string OldSearchLocation = Wrap0i(N->Project->SearchLocation, sizeof(N->Project->SearchLocation));
char *OldSearchDirectory = ConstructDirectoryPath(&OldBaseDir, &OldSearchLocation, 0);
db_header_project NewProjectHeader = *N->Project; db_header_project NewProjectHeader = *N->Project;
ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir); ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormat(NewProjectHeader.SearchLocation, sizeof(NewProjectHeader.SearchLocation), CurrentProject->SearchLocation); 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)); MakeDir(Wrap0(NewSearchDirectory));
printf("%sRelocating Search Page from %s to %s%s\n", printf("%sRelocating Search Page from %s to %s%s\n",
@ -13392,8 +13413,8 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
Free(OldSearchPagePath); Free(OldSearchPagePath);
Free(NewSearchPagePath); Free(NewSearchPagePath);
char *OldSearchIndexPath = ConstructIndexFilePath(N->Project); char *OldSearchIndexPath = ConstructIndexFilePath(OldBaseDir, OldSearchLocation, Wrap0i(N->Project->ID, sizeof(N->Project->ID)));
char *NewSearchIndexPath = ConstructIndexFilePath(&NewProjectHeader); char *NewSearchIndexPath = ConstructIndexFilePath(NewBaseDir, NewSearchLocation, Wrap0i(N->Project->ID, sizeof(N->Project->ID)));
rename(OldSearchIndexPath, NewSearchIndexPath); rename(OldSearchIndexPath, NewSearchIndexPath);
Free(OldSearchIndexPath); Free(OldSearchIndexPath);
Free(NewSearchIndexPath); Free(NewSearchIndexPath);
@ -13401,10 +13422,10 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
Free(NewSearchDirectory); Free(NewSearchDirectory);
FreeFile(&DB.File); 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? 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))); RemoveChildDirectories(Wrap0(OldSearchDirectory), Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir)));
} }
@ -13412,7 +13433,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
remove(OldSearchDirectory); remove(OldSearchDirectory);
Free(OldSearchDirectory); Free(OldSearchDirectory);
ClearCopyStringNoFormat(N->Project->SearchLocation, sizeof(N->Project->SearchLocation), CurrentProject->SearchLocation); 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)))) if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir, sizeof(N->Project->BaseDir))))
@ -13435,7 +13456,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
*Modified = TRUE; *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; } 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); ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
@ -14113,13 +14134,16 @@ DeleteHTMLFilesOfProject(db_header_project *Project)
char *Ptr = (char *)Project; char *Ptr = (char *)Project;
Ptr += sizeof(db_header_project) + sizeof(db_entry) * Project->EntryCount; 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); db_entry *Entry = LocateFirstEntry(Project);
for(int i = 0; i < Project->EntryCount; ++i, ++Entry) 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; return Ptr;
} }
@ -14132,7 +14156,9 @@ DeleteHTMLFilesOfProjectAndChildren(db_header_project *Project)
{ {
Ptr = DeleteHTMLFilesOfProjectAndChildren(Ptr); 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; return Ptr;
} }
@ -14437,7 +14463,10 @@ SyncProjects_TopLevel(project_generations *G, project *C, db_block_projects **SP
if((*SChild)->ChildCount == 0 && (*SChild)->EntryCount == 0) 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); DeleteLandmarksForSearch(C->Index);
DeleteStaleAssets(); DeleteStaleAssets();
} }
@ -14491,7 +14520,11 @@ SyncProjects(project_generations *G, project *C, db_header_project **SParent, db
if((*SChild)->ChildCount == 0 && (*SChild)->EntryCount == 0) 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); DeleteLandmarksForSearch(C->Index);
} }

View File

@ -521,6 +521,7 @@ typedef struct project
string StreamUsername; string StreamUsername;
string VODPlatform; string VODPlatform;
bool DenyBespokeTemplates;
bool SingleBrowserTab; bool SingleBrowserTab;
bool IgnorePrivacy; bool IgnorePrivacy;
@ -917,6 +918,7 @@ InitTypeSpecs(void)
//// ////
PushTypeSpecField(Root, FT_STRING, IDENT_UNIT, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_UNIT, TRUE);
PushTypeSpecField(Root, FT_BARE, IDENT_TITLE_LIST_END, 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_IGNORE_PRIVACY, TRUE);
PushTypeSpecField(Root, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, TRUE); PushTypeSpecField(Root, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, TRUE);
PushTypeSpecField(Root, FT_NUMBER, IDENT_PRIVACY_CHECK_INTERVAL, 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); PushTypeSpecField(Project, FT_BARE, IDENT_TITLE_LIST_END, TRUE);
// NOTE(matt): Modes // 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_IGNORE_PRIVACY, TRUE);
PushTypeSpecField(Project, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, 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; config_bool_pair *This = ProjectTree->BoolPairs + i;
switch(This->Key) switch(This->Key)
{ {
case IDENT_DENY_BESPOKE_TEMPLATES:
{ P->DenyBespokeTemplates = This->Value; } break;
case IDENT_IGNORE_PRIVACY: case IDENT_IGNORE_PRIVACY:
{ P->IgnorePrivacy = This->Value; } break; { P->IgnorePrivacy = This->Value; } break;
case IDENT_SINGLE_BROWSER_TAB: case IDENT_SINGLE_BROWSER_TAB:

View File

@ -34,10 +34,11 @@ function hideEntriesOfProject(ProjectElement)
ProjectElement.classList.add("off"); ProjectElement.classList.add("off");
} }
var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value; var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value;
var searchLocation = ProjectElement.attributes.getNamedItem("data-searchLocation").value;
for(var i = 0; i < projects.length; ++i) for(var i = 0; i < projects.length; ++i)
{ {
var ThisProject = projects[i]; var ThisProject = projects[i];
if(ThisProject.baseURL === baseURL) if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation)
{ {
ThisProject.filteredOut = true; ThisProject.filteredOut = true;
if(ThisProject.entriesContainer != null) if(ThisProject.entriesContainer != null)
@ -56,10 +57,11 @@ function showEntriesOfProject(ProjectElement)
ProjectElement.classList.remove("off"); ProjectElement.classList.remove("off");
} }
var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value; var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value;
var searchLocation = ProjectElement.attributes.getNamedItem("data-searchLocation").value;
for(var i = 0; i < projects.length; ++i) for(var i = 0; i < projects.length; ++i)
{ {
var ThisProject = projects[i]; var ThisProject = projects[i];
if(ThisProject.baseURL === baseURL) if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation)
{ {
ThisProject.filteredOut = false; ThisProject.filteredOut = false;
if(ThisProject.entriesContainer != null) if(ThisProject.entriesContainer != null)
@ -71,7 +73,7 @@ function showEntriesOfProject(ProjectElement)
} }
} }
function hideProjectSearchResults(baseURL) function hideProjectSearchResults(baseURL, playerLocation)
{ {
var cineraResults = document.getElementById("cineraResults"); var cineraResults = document.getElementById("cineraResults");
if(cineraResults) if(cineraResults)
@ -80,7 +82,8 @@ function hideProjectSearchResults(baseURL)
for(var i = 0; i < cineraResultsProjects.length; ++i) for(var i = 0; i < cineraResultsProjects.length; ++i)
{ {
var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value; 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"; cineraResultsProjects[i].style.display = "none";
return; return;
@ -89,7 +92,7 @@ function hideProjectSearchResults(baseURL)
} }
} }
function showProjectSearchResults(baseURL) function showProjectSearchResults(baseURL, playerLocation)
{ {
var cineraResults = document.getElementById("cineraResults"); var cineraResults = document.getElementById("cineraResults");
if(cineraResults) if(cineraResults)
@ -98,7 +101,8 @@ function showProjectSearchResults(baseURL)
for(var i = 0; i < cineraResultsProjects.length; ++i) for(var i = 0; i < cineraResultsProjects.length; ++i)
{ {
var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value; 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"; cineraResultsProjects[i].style.display = "flex";
return; return;
@ -110,6 +114,7 @@ function showProjectSearchResults(baseURL)
function toggleEntriesOfProjectAndChildren(ProjectFilterElement) function toggleEntriesOfProjectAndChildren(ProjectFilterElement)
{ {
var baseURL = ProjectFilterElement.attributes.getNamedItem("data-baseURL").value; var baseURL = ProjectFilterElement.attributes.getNamedItem("data-baseURL").value;
var searchLocation = ProjectFilterElement.attributes.getNamedItem("data-searchLocation").value;
var shouldShow = ProjectFilterElement.classList.contains("off"); var shouldShow = ProjectFilterElement.classList.contains("off");
if(shouldShow) if(shouldShow)
{ {
@ -125,7 +130,8 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement)
for(var i = 0; i < projects.length; ++i) for(var i = 0; i < projects.length; ++i)
{ {
var ThisProject = projects[i]; var ThisProject = projects[i];
if(ThisProject.baseURL === baseURL)
if(ThisProject.baseURL === baseURL && ThisProject.searchLocation === searchLocation)
{ {
if(shouldShow) if(shouldShow)
{ {
@ -135,7 +141,7 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement)
{ {
ThisProject.entriesContainer.style.display = "flex"; ThisProject.entriesContainer.style.display = "flex";
} }
showProjectSearchResults(projects[i].baseURL); showProjectSearchResults(ThisProject.baseURL, ThisProject.playerLocation);
} }
else else
{ {
@ -145,7 +151,7 @@ function toggleEntriesOfProjectAndChildren(ProjectFilterElement)
{ {
ThisProject.entriesContainer.style.display = "none"; 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) for(var j = 0; j < indexChildFilterProjects.length; ++j)
{ {
var ThisElement = indexChildFilterProjects[j]; var ThisElement = indexChildFilterProjects[j];
var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value;
var playerLocation = ThisElement.attributes.getNamedItem("data-playerLocation").value;
if(shouldShow) if(shouldShow)
{ {
var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value;
showEntriesOfProject(ThisElement); showEntriesOfProject(ThisElement);
showProjectSearchResults(baseURL); showProjectSearchResults(baseURL, playerLocation);
} }
else else
{ {
var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value;
hideEntriesOfProject(ThisElement); hideEntriesOfProject(ThisElement);
hideProjectSearchResults(baseURL); hideProjectSearchResults(baseURL, playerLocation);
} }
} }
} }
@ -280,14 +286,17 @@ function prepareProjects()
{ {
var ID = projectsContainer[i].attributes.getNamedItem("data-project").value; var ID = projectsContainer[i].attributes.getNamedItem("data-project").value;
var baseURL = projectsContainer[i].attributes.getNamedItem("data-baseURL").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 playerLocation = projectsContainer[i].attributes.getNamedItem("data-playerLocation").value;
var theme = projectsContainer[i].classList.item(1); var theme = projectsContainer[i].classList.item(1);
projects[i] = projects[i] =
{ {
baseURL: baseURL, baseURL: baseURL,
searchLocation: searchLocation,
playerLocation: playerLocation,
playerURLPrefix: (baseURL ? baseURL + "/" : "") + (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"), projectTitleElement: projectsContainer[i].querySelector(":scope > .cineraProjectTitle"),
entriesContainer: projectsContainer[i].querySelector(":scope > .cineraIndexEntries"), entriesContainer: projectsContainer[i].querySelector(":scope > .cineraIndexEntries"),
dayContainerPrototype: dayContainerPrototype.cloneNode(true), dayContainerPrototype: dayContainerPrototype.cloneNode(true),
@ -529,6 +538,7 @@ function renderResults() {
if(projects[i].playerURLPrefix === episode.playerURLPrefix) if(projects[i].playerURLPrefix === episode.playerURLPrefix)
{ {
projectContainer.setAttribute("data-baseURL", projects[i].baseURL); projectContainer.setAttribute("data-baseURL", projects[i].baseURL);
projectContainer.setAttribute("data-playerLocation", projects[i].playerLocation);
if(projects[i].filteredOut) if(projects[i].filteredOut)
{ {
projectContainer.style.display = "none"; projectContainer.style.display = "none";