cinera.c: Make @author and :categories searchable
This is a stop-gap gap solution pending CINERA_DB_VERSION 6. It simply augments the .index files, prepending "@author: " to timestamps bearing an author – e.g. audience questions – and appending " [:each :category]" to those bearing topic or medium categorisation.
This commit is contained in:
parent
a67a5ee34b
commit
e5ffec7a55
825
cinera/cinera.c
825
cinera/cinera.c
|
@ -23,7 +23,7 @@ typedef struct
|
|||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 10,
|
||||
.Patch = 30
|
||||
.Patch = 31
|
||||
};
|
||||
|
||||
#define __USE_XOPEN2K8 // NOTE(matt): O_NOFOLLOW
|
||||
|
@ -8350,16 +8350,70 @@ BuildTimestampClass(buffer *TimestampClass, _memory_book(category_info) *LocalTo
|
|||
CopyStringToBuffer(TimestampClass, "\"");
|
||||
}
|
||||
|
||||
void
|
||||
BuildCategoryIcons(buffer *CategoryIcons, _memory_book(category_info) *LocalTopics, _memory_book(category_info) *LocalMedia, string DefaultMedium, bool *RequiresCineraJS)
|
||||
bool
|
||||
IsWhitespace(char C)
|
||||
{
|
||||
bool CategoriesSpan = FALSE;
|
||||
return (C == ' ' || C == '\t' || C == '\n');
|
||||
}
|
||||
|
||||
bool
|
||||
ContainsWhitespace(string S)
|
||||
{
|
||||
bool Result = FALSE;
|
||||
for(int i = 0; i < S.Length; ++i)
|
||||
{
|
||||
if(IsWhitespace(S.Base[i]))
|
||||
{
|
||||
Result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void
|
||||
ConsumeWhitespace(buffer *B)
|
||||
{
|
||||
while(B->Ptr - B->Location < B->Size && IsWhitespace(*B->Ptr))
|
||||
{
|
||||
++B->Ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PushCategorySearchEntry(buffer *SearchEntry, HMML_Timestamp *Timestamp, category_info *Category, bool Underway)
|
||||
{
|
||||
if(Underway || Timestamp->text[0])
|
||||
{
|
||||
CopyStringToBuffer(SearchEntry, " ");
|
||||
}
|
||||
if(!Underway)
|
||||
{
|
||||
CopyStringToBuffer(SearchEntry, "[");
|
||||
}
|
||||
|
||||
CopyStringToBuffer(SearchEntry, ":");
|
||||
bool NeedsQuoting = ContainsWhitespace(Category->Marker);
|
||||
if(NeedsQuoting)
|
||||
{
|
||||
CopyStringToBuffer(SearchEntry, "\"");
|
||||
}
|
||||
CopyStringToBufferNoFormat(SearchEntry, Category->Marker);
|
||||
if(NeedsQuoting)
|
||||
{
|
||||
CopyStringToBuffer(SearchEntry, "\"");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BuildCategoryIcons(buffer *SearchEntry, buffer *CategoryIcons, _memory_book(category_info) *LocalTopics, _memory_book(category_info) *LocalMedia, string DefaultMedium, bool *RequiresCineraJS, HMML_Timestamp *Timestamp)
|
||||
{
|
||||
bool Underway = FALSE;
|
||||
category_info *FirstLocalTopic = GetPlaceInBook(LocalTopics, 0);
|
||||
category_info *FirstLocalMedium = GetPlaceInBook(LocalMedia, 0);
|
||||
if(!(LocalTopics->ItemCount == 1 && StringsMatch(FirstLocalTopic->Marker, Wrap0("nullTopic"))
|
||||
&& LocalMedia->ItemCount == 1 && StringsMatch(DefaultMedium, FirstLocalMedium->Marker)))
|
||||
&& LocalMedia->ItemCount == 1 && StringsMatch(FirstLocalMedium->Marker, DefaultMedium)))
|
||||
{
|
||||
CategoriesSpan = TRUE;
|
||||
CopyStringToBuffer(CategoryIcons, "<span class=\"cineraCategories\">");
|
||||
}
|
||||
|
||||
|
@ -8368,6 +8422,14 @@ BuildCategoryIcons(buffer *CategoryIcons, _memory_book(category_info) *LocalTopi
|
|||
for(int i = 0; i < LocalTopics->ItemCount; ++i)
|
||||
{
|
||||
category_info *This = GetPlaceInBook(LocalTopics, i);
|
||||
|
||||
// .index
|
||||
if(SearchEntry)
|
||||
{
|
||||
PushCategorySearchEntry(SearchEntry, Timestamp, This, Underway);
|
||||
}
|
||||
|
||||
// .html
|
||||
// NOTE(matt): Stack-string
|
||||
char SanitisedMarker[This->Marker.Length + 1];
|
||||
CopyString(SanitisedMarker, sizeof(SanitisedMarker), "%.*s", (int)This->Marker.Length, This->Marker.Base);
|
||||
|
@ -8385,14 +8447,24 @@ BuildCategoryIcons(buffer *CategoryIcons, _memory_book(category_info) *LocalTopi
|
|||
}
|
||||
CopyStringToBuffer(CategoryIcons,
|
||||
"></div>");
|
||||
|
||||
Underway = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(!(LocalMedia->ItemCount == 1 && StringsMatch(DefaultMedium, FirstLocalMedium->Marker)))
|
||||
if(!(LocalMedia->ItemCount == 1 && StringsMatch(FirstLocalMedium->Marker, DefaultMedium)))
|
||||
{
|
||||
for(int i = 0; i < LocalMedia->ItemCount; ++i)
|
||||
{
|
||||
category_info *This = GetPlaceInBook(LocalMedia, i);
|
||||
|
||||
// .index
|
||||
if(SearchEntry)
|
||||
{
|
||||
PushCategorySearchEntry(SearchEntry, Timestamp, This, Underway);
|
||||
}
|
||||
|
||||
// .html
|
||||
// NOTE(matt): Stack-string
|
||||
char SanitisedMarker[This->Marker.Length + 1];
|
||||
CopyString(SanitisedMarker, sizeof(SanitisedMarker), "%.*s", (int)This->Marker.Length, This->Marker.Base);
|
||||
|
@ -8409,11 +8481,20 @@ BuildCategoryIcons(buffer *CategoryIcons, _memory_book(category_info) *LocalTopi
|
|||
|
||||
CopyStringToBuffer(CategoryIcons, "</div>");
|
||||
}
|
||||
|
||||
Underway = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(CategoriesSpan)
|
||||
if(Underway)
|
||||
{
|
||||
// .index
|
||||
if(SearchEntry)
|
||||
{
|
||||
CopyStringToBuffer(SearchEntry, "]");
|
||||
}
|
||||
|
||||
// .html
|
||||
CopyStringToBuffer(CategoryIcons, "</span>");
|
||||
}
|
||||
}
|
||||
|
@ -9220,21 +9301,6 @@ StripSurroundingSlashes(char *String) // NOTE(matt): For relative paths
|
|||
return Ptr;
|
||||
}
|
||||
|
||||
bool
|
||||
IsWhitespace(char C)
|
||||
{
|
||||
return (C == ' ' || C == '\t' || C == '\n');
|
||||
}
|
||||
|
||||
void
|
||||
ConsumeWhitespace(buffer *B)
|
||||
{
|
||||
while(B->Ptr - B->Location < B->Size && IsWhitespace(*B->Ptr))
|
||||
{
|
||||
++B->Ptr;
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
StripPWDIndicators(string Path)
|
||||
{
|
||||
|
@ -10862,113 +10928,288 @@ TimecodeIs(v4 Timecode, int Hours, int Minutes, int Seconds, int Milliseconds)
|
|||
return Timecode.Hours == Hours && Timecode.Minutes == Minutes && Timecode.Seconds == Seconds && Timecode.Milliseconds == Milliseconds;
|
||||
}
|
||||
|
||||
rc
|
||||
ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, memory_book *Strings,
|
||||
menu_buffers *MenuBuffers, index_buffers *IndexBuffers, player_buffers *PlayerBuffers,
|
||||
medium *DefaultMedium, speakers *Speakers, string Author,
|
||||
_memory_book(ref_info) *ReferencesArray,
|
||||
bool *HasQuoteMenu, bool *HasReferenceMenu, bool *HasFilterMenu, bool *RequiresCineraJS,
|
||||
int *QuoteIdentifier, int *RefIdentifier,
|
||||
_memory_book(category_info) *Topics, _memory_book(category_info) *Media,
|
||||
HMML_Timestamp *Timestamp, v4 *PreviousTimecode)
|
||||
void
|
||||
ProcessTimestampCoda(buffer *SearchEntry, index_buffers *IndexBuffers)
|
||||
{
|
||||
// .index
|
||||
CopyStringToBuffer(SearchEntry, "\"\n");
|
||||
|
||||
// .html
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</div>\n"
|
||||
" </div>\n"
|
||||
" </div>\n");
|
||||
}
|
||||
|
||||
rc
|
||||
ProcessTimestampCategories(neighbourhood *N,
|
||||
buffer *SearchEntry, index_buffers *IndexBuffers,
|
||||
medium *DefaultMedium,
|
||||
bool *HasFilterMenu,
|
||||
bool *RequiresCineraJS,
|
||||
_memory_book(category_info) *Topics, _memory_book(category_info) *LocalTopics,
|
||||
_memory_book(category_info) *Media, _memory_book(category_info) *LocalMedia,
|
||||
HMML_Timestamp *Timestamp, v4 Timecode,
|
||||
int *MarkerIndex, bool HasQuote, bool HasReference)
|
||||
{
|
||||
MEM_TEST_TOP();
|
||||
// TODO(matt): Introduce and use a SystemError() in here
|
||||
rc Result = RC_SUCCESS;
|
||||
|
||||
v4 Timecode = V4(Timestamp->h, Timestamp->m, Timestamp->s, Timestamp->ms);
|
||||
if(TimecodeToDottedSeconds(Timecode) >= TimecodeToDottedSeconds(*PreviousTimecode))
|
||||
{
|
||||
*PreviousTimecode = Timecode;
|
||||
|
||||
memory_book LocalTopics = InitBook(sizeof(category_info), 8);
|
||||
memory_book LocalMedia = InitBook(sizeof(category_info), 8);
|
||||
|
||||
quote_info QuoteInfo = { };
|
||||
|
||||
bool HasQuote = FALSE;
|
||||
bool HasReference = FALSE;
|
||||
|
||||
RewindBuffer(&IndexBuffers->Master);
|
||||
RewindBuffer(&IndexBuffers->Header);
|
||||
RewindBuffer(&IndexBuffers->Class);
|
||||
RewindBuffer(&IndexBuffers->Data);
|
||||
RewindBuffer(&IndexBuffers->Text);
|
||||
RewindBuffer(&IndexBuffers->CategoryIcons);
|
||||
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Header,
|
||||
" <div data-timestamp=\"%.3f\"",
|
||||
TimecodeToDottedSeconds(Timecode));
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Class,
|
||||
" class=\"marker");
|
||||
|
||||
speaker *Speaker = GetSpeaker(&Speakers->Speakers, Author);
|
||||
if(!IsCategorisedAFK(Timestamp))
|
||||
{
|
||||
// NOTE(matt): I reckon it's fair to only cite the speaker when there are a multiple of them
|
||||
if(Speakers->Speakers.ItemCount > 1 && Speaker && !IsCategorisedAuthored(Timestamp))
|
||||
{
|
||||
string DisplayName = !Speaker->Seen ? Speaker->Person->Name : Speaker->Person->Abbreviations[Speakers->AbbrevScheme];
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
"<span class=\"author\" data-hue=\"%d\" data-saturation=\"%d%%\"",
|
||||
Speaker->Colour.Hue,
|
||||
Speaker->Colour.Saturation);
|
||||
|
||||
if(Speaker->Seen)
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Text, " title=\"");
|
||||
CopyStringToBufferHTMLSafe(&IndexBuffers->Text, Speaker->Person->Name);
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "\"");
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
">%.*s</span>: ", (int)DisplayName.Length, DisplayName.Base);
|
||||
|
||||
Speaker->Seen = TRUE;
|
||||
}
|
||||
else if(Author.Length > 0)
|
||||
{
|
||||
if(!*HasFilterMenu)
|
||||
{
|
||||
*HasFilterMenu = TRUE;
|
||||
}
|
||||
InsertCategory(Topics, &LocalTopics, Media, &LocalMedia, Wrap0("authored"), NULL);
|
||||
hsl_colour AuthorColour;
|
||||
StringToColourHash(&AuthorColour, Author);
|
||||
// TODO(matt): That EDITION_NETWORK site database API-polling stuff
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
"<span class=\"author\" data-hue=\"%d\" data-saturation=\"%d%%\">%.*s</span> ",
|
||||
AuthorColour.Hue, AuthorColour.Saturation,
|
||||
(int)Author.Length, Author.Base);
|
||||
}
|
||||
}
|
||||
|
||||
char *InPtr = Timestamp->text;
|
||||
|
||||
int MarkerIndex = 0, RefIndex = 0;
|
||||
while(*InPtr || RefIndex < Timestamp->reference_count)
|
||||
{
|
||||
if(MarkerIndex < Timestamp->marker_count &&
|
||||
InPtr - Timestamp->text == Timestamp->markers[MarkerIndex].offset)
|
||||
{
|
||||
char *Readable = Timestamp->markers[MarkerIndex].parameter
|
||||
? Timestamp->markers[MarkerIndex].parameter
|
||||
: Timestamp->markers[MarkerIndex].marker;
|
||||
HMML_MarkerType Type = Timestamp->markers[MarkerIndex].type;
|
||||
if(Type == HMML_CATEGORY)
|
||||
while(*MarkerIndex < Timestamp->marker_count)
|
||||
{
|
||||
hsl_colour TopicColour = {};
|
||||
Result = GenerateTopicColours(N, Wrap0(Timestamp->markers[MarkerIndex].marker), &TopicColour);
|
||||
Result = GenerateTopicColours(N, Wrap0(Timestamp->markers[*MarkerIndex].marker), &TopicColour);
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(!*HasFilterMenu)
|
||||
{
|
||||
*HasFilterMenu = TRUE;
|
||||
}
|
||||
InsertCategory(Topics, &LocalTopics, Media, &LocalMedia, Wrap0(Timestamp->markers[MarkerIndex].marker), &TopicColour);
|
||||
InsertCategory(Topics, LocalTopics, Media, LocalMedia, Wrap0(Timestamp->markers[*MarkerIndex].marker), &TopicColour);
|
||||
++*MarkerIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(LocalTopics->ItemCount == 0)
|
||||
{
|
||||
hsl_colour TopicColour = {};
|
||||
Result = GenerateTopicColours(N, Wrap0("nullTopic"), &TopicColour);
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
InsertCategory(Topics, LocalTopics, Media, LocalMedia, Wrap0("nullTopic"), &TopicColour);
|
||||
}
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(LocalMedia->ItemCount == 0)
|
||||
{
|
||||
InsertCategory(Topics, LocalTopics, Media, LocalMedia, DefaultMedium->ID, NULL);
|
||||
}
|
||||
|
||||
BuildTimestampClass(&IndexBuffers->Class, LocalTopics, LocalMedia, DefaultMedium->ID);
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Header, &IndexBuffers->Class, 0, PAGE_PLAYER);
|
||||
|
||||
if(HasQuote || HasReference)
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Data, "\"");
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Header, &IndexBuffers->Data, 0, PAGE_PLAYER);
|
||||
}
|
||||
CopyStringToBuffer(&IndexBuffers->Header, ">\n");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Header, 0, PAGE_PLAYER);
|
||||
CopyStringToBuffer(&IndexBuffers->Master,
|
||||
" <div class=\"cineraContent\"><span class=\"timecode\">");
|
||||
CopyTimecodeToBuffer(&IndexBuffers->Master, Timecode);
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</span>");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Text, 0, PAGE_PLAYER);
|
||||
|
||||
if(LocalTopics->ItemCount > 0)
|
||||
{
|
||||
BuildCategoryIcons(SearchEntry, &IndexBuffers->Master, LocalTopics, LocalMedia, DefaultMedium->ID, RequiresCineraJS, Timestamp);
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</div>\n"
|
||||
" <div class=\"progress faded\">\n"
|
||||
" <div class=\"cineraContent\"><span class=\"timecode\">");
|
||||
CopyTimecodeToBuffer(&IndexBuffers->Master, Timecode);
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</span>");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Text, 0, PAGE_PLAYER);
|
||||
|
||||
if(LocalTopics->ItemCount > 0)
|
||||
{
|
||||
BuildCategoryIcons(0, &IndexBuffers->Master, LocalTopics, LocalMedia, DefaultMedium->ID, RequiresCineraJS, Timestamp);
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</div>\n"
|
||||
" </div>\n"
|
||||
" <div class=\"progress main\">\n"
|
||||
" <div class=\"cineraContent\"><span class=\"timecode\">");
|
||||
CopyTimecodeToBuffer(&IndexBuffers->Master, Timecode);
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</span>");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Text, 0, PAGE_PLAYER);
|
||||
|
||||
if(LocalTopics->ItemCount > 0)
|
||||
{
|
||||
BuildCategoryIcons(0, &IndexBuffers->Master, LocalTopics, LocalMedia, DefaultMedium->ID, RequiresCineraJS, Timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
rc
|
||||
ProcessTimestampQuoting(buffer *SearchEntry, string Filepath, memory_book *Strings,
|
||||
menu_buffers *MenuBuffers, index_buffers *IndexBuffers,
|
||||
speakers *Speakers, speaker *Speaker, string Author,
|
||||
bool *HasQuoteMenu, int *QuoteIdentifier,
|
||||
bool *HasQuote, bool HasReference,
|
||||
HMML_Timestamp *Timestamp, v4 Timecode)
|
||||
{
|
||||
rc Result = RC_SUCCESS;
|
||||
if(Timestamp->quote.present)
|
||||
{
|
||||
if(!*HasQuoteMenu)
|
||||
{
|
||||
CopyStringToBuffer(&MenuBuffers->Quote,
|
||||
" <div class=\"menu quotes\">\n"
|
||||
" <span>Quotes ▼</span>\n"
|
||||
" <div class=\"refs quotes_container\">\n");
|
||||
|
||||
*HasQuoteMenu = TRUE;
|
||||
}
|
||||
|
||||
if(!HasReference)
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Data, " data-ref=\"&#%d;", *QuoteIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Data, ",&#%d;", *QuoteIdentifier);
|
||||
}
|
||||
|
||||
*HasQuote = TRUE;
|
||||
|
||||
bool ShouldFetchQuotes = FALSE;
|
||||
if(Config->CacheDir.Length == 0 || time(0) - LastQuoteFetch > 60*60)
|
||||
{
|
||||
ShouldFetchQuotes = TRUE;
|
||||
}
|
||||
|
||||
if(!Speaker && Speakers->Speakers.ItemCount > 0)
|
||||
{
|
||||
Speaker = GetPlaceInBook(&Speakers->Speakers, 0);
|
||||
}
|
||||
string QuoteUsername;
|
||||
if(Timestamp->quote.author)
|
||||
{
|
||||
QuoteUsername = Wrap0(Timestamp->quote.author);
|
||||
}
|
||||
else if(Speaker)
|
||||
{
|
||||
QuoteUsername = Speaker->Person->QuoteUsername;
|
||||
}
|
||||
else
|
||||
{
|
||||
QuoteUsername = Author;
|
||||
}
|
||||
|
||||
|
||||
quote_info QuoteInfo = { };
|
||||
/* */ MEM_TEST_MID();
|
||||
/* +MEM */ Result = BuildQuote(Strings, &QuoteInfo,
|
||||
QuoteUsername, Timestamp->quote.id, ShouldFetchQuotes);
|
||||
/* */ MEM_TEST_MID();
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
CopyStringToBuffer(&MenuBuffers->Quote,
|
||||
" <a target=\"_blank\" data-id=\"&#%d;\" class=\"ref\" href=\"https://dev.abaines.me.uk/quotes/%.*s/%d\">\n"
|
||||
" <span>\n"
|
||||
" <span class=\"ref_content\">\n"
|
||||
" <div class=\"source\">Quote %d</div>\n"
|
||||
" <div class=\"ref_title\">",
|
||||
*QuoteIdentifier,
|
||||
(int)QuoteUsername.Length, QuoteUsername.Base,
|
||||
Timestamp->quote.id,
|
||||
Timestamp->quote.id);
|
||||
|
||||
CopyStringToBufferHTMLSafe(&MenuBuffers->Quote, QuoteInfo.Text);
|
||||
|
||||
string DateString = UnixTimeToDateString(Strings, QuoteInfo.Date);
|
||||
CopyStringToBuffer(&MenuBuffers->Quote, "</div>\n"
|
||||
" <div class=\"quote_byline\">—%.*s, %.*s</div>\n"
|
||||
" </span>\n"
|
||||
" <div class=\"ref_indices\">\n"
|
||||
" <span data-timestamp=\"%.3f\" class=\"timecode\"><span class=\"ref_index\">[&#%d;]</span><span class=\"time\">",
|
||||
(int)QuoteUsername.Length, QuoteUsername.Base,
|
||||
(int)DateString.Length, DateString.Base, // TODO(matt): Convert Unixtime to date-string
|
||||
TimecodeToDottedSeconds(Timecode),
|
||||
*QuoteIdentifier);
|
||||
CopyTimecodeToBuffer(&MenuBuffers->Quote, Timecode);
|
||||
CopyStringToBuffer(&MenuBuffers->Quote, "</span></span>\n"
|
||||
" </div>\n"
|
||||
" </span>\n"
|
||||
" </a>\n");
|
||||
if(!Timestamp->text[0])
|
||||
{
|
||||
// .index
|
||||
CopyStringToBuffer(SearchEntry, "\u201C");
|
||||
CopyStringToBufferNoFormat(SearchEntry, QuoteInfo.Text);
|
||||
CopyStringToBuffer(SearchEntry, "\u201D");
|
||||
|
||||
// .html
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "“");
|
||||
CopyStringToBufferHTMLSafe(&IndexBuffers->Text, QuoteInfo.Text);
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "”");
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE(matt): Here accounting for ProcessTimestampText() not writing to .index
|
||||
|
||||
// .index
|
||||
CopyStringToBufferNoFormat(SearchEntry, Wrap0(Timestamp->text));
|
||||
}
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "<sup>&#%d;</sup>", *QuoteIdentifier);
|
||||
++*QuoteIdentifier;
|
||||
}
|
||||
else if(Result == RC_UNFOUND)
|
||||
{
|
||||
IndexingQuoteError(&Filepath, Timestamp->line, QuoteUsername, Timestamp->quote.id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// .index
|
||||
CopyStringToBufferNoFormat(SearchEntry, Wrap0(Timestamp->text));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
rc
|
||||
ProcessTimestampText(neighbourhood *N, string Filepath, memory_book *Strings,
|
||||
menu_buffers *MenuBuffers, index_buffers *IndexBuffers,
|
||||
_memory_book(ref_info) *ReferencesArray,
|
||||
bool *HasReferenceMenu, bool *HasFilterMenu,
|
||||
int *RefIdentifier,
|
||||
_memory_book(category_info) *Topics, _memory_book(category_info) *LocalTopics,
|
||||
_memory_book(category_info) *Media, _memory_book(category_info) *LocalMedia,
|
||||
HMML_Timestamp *Timestamp,
|
||||
bool *HasReference, v4 Timecode, int *MarkerIndex)
|
||||
{
|
||||
// NOTE(matt): While this function processes the Timestamp->text for the benefit of both the .html and .index sides, it
|
||||
// only writes out .html, meaning we need to write the .index file elsewhere in ProcessTimestampQuoting().
|
||||
rc Result = RC_SUCCESS;
|
||||
|
||||
int RefIndex = 0;
|
||||
char *InPtr = Timestamp->text;
|
||||
while(*InPtr || RefIndex < Timestamp->reference_count)
|
||||
{
|
||||
if(*MarkerIndex < Timestamp->marker_count &&
|
||||
InPtr - Timestamp->text == Timestamp->markers[*MarkerIndex].offset)
|
||||
{
|
||||
char *Readable = Timestamp->markers[*MarkerIndex].parameter
|
||||
? Timestamp->markers[*MarkerIndex].parameter
|
||||
: Timestamp->markers[*MarkerIndex].marker;
|
||||
HMML_MarkerType Type = Timestamp->markers[*MarkerIndex].type;
|
||||
if(Type == HMML_CATEGORY)
|
||||
{
|
||||
hsl_colour TopicColour = {};
|
||||
Result = GenerateTopicColours(N, Wrap0(Timestamp->markers[*MarkerIndex].marker), &TopicColour);
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(!*HasFilterMenu)
|
||||
{
|
||||
*HasFilterMenu = TRUE;
|
||||
}
|
||||
InsertCategory(Topics, LocalTopics, Media, LocalMedia, Wrap0(Timestamp->markers[*MarkerIndex].marker), &TopicColour);
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "%.*s", (int)StringLength(Readable), InPtr);
|
||||
}
|
||||
else
|
||||
|
@ -10980,16 +11221,16 @@ ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, m
|
|||
{
|
||||
// TODO(matt): That EDITION_NETWORK site database API-polling stuff
|
||||
hsl_colour Colour;
|
||||
StringToColourHash(&Colour, Wrap0(Timestamp->markers[MarkerIndex].marker));
|
||||
StringToColourHash(&Colour, Wrap0(Timestamp->markers[*MarkerIndex].marker));
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
"<span class=\"%s\" data-hue=\"%d\" data-saturation=\"%d%%\">%.*s</span>",
|
||||
Timestamp->markers[MarkerIndex].type == HMML_MEMBER ? "member" : "project",
|
||||
Timestamp->markers[*MarkerIndex].type == HMML_MEMBER ? "member" : "project",
|
||||
Colour.Hue, Colour.Saturation,
|
||||
(int)StringLength(Readable), InPtr);
|
||||
}
|
||||
|
||||
InPtr += StringLength(Readable);
|
||||
++MarkerIndex;
|
||||
++*MarkerIndex;
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
|
@ -11030,7 +11271,7 @@ ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, m
|
|||
IndexingError(Filepath, Timestamp->line, S_ERROR,
|
||||
"Cannot process new combination of reference info\n"
|
||||
"\n"
|
||||
"Either tweak your timestamp, or contact miblodelcarpio@gmail.com\n"
|
||||
"Either tweak your timestamp, or write to contact@miblo.net\n"
|
||||
"mentioning the ref node you want to write and how you want it to\n"
|
||||
"appear in the references menu",
|
||||
0);
|
||||
|
@ -11040,8 +11281,8 @@ ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, m
|
|||
break; // NOTE(matt): Out of the while()
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Data, "%s%s", !HasReference ? " data-ref=\"" : "," , This->ID);
|
||||
HasReference = TRUE;
|
||||
CopyStringToBuffer(&IndexBuffers->Data, "%s%s", !*HasReference ? " data-ref=\"" : "," , This->ID);
|
||||
*HasReference = TRUE;
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "<sup>%s%d</sup>",
|
||||
RefIndex > 0 && Timestamp->references[RefIndex].offset == Timestamp->references[RefIndex-1].offset ? "," : "",
|
||||
*RefIdentifier);
|
||||
|
@ -11084,217 +11325,171 @@ ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, m
|
|||
}
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(Timestamp->quote.present)
|
||||
{
|
||||
if(!*HasQuoteMenu)
|
||||
{
|
||||
CopyStringToBuffer(&MenuBuffers->Quote,
|
||||
" <div class=\"menu quotes\">\n"
|
||||
" <span>Quotes ▼</span>\n"
|
||||
" <div class=\"refs quotes_container\">\n");
|
||||
return Result;
|
||||
}
|
||||
|
||||
*HasQuoteMenu = TRUE;
|
||||
speaker *
|
||||
ProcessTimestampAuthoring(buffer *SearchEntry, index_buffers *IndexBuffers,
|
||||
speakers *Speakers, string Author, bool *HasFilterMenu,
|
||||
_memory_book(category_info) *Topics, _memory_book(category_info) *LocalTopics,
|
||||
_memory_book(category_info) *Media, _memory_book(category_info) *LocalMedia,
|
||||
HMML_Timestamp *Timestamp)
|
||||
{
|
||||
speaker *Speaker = GetSpeaker(&Speakers->Speakers, Author);
|
||||
|
||||
if(!IsCategorisedAFK(Timestamp))
|
||||
{
|
||||
// NOTE(matt): I reckon it's fair to only cite the speaker when there are a multiple of them
|
||||
if(Speakers->Speakers.ItemCount > 1 && Speaker && !IsCategorisedAuthored(Timestamp))
|
||||
{
|
||||
// .index
|
||||
CopyStringToBufferNoFormat(SearchEntry, Speaker->Person->Name);
|
||||
CopyStringToBuffer(SearchEntry, ": ");
|
||||
|
||||
// .html
|
||||
string DisplayName = !Speaker->Seen ? Speaker->Person->Name : Speaker->Person->Abbreviations[Speakers->AbbrevScheme];
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
"<span class=\"author\" data-hue=\"%d\" data-saturation=\"%d%%\"",
|
||||
Speaker->Colour.Hue,
|
||||
Speaker->Colour.Saturation);
|
||||
|
||||
if(Speaker->Seen)
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Text, " title=\"");
|
||||
CopyStringToBufferHTMLSafe(&IndexBuffers->Text, Speaker->Person->Name);
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "\"");
|
||||
}
|
||||
|
||||
if(!HasReference)
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Data, " data-ref=\"&#%d;", *QuoteIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Data, ",&#%d;", *QuoteIdentifier);
|
||||
}
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
">%.*s</span>: ", (int)DisplayName.Length, DisplayName.Base);
|
||||
|
||||
HasQuote = TRUE;
|
||||
Speaker->Seen = TRUE;
|
||||
}
|
||||
else if(Author.Length > 0)
|
||||
{
|
||||
// .index
|
||||
CopyStringToBuffer(SearchEntry, "@");
|
||||
CopyStringToBufferNoFormat(SearchEntry, Author);
|
||||
CopyStringToBuffer(SearchEntry, ": ");
|
||||
|
||||
bool ShouldFetchQuotes = FALSE;
|
||||
if(Config->CacheDir.Length == 0 || time(0) - LastQuoteFetch > 60*60)
|
||||
{
|
||||
ShouldFetchQuotes = TRUE;
|
||||
}
|
||||
|
||||
if(!Speaker && Speakers->Speakers.ItemCount > 0)
|
||||
{
|
||||
Speaker = GetPlaceInBook(&Speakers->Speakers, 0);
|
||||
}
|
||||
string QuoteUsername;
|
||||
if(Timestamp->quote.author)
|
||||
{
|
||||
QuoteUsername = Wrap0(Timestamp->quote.author);
|
||||
}
|
||||
else if(Speaker)
|
||||
{
|
||||
QuoteUsername = Speaker->Person->QuoteUsername;
|
||||
}
|
||||
else
|
||||
{
|
||||
QuoteUsername = Author;
|
||||
}
|
||||
|
||||
/* */ MEM_TEST_MID();
|
||||
/* +MEM */ Result = BuildQuote(Strings, &QuoteInfo,
|
||||
QuoteUsername, Timestamp->quote.id, ShouldFetchQuotes);
|
||||
/* */ MEM_TEST_MID();
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
CopyStringToBuffer(&MenuBuffers->Quote,
|
||||
" <a target=\"_blank\" data-id=\"&#%d;\" class=\"ref\" href=\"https://dev.abaines.me.uk/quotes/%.*s/%d\">\n"
|
||||
" <span>\n"
|
||||
" <span class=\"ref_content\">\n"
|
||||
" <div class=\"source\">Quote %d</div>\n"
|
||||
" <div class=\"ref_title\">",
|
||||
*QuoteIdentifier,
|
||||
(int)QuoteUsername.Length, QuoteUsername.Base,
|
||||
Timestamp->quote.id,
|
||||
Timestamp->quote.id);
|
||||
|
||||
CopyStringToBufferHTMLSafe(&MenuBuffers->Quote, QuoteInfo.Text);
|
||||
|
||||
string DateString = UnixTimeToDateString(Strings, QuoteInfo.Date);
|
||||
CopyStringToBuffer(&MenuBuffers->Quote, "</div>\n"
|
||||
" <div class=\"quote_byline\">—%.*s, %.*s</div>\n"
|
||||
" </span>\n"
|
||||
" <div class=\"ref_indices\">\n"
|
||||
" <span data-timestamp=\"%.3f\" class=\"timecode\"><span class=\"ref_index\">[&#%d;]</span><span class=\"time\">",
|
||||
(int)QuoteUsername.Length, QuoteUsername.Base,
|
||||
(int)DateString.Length, DateString.Base, // TODO(matt): Convert Unixtime to date-string
|
||||
TimecodeToDottedSeconds(Timecode),
|
||||
*QuoteIdentifier);
|
||||
CopyTimecodeToBuffer(&MenuBuffers->Quote, Timecode);
|
||||
CopyStringToBuffer(&MenuBuffers->Quote, "</span></span>\n"
|
||||
" </div>\n"
|
||||
" </span>\n"
|
||||
" </a>\n");
|
||||
if(!Timestamp->text[0])
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "“");
|
||||
CopyStringToBufferHTMLSafe(&IndexBuffers->Text, QuoteInfo.Text);
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "”");
|
||||
}
|
||||
CopyStringToBuffer(&IndexBuffers->Text, "<sup>&#%d;</sup>", *QuoteIdentifier);
|
||||
++*QuoteIdentifier;
|
||||
}
|
||||
else if(Result == RC_UNFOUND)
|
||||
{
|
||||
IndexingQuoteError(&Filepath, Timestamp->line, QuoteUsername, Timestamp->quote.id);
|
||||
}
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "\"%.3f\": \"", TimecodeToDottedSeconds(Timecode));
|
||||
if(Timestamp->quote.present && !Timestamp->text[0])
|
||||
{
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "\u201C");
|
||||
CopyStringToBufferNoFormat(&CollationBuffers->SearchEntry, QuoteInfo.Text);
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "\u201D");
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyStringToBufferNoFormat(&CollationBuffers->SearchEntry, Wrap0(Timestamp->text));
|
||||
}
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "\"\n");
|
||||
|
||||
while(MarkerIndex < Timestamp->marker_count)
|
||||
{
|
||||
hsl_colour TopicColour = {};
|
||||
Result = GenerateTopicColours(N, Wrap0(Timestamp->markers[MarkerIndex].marker), &TopicColour);
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
// .html
|
||||
if(!*HasFilterMenu)
|
||||
{
|
||||
*HasFilterMenu = TRUE;
|
||||
}
|
||||
InsertCategory(Topics, &LocalTopics, Media, &LocalMedia, Wrap0(Timestamp->markers[MarkerIndex].marker), &TopicColour);
|
||||
++MarkerIndex;
|
||||
InsertCategory(Topics, LocalTopics, Media, LocalMedia, Wrap0("authored"), NULL);
|
||||
hsl_colour AuthorColour;
|
||||
StringToColourHash(&AuthorColour, Author);
|
||||
// TODO(matt): That EDITION_NETWORK site database API-polling stuff
|
||||
CopyStringToBuffer(&IndexBuffers->Text,
|
||||
"<span class=\"author\" data-hue=\"%d\" data-saturation=\"%d%%\">@%.*s</span> ",
|
||||
AuthorColour.Hue, AuthorColour.Saturation,
|
||||
(int)Author.Length, Author.Base);
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
return Speaker;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessTimestampTiming(buffer *SearchEntry, index_buffers *IndexBuffers, v4 Timecode)
|
||||
{
|
||||
float Time = TimecodeToDottedSeconds(Timecode);
|
||||
|
||||
// .index
|
||||
CopyStringToBuffer(SearchEntry, "\"%.3f\": \"", Time);
|
||||
|
||||
// .html
|
||||
CopyStringToBuffer(&IndexBuffers->Header,
|
||||
" <div data-timestamp=\"%.3f\"", Time);
|
||||
}
|
||||
|
||||
rc
|
||||
ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, memory_book *Strings,
|
||||
menu_buffers *MenuBuffers, index_buffers *IndexBuffers, player_buffers *PlayerBuffers,
|
||||
medium *DefaultMedium, speakers *Speakers, string Author,
|
||||
_memory_book(ref_info) *ReferencesArray,
|
||||
bool *HasQuoteMenu, bool *HasReferenceMenu, bool *HasFilterMenu, bool *RequiresCineraJS,
|
||||
int *QuoteIdentifier, int *RefIdentifier,
|
||||
_memory_book(category_info) *Topics, _memory_book(category_info) *Media,
|
||||
HMML_Timestamp *Timestamp, v4 *PreviousTimecode)
|
||||
{
|
||||
MEM_TEST_TOP();
|
||||
// TODO(matt): Introduce and use a SystemError() in here
|
||||
rc Result = RC_SUCCESS;
|
||||
|
||||
v4 Timecode = V4(Timestamp->h, Timestamp->m, Timestamp->s, Timestamp->ms);
|
||||
if(TimecodeToDottedSeconds(Timecode) >= TimecodeToDottedSeconds(*PreviousTimecode))
|
||||
{
|
||||
break;
|
||||
}
|
||||
*PreviousTimecode = Timecode;
|
||||
|
||||
memory_book LocalTopics = InitBook(sizeof(category_info), 8);
|
||||
memory_book LocalMedia = InitBook(sizeof(category_info), 8);
|
||||
|
||||
bool HasQuote = FALSE;
|
||||
bool HasReference = FALSE;
|
||||
|
||||
RewindBuffer(&IndexBuffers->Master);
|
||||
RewindBuffer(&IndexBuffers->Header);
|
||||
RewindBuffer(&IndexBuffers->Class);
|
||||
RewindBuffer(&IndexBuffers->Data);
|
||||
RewindBuffer(&IndexBuffers->Text);
|
||||
RewindBuffer(&IndexBuffers->CategoryIcons);
|
||||
|
||||
|
||||
ProcessTimestampTiming(&CollationBuffers->SearchEntry, IndexBuffers, Timecode);
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Class,
|
||||
" class=\"marker");
|
||||
|
||||
speaker *Speaker = ProcessTimestampAuthoring(&CollationBuffers->SearchEntry, IndexBuffers,
|
||||
Speakers, Author, HasFilterMenu,
|
||||
Topics, &LocalTopics,
|
||||
Media, &LocalMedia,
|
||||
Timestamp);
|
||||
|
||||
int MarkerIndex = 0;
|
||||
Result = ProcessTimestampText(N, Filepath, Strings,
|
||||
MenuBuffers, IndexBuffers,
|
||||
ReferencesArray,
|
||||
HasReferenceMenu, HasFilterMenu,
|
||||
RefIdentifier,
|
||||
Topics, &LocalTopics,
|
||||
Media, &LocalMedia,
|
||||
Timestamp,
|
||||
&HasReference, Timecode, &MarkerIndex);
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
Result = ProcessTimestampQuoting(&CollationBuffers->SearchEntry, Filepath, Strings,
|
||||
MenuBuffers, IndexBuffers,
|
||||
Speakers, Speaker, Author,
|
||||
HasQuoteMenu, QuoteIdentifier,
|
||||
&HasQuote, HasReference,
|
||||
Timestamp, Timecode);
|
||||
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(LocalTopics.ItemCount == 0)
|
||||
{
|
||||
hsl_colour TopicColour = {};
|
||||
Result = GenerateTopicColours(N, Wrap0("nullTopic"), &TopicColour);
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
InsertCategory(Topics, &LocalTopics, Media, &LocalMedia, Wrap0("nullTopic"), &TopicColour);
|
||||
}
|
||||
Result = ProcessTimestampCategories(N,
|
||||
&CollationBuffers->SearchEntry, IndexBuffers,
|
||||
DefaultMedium,
|
||||
HasFilterMenu,
|
||||
RequiresCineraJS,
|
||||
Topics, &LocalTopics,
|
||||
Media, &LocalMedia,
|
||||
Timestamp, Timecode,
|
||||
&MarkerIndex, HasQuote, HasReference);
|
||||
}
|
||||
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
if(LocalMedia.ItemCount == 0)
|
||||
{
|
||||
InsertCategory(Topics, &LocalTopics, Media, &LocalMedia, DefaultMedium->ID, NULL);
|
||||
}
|
||||
|
||||
BuildTimestampClass(&IndexBuffers->Class, &LocalTopics, &LocalMedia, DefaultMedium->ID);
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Header, &IndexBuffers->Class, 0, PAGE_PLAYER);
|
||||
|
||||
if(HasQuote || HasReference)
|
||||
{
|
||||
CopyStringToBuffer(&IndexBuffers->Data, "\"");
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Header, &IndexBuffers->Data, 0, PAGE_PLAYER);
|
||||
}
|
||||
CopyStringToBuffer(&IndexBuffers->Header, ">\n");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Header, 0, PAGE_PLAYER);
|
||||
CopyStringToBuffer(&IndexBuffers->Master,
|
||||
" <div class=\"cineraContent\"><span class=\"timecode\">");
|
||||
CopyTimecodeToBuffer(&IndexBuffers->Master, Timecode);
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</span>");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Text, 0, PAGE_PLAYER);
|
||||
|
||||
if(LocalTopics.ItemCount > 0)
|
||||
{
|
||||
BuildCategoryIcons(&IndexBuffers->Master, &LocalTopics, &LocalMedia, DefaultMedium->ID, RequiresCineraJS);
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</div>\n"
|
||||
" <div class=\"progress faded\">\n"
|
||||
" <div class=\"cineraContent\"><span class=\"timecode\">");
|
||||
CopyTimecodeToBuffer(&IndexBuffers->Master, Timecode);
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</span>");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Text, 0, PAGE_PLAYER);
|
||||
|
||||
if(LocalTopics.ItemCount > 0)
|
||||
{
|
||||
BuildCategoryIcons(&IndexBuffers->Master, &LocalTopics, &LocalMedia, DefaultMedium->ID, RequiresCineraJS);
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</div>\n"
|
||||
" </div>\n"
|
||||
" <div class=\"progress main\">\n"
|
||||
" <div class=\"cineraContent\"><span class=\"timecode\">");
|
||||
CopyTimecodeToBuffer(&IndexBuffers->Master, Timecode);
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</span>");
|
||||
|
||||
CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->Text, 0, PAGE_PLAYER);
|
||||
|
||||
if(LocalTopics.ItemCount > 0)
|
||||
{
|
||||
//CopyLandmarkedBuffer(&IndexBuffers->Master, &IndexBuffers->CategoryIcons, PAGE_PLAYER);
|
||||
BuildCategoryIcons(&IndexBuffers->Master, &LocalTopics, &LocalMedia, DefaultMedium->ID, RequiresCineraJS);
|
||||
}
|
||||
|
||||
CopyStringToBuffer(&IndexBuffers->Master, "</div>\n"
|
||||
" </div>\n"
|
||||
" </div>\n");
|
||||
ProcessTimestampCoda(&CollationBuffers->SearchEntry, IndexBuffers);
|
||||
|
||||
CopyLandmarkedBuffer(&PlayerBuffers->Main, &IndexBuffers->Master, 0, PAGE_PLAYER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeBook(&LocalTopics);
|
||||
FreeBook(&LocalMedia);
|
||||
|
@ -18313,7 +18508,7 @@ main(int ArgC, char **Args)
|
|||
if(ClaimBuffer(&CollationBuffers.Player, BID_COLLATION_BUFFERS_PLAYER, Kilobytes(552)) == RC_ARENA_FULL) { Exit(); };
|
||||
|
||||
if(ClaimBuffer(&CollationBuffers.IncludesSearch, BID_COLLATION_BUFFERS_INCLUDES_SEARCH, Kilobytes(4)) == RC_ARENA_FULL) { Exit(); };
|
||||
if(ClaimBuffer(&CollationBuffers.SearchEntry, BID_COLLATION_BUFFERS_SEARCH_ENTRY, Kilobytes(32)) == RC_ARENA_FULL) { Exit(); };
|
||||
if(ClaimBuffer(&CollationBuffers.SearchEntry, BID_COLLATION_BUFFERS_SEARCH_ENTRY, Kilobytes(64)) == RC_ARENA_FULL) { Exit(); };
|
||||
|
||||
CollationBuffers.Search.ID = BID_COLLATION_BUFFERS_SEARCH; // NOTE(matt): Allocated by SearchToBuffer()
|
||||
|
||||
|
|
Loading…
Reference in New Issue