diff --git a/src/transcript_browser/_main.cpp b/src/transcript_browser/_main.cpp deleted file mode 100644 index aa32c01..0000000 --- a/src/transcript_browser/_main.cpp +++ /dev/null @@ -1,384 +0,0 @@ -#define BASIC_IMPL -#include "../basic/basic.h" -#include "../basic/filesystem.h" -#include "tests.h" - -#include -#include -#include - -Arena Perm; - -/* - -TODO: -- New threading model idea: I could just spin up a bunch of threads and then don't kill them. Just use them for searching! Each one would have it's own xarena and so on. -- Improve scrolling -- Highlight selected line -- Improve the looks of the application -*/ - -struct TimeString { - uint16_t hour; - uint16_t minute; - uint16_t second; - String string; -}; - -Array ParseSrtFile(Arena *arena, String filename) { - String content = ReadFile(*arena, filename); - Array lines = Split(*arena, content, "\n"); - - IterRemove(lines) { - IterRemovePrepare(lines); - it = Trim(it); - if (it.len == 0) remove_item = true; - } - - long section_number = 1; - Array time_strings = {*arena}; - for (int i = 0; i < lines.len;) { - String it0 = lines[i++]; - long num = strtol(it0.data, NULL, 10); - Assert(section_number == num); // @todo: error - section_number += 1; - - TimeString item = {}; - String it1 = lines[i++]; - item.hour = (uint16_t)strtol(it1.data, NULL, 10); - item.minute = (uint16_t)strtol(it1.data + 3, NULL, 10); - item.second = (uint16_t)strtol(it1.data + 6, NULL, 10); - - String next_section_number = Format(*arena, "%d", section_number); - while (i < lines.len && lines[i] != next_section_number) { - String it = lines[i]; - item.string = lines[i]; - time_strings.add(item); - i += 1; - } - } - - IterRemove(time_strings) { - IterRemovePrepare(time_strings); - if (i > 0 && AreEqual(time_strings[i - 1].string, time_strings[i].string, true)) { - remove_item = true; - } - } - - return time_strings; -} - -struct TimeFile { - Array time_strings; - String file; -}; - -struct ParseThreadIO { - Array input_files; - - // output - Arena *arena; - Array time_files; -}; - -void ParseThreadEntry(ParseThreadIO *io) { - io->arena = AllocArena(); - io->time_files.allocator = *io->arena; - For(io->input_files) { - Array time_strings = ParseSrtFile(io->arena, it); - io->time_files.add({time_strings, it}); - } -} - -struct XToTimeString { - String string; // String inside transcript arena - uint16_t hour; - uint16_t minute; - uint16_t second; - String filepath; -}; -Arena XArena; - -void AddFolder(String folder, Array *filenames, Array *x_to_time_string) { - Scratch scratch; - - Array srt_files = {scratch}; - for (FileIter iter = IterateFiles(scratch, folder); IsValid(iter); Advance(&iter)) { - String file = Copy(Perm, iter.absolute_path); - filenames->add(file); - if (EndsWith(iter.filename, ".srt")) { - srt_files.add(file); - } - } - - int64_t thread_count = 16; - Array threads = {scratch}; - int64_t files_per_thread = srt_files.len / thread_count; - int64_t remainder = srt_files.len % thread_count; - int64_t fi = 0; - - Array io = {scratch}; - io.reserve(thread_count); - for (int ti = 0; ti < thread_count; ti += 1) { - Array files = {scratch}; - for (int i = 0; fi < srt_files.len && i < files_per_thread + remainder; fi += 1, i += 1) { - files.add(srt_files[fi]); - } - if (remainder) remainder = 0; - - ParseThreadIO *i = io.alloc(); - i->input_files = files; - threads.add(new std::thread(ParseThreadEntry, i)); - } - - For(threads) { - it->join(); - delete it; - } - - ForItem(it_io, io) { - ForItem(it_time_file, it_io.time_files) { - For(it_time_file.time_strings) { - String s = Copy(XArena, it.string); - s.data[s.len] = ' '; - x_to_time_string->add({s, it.hour, it.minute, it.second, it_time_file.file}); - } - } - Release(it_io.arena); - } -} - -// -// Searching thread -// - -Arena MatchesArena; -Array Matches = {MatchesArena}; -XToTimeString *ItemFound; -Array Prompt; // system allocated - -std::mutex SearchThreadArrayMutex; -std::binary_semaphore SearchThreadSemaphore{0}; -bool SearchThreadStopSearching = false; -bool SearchThreadRunning = true; -void SearchThreadEntry() { - InitArena(&MatchesArena); - for (;;) { - SearchThreadSemaphore.acquire(); - if (!SearchThreadRunning) break; - SearchThreadStopSearching = false; - - if (Prompt.len) { - SearchThreadArrayMutex.lock(); - { - Matches.clear(); - } - SearchThreadArrayMutex.unlock(); - - String buffer = {(char *)XArena.data, (int64_t)XArena.len}; - String find = {Prompt.data, Prompt.len}; - int64_t index = 0; - while (Seek(buffer, find, &index, SeekFlag_IgnoreCase)) { - String found = {buffer.data + index, find.len}; - SearchThreadArrayMutex.lock(); - { - Matches.add(found); - } - SearchThreadArrayMutex.unlock(); - - if (SearchThreadStopSearching) break; - buffer = buffer.skip(index + find.len); - } - } - } -} - -void SearchThreadClose(std::thread &thread) { - SearchThreadRunning = false; - SearchThreadSemaphore.release(); - thread.join(); -} - -int main() { - InitOS(); - InitScratch(); - InitArena(&Perm); - InitArena(&XArena); - Arena *frame_arena = AllocArena(); - XArena.align = 0; - - String start_string = "read=D:/zizek"; - For(start_string) Prompt.add(it); - - std::thread search_thread(SearchThreadEntry); - int64_t chosen_text = 0; - int64_t match_search_offset = 0; - Array filenames = {}; - Array x_to_time_string = {}; - - InitWindow(1920, 1080, "Transcript Browser"); - SetWindowState(FLAG_WINDOW_RESIZABLE); - SetTargetFPS(60); - Font font = LoadFontEx("C:/Windows/Fonts/consola.ttf", 20, 0, 250); - while (!WindowShouldClose()) { - Clear(frame_arena); - - for (int key = GetCharPressed(); key; key = GetCharPressed()) { - UTF8Result utf8 = UTF32ToUTF8(key); - if (utf8.error) { - Prompt.add('?'); - continue; - } - - for (int i = 0; i < utf8.len; i += 1) { - Prompt.add(utf8.out_str[i]); - match_search_offset = 0; - SearchThreadStopSearching = true; - SearchThreadSemaphore.release(); - } - } - - if (IsKeyPressed(KEY_BACKSPACE) || IsKeyPressedRepeat(KEY_BACKSPACE)) { - if (ItemFound) { - ItemFound = NULL; - } else if (Prompt.len > 0) { - Prompt.pop(); - match_search_offset = 0; - SearchThreadStopSearching = true; - SearchThreadSemaphore.release(); - } - } - - int64_t offset_size = 1; - if (IsKeyDown(KEY_LEFT_CONTROL)) { - offset_size = 10; - } - if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) { - chosen_text += offset_size; - if (chosen_text > 10) match_search_offset += offset_size; - } - if (IsKeyPressed(KEY_UP) || IsKeyPressedRepeat(KEY_UP)) { - chosen_text -= offset_size; - match_search_offset -= offset_size; - } - chosen_text = Clamp(chosen_text, (int64_t)0, Max(Matches.len - 1, (int64_t)0)); - match_search_offset = Clamp(match_search_offset, (int64_t)0, Max(Matches.len - 1 - 10, (int64_t)0)); - - if (IsKeyPressed(KEY_ENTER)) { - String prompt = {Prompt.data, Prompt.len}; - if (StartsWith(prompt, "read=")) { - Prompt.add('\0'); - AddFolder(prompt.skip(5), &filenames, &x_to_time_string); - Prompt.clear(); - } else if (ItemFound) { - String base = ChopLastPeriod(ItemFound->filepath); // .srt - base = ChopLastPeriod(base); // .en - - For(filenames) { - if (StartsWith(it, base)) { - if (EndsWith(it, ".mkv") || EndsWith(it, ".webm") || EndsWith(it, ".mp4")) { - int seconds = ItemFound->hour * 60 * 60 + ItemFound->minute * 60 + ItemFound->second; - String copy = Copy(*frame_arena, it); - for (int i = 0; i < copy.len; i += 1) - if (copy.data[i] == '/') copy.data[i] = '\\'; - String args = Format(*frame_arena, "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe --start-time %d \"%.*s\"", seconds, FmtString(copy)); - printf("%.*s\n", FmtString(args)); - RunEx(args); - } - } - } - } else if (Matches.len) { - String string = Matches[chosen_text]; - For(x_to_time_string) { - uintptr_t begin = (uintptr_t)(it.string.data); - uintptr_t end = (uintptr_t)(it.string.data + it.string.len); - uintptr_t needle = (uintptr_t)string.data; - - if (needle >= begin && needle < end) { - ItemFound = ⁢ - break; - } - } - } - } - BeginDrawing(); - ClearBackground(RAYWHITE); - - float font_size = 20; - float y = 0; - int xwidth = (int)MeasureTextEx(font, "_", font_size, 1).x; - - if (ItemFound) { - uintptr_t begin_region = (uintptr_t)XArena.data; - uintptr_t end_region = (uintptr_t)XArena.data + XArena.len; - - uintptr_t begin = (uintptr_t)(ItemFound->string.data - 1000); - uintptr_t end = (uintptr_t)(ItemFound->string.data + 1000); - - begin = Clamp(begin, begin_region, end_region); - end = Clamp(end, begin_region, end_region); - String string = {(char *)begin, (int64_t)(end - begin)}; - - String filename = SkipToLastSlash(ItemFound->filepath); - DrawTextEx(font, filename.data, {0, y}, font_size, 1, BLACK); - y += font_size; - - int per_line = (GetRenderWidth() / xwidth) - 20; - - for (String it = string; it.len;) { - String line = it.get_prefix(per_line); - - if (ItemFound->string.data >= line.data && ItemFound->string.data < line.data + line.len) { - DrawRectangleLines(0, (int)(y + font_size), GetRenderWidth(), 2, SKYBLUE); - } - - String line_terminated = Copy(*frame_arena, line); - DrawTextEx(font, line_terminated.data, {0, y}, font_size, 1, DARKGRAY); - - y += font_size; - it = it.skip(per_line); - } - } else { - Prompt.add('\0'); - DrawTextEx(font, "> ", {0, y}, font_size, 1, BLACK); - DrawTextEx(font, Prompt.data, {(float)xwidth * 3, y}, font_size, 1, BLACK); - Prompt.pop(); - y += font_size; - - int64_t chars_per_line = GetRenderWidth() / xwidth - Prompt.len; - - SearchThreadArrayMutex.lock(); - for (int64_t i = match_search_offset; i < Matches.len; i += 1) { - String it = Matches[i]; - uintptr_t begin_region = (uintptr_t)XArena.data; - uintptr_t end_region = (uintptr_t)XArena.data + XArena.len; - - uintptr_t begin = (uintptr_t)(it.data - chars_per_line / 2); - uintptr_t end = (uintptr_t)(it.data + chars_per_line / 2); - - begin = Clamp(begin, begin_region, end_region); - end = Clamp(end, begin_region, end_region); - String string = Copy(*frame_arena, {(char *)begin, (int64_t)(end - begin)}); - - String string_first = Copy(*frame_arena, {(char *)begin, (int64_t)(it.data - begin)}); - String string_middle = Copy(*frame_arena, it); - int width = (int)MeasureTextEx(font, string_first.data, font_size, 1).x; - if (chosen_text == i) DrawRectangleLines(0, (int)(y + font_size), GetRenderWidth(), 2, SKYBLUE); - - String num = Format(*frame_arena, "%d", i); - DrawTextEx(font, num.data, {0, y}, font_size, 1, DARKGRAY); - DrawTextEx(font, string.data, {(float)xwidth * 4, y}, font_size, 1, DARKGRAY); - DrawTextEx(font, string_middle.data, {(float)xwidth * 4 + (float)width, y}, font_size, 1, SKYBLUE); - - y += font_size; - if (y > GetRenderHeight()) break; - } - SearchThreadArrayMutex.unlock(); - } - - if (IsKeyDown(KEY_F1)) DrawFPS(0, 0); - EndDrawing(); - } - CloseWindow(); - SearchThreadClose(search_thread); -}