diff --git a/hmml_to_youtube/hmml_to_youtube.c b/hmml_to_youtube/hmml_to_youtube.c new file mode 100644 index 0000000..ab09e9f --- /dev/null +++ b/hmml_to_youtube/hmml_to_youtube.c @@ -0,0 +1,324 @@ +#if 0 +ctime -begin ${0%.*}.ctm +clang -g -fsanitize=address $0 -o ${0%.*} hmml.a +ctime -end ${0%.*}.ctm +exit +#endif + +#include "hmmlib.h" +#include +#include + +#ifndef bool +typedef unsigned int bool; +#endif + +#define TRUE 1 +#define FALSE 0 + +typedef struct +{ + char *Location; + char *Ptr; + int Size; +} buffer; + +int +StringLength(char *String) +{ + int i = 0; + while(String[i]) + { + ++i; + } + return i; +} + +bool +StringsDiffer(char A[], char B[]) +{ + char APtr, BPtr; + while(*A) + { + APtr = *A++; + BPtr = *B++; + if(APtr >= 'A' && APtr <= 'Z') + { + APtr += 32; + } + if(BPtr >= 'A' && BPtr <= 'Z') + { + BPtr += 32; + } + if(APtr != BPtr) + { + return TRUE; + } + } + return FALSE; +} + +int +main(int ArgC, char **Args) +{ + if(ArgC < 2) + { + fprintf(stderr, "Usage: %s filename(s)\n", Args[0]); + return 1; + } + + FILE *InFile; + for(int FileIndex = 1; FileIndex < ArgC; ++FileIndex) + { + if(!(InFile = fopen(Args[FileIndex], "r"))) + { + perror(Args[0]); + return 1; + } + + // Init MemoryArena + int ArenaSize = 1024 * 32; + char *MemoryArena; + if(!(MemoryArena = calloc(ArenaSize, 1))) + { + perror(Args[0]); + return 1; + } + int ClaimedMemory = 0; + + // Buffers and Pointers + char *InPtr; // Associated buffer is allocated by hmml_parse_file() + buffer Temp; // Temp.Ptr may be used independently of Temp.Location + buffer Out; + + //printf("Reading %s\n", Args[FileIndex]); + HMML_Output HMML = hmml_parse_file(InFile); + fclose(InFile); + + if(HMML.well_formed) + { + Out.Location = MemoryArena + ClaimedMemory; + Out.Size = 1024*16; + ClaimedMemory += Out.Size; + + bool WritingChat = TRUE; + + char *Member = HMML.metadata.twitch ? + HMML.metadata.twitch : + HMML.metadata.member; + + for(int BuildPass = 0; BuildPass < 2; ++BuildPass) + { + if(WritingChat == FALSE) + { + printf("%s: %ld characters over budget. Shrinking...\n", Args[FileIndex], (Out.Ptr - Out.Location) - 5000); + } + + Out.Ptr = Out.Location; + for(int AnnotationIndex = 0; AnnotationIndex < HMML.annotation_count; ++AnnotationIndex) + { + if(HMML.annotations[AnnotationIndex].author && !WritingChat) + { + goto skip; + } + + InPtr = HMML.annotations[AnnotationIndex].time; + + while(*InPtr) + { + *Out.Ptr++ = *InPtr++; + } + *Out.Ptr++ = ' '; + + InPtr = HMML.annotations[AnnotationIndex].text; + + + // TODO(matt): Get this logic correct + if(HMML.annotations[AnnotationIndex].author) + { + Temp.Location = "Chat comment: \""; + Temp.Ptr = Temp.Location; + while(*Temp.Ptr) + { + *Out.Ptr++ = *Temp.Ptr++; + } + + if(*HMML.annotations[AnnotationIndex].text) + { + InPtr = HMML.annotations[AnnotationIndex].text; + if(!StringsDiffer(Member, InPtr)) + { + InPtr += StringLength(Member); + + while(*InPtr && + !(*InPtr >= '0' && *InPtr <= '9') && + !(*InPtr >= 'A' && *InPtr <= 'Z') && + !(*InPtr >= 'a' && *InPtr <= 'z')) + { + ++InPtr; + } + + if(*InPtr && *InPtr >= 'a' && *InPtr <= 'z') + { + *InPtr -= 32; + } + } + } + } + + if(HMML.annotations[AnnotationIndex].reference_count) + { + for(int RefIndex = 0; RefIndex < HMML.annotations[AnnotationIndex].reference_count; ++RefIndex) + { + while(InPtr - HMML.annotations[AnnotationIndex].text < HMML.annotations[AnnotationIndex].references[RefIndex].offset) + { + *Out.Ptr++ = *InPtr++; + } + + if(HMML.annotations[AnnotationIndex].references[RefIndex].offset == 0) + { + if(HMML.annotations[AnnotationIndex].references[RefIndex].page) + { + Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].page; + } + else if(HMML.annotations[AnnotationIndex].references[RefIndex].site) + { + Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].site; + } + else if(HMML.annotations[AnnotationIndex].references[RefIndex].title) + { + Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].title; + } + + if(Out.Ptr[-1] != '"' && Out.Ptr[-1] != ' ') + { + *Out.Ptr++ = ' '; + } + + while(*Temp.Ptr) + { + *Out.Ptr++ = *Temp.Ptr++; + } + } + + if(HMML.annotations[AnnotationIndex].references[RefIndex].url) + { + Temp.Ptr = HMML.annotations[AnnotationIndex].references[RefIndex].url; + + if(HMML.annotations[AnnotationIndex].references[RefIndex].offset < StringLength(HMML.annotations[AnnotationIndex].text) || + RefIndex < HMML.annotations[AnnotationIndex].reference_count-1) + { + if(Out.Ptr[-1] != ' ') + { + *Out.Ptr++ = ' '; + } + *Out.Ptr++ = '-'; + *Out.Ptr++ = ' '; + while(*Temp.Ptr) + { + *Out.Ptr++ = *Temp.Ptr++; + } + *Out.Ptr++ = ' '; + *Out.Ptr++ = '-'; + } + else + { + if(Out.Ptr[-1] == ' ') + { + --Out.Ptr; + } + if(InPtr[-3] != ':') + { + *Out.Ptr++ = ':'; + *Out.Ptr++ = ' '; + } + while(*Temp.Ptr) + { + *Out.Ptr++ = *Temp.Ptr++; + } + } + } + } + } + + while(*InPtr) + { + *Out.Ptr++ = *InPtr++; + } + + if(HMML.annotations[AnnotationIndex].author && + WritingChat == TRUE) + { + *Out.Ptr++ = '\"'; + } + + *Out.Ptr++ = '\n'; +skip: {}; + } + + Temp.Location = MemoryArena + ClaimedMemory; + Temp.Size = 256; + ClaimedMemory += Temp.Size; + Temp.Ptr = Temp.Location; + + sprintf(Temp.Location, "\nAnnotated by %s - https://handmade.network/m/%s\n", + HMML.metadata.annotator, HMML.metadata.annotator); + + while(*Temp.Ptr) + { + *Out.Ptr++ = *Temp.Ptr++; + } + + *Temp.Location = '\0'; + ClaimedMemory -= Temp.Size; + + if(Out.Ptr - Out.Location > 5000) + { + WritingChat = FALSE; + } + else + { + break; + } + } + + if(Out.Ptr - Out.Location > 5000) + { + fprintf(stderr, "%s: %ld characters over budget. Requires manual shrinking!\n", Args[FileIndex], (Out.Ptr - Out.Location) - 5000); + } + + // NOTE(matt): At this point we should have filled a buffer with the stuff + hmml_free(&HMML); + + // NOTE(matt): Open a file for writing out to + Temp.Location = MemoryArena + ClaimedMemory; + Temp.Size = StringLength(Args[FileIndex]) + 5; + ClaimedMemory += Temp.Size; + + sprintf(Temp.Location, "%s.txt", Args[FileIndex]); + //printf("Writing to %s\n", Temp.Location); + FILE *OutFile; + if(!(OutFile = fopen(Temp.Location, "w"))) + { + perror(Args[0]); + free(MemoryArena); + return 1; + } + + *Temp.Location = '\0'; + ClaimedMemory -= Temp.Size; + + fwrite(Out.Location, Out.Ptr - Out.Location, 1, OutFile); + fclose(OutFile); + } + else + { + fprintf(stderr, "%s:%d: %s\n", Args[FileIndex], HMML.error.line, HMML.error.message); + hmml_free(&HMML); + } + + free(MemoryArena); + } + + return 0; +}