// THQA Subtitle format (.sub) // Text-based subtitle file with timing information // Format: \r\n type thqa_sub ui("Subtitle File", root) { criteria { require _ext == "sub"; // First character should be a digit (start of timestamp) first_byte = u8at(0); require first_byte >= 0x30 && first_byte <= 0x39; } // Read entire file as UTF-8 text (handles special characters properly) fileset_text(utf8(read(size()))); // Split into lines lines = split_lines(file_text); line_count = len(lines); // Parse each line skip_tree("subtitles"); line_idx = 0; repeat(line_count) { lineset_text(list_at(lines, line_idx)); // Split line by spaces: "start duration text..." // First space separates start time space1 = find(line_text, " "); if (space1 > 0) { start_str = substr(line_text, 0, space1); rest1 = substr(line_text, space1 + 1, len(line_text) - space1 - 1); // Second space separates duration from text space2 = find(rest1, " "); if (space2 > 0) { duration_str = substr(rest1, 0, space2); subset_text(substr(rest1, space2 + 1, len(rest1) - space2 - 1)); ctx_set("_thqa_sub_start", start_str); ctx_set("_thqa_sub_duration", duration_str); ctx_set("_thqa_sub_text", sub_text); ctx_set("_thqa_sub_idx", line_idx); dummy = bytesat(0, 1); row_child = dummy |> parse thqa_sub_row; push("subtitles", row_child); } } line_idx = line_idx + 1; } // Table display attribute ui_table("subtitles", "subtitles", "Index,Start,Duration,Text"); subtitle_count = len(lines) ui("Subtitle Count"); file_size = size() ui("File Size"); } // Row type for subtitle table type thqa_sub_row ui("Subtitle") { set_hidden(); Index = ctx_get("_thqa_sub_idx"); Start = ctx_get("_thqa_sub_start"); Duration = ctx_get("_thqa_sub_duration"); Text = ctx_get("_thqa_sub_text"); }