Created
March 16, 2025 05:15
-
-
Save LaptopDev/ac02fcd55d929323c722ad71919ff4cd to your computer and use it in GitHub Desktop.
Convert youtube .vtt to .srt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local input_file = "tG1hCDXoE-I.en.vtt" -- Change this to your VTT file path | |
local output_file = "output.srt" | |
-- Define input and output file paths. | |
-- Read the entire VTT file into an array of lines. | |
local lines = {} | |
for line in io.lines(input_file) do | |
table.insert(lines, line) | |
end | |
-- Arrays for storing parsed values: | |
local timestamp_str_start = {} -- Starting timestamp extracted from VTT (from line start to space after '>') | |
local timestamp_str_start_len = {} -- Length of the starting timestamp string (first element number value) | |
local timestamp_str_ending = {} -- Ending timestamp snippet (the first non-blank line after three blank lines) | |
local top_subtitle = {} -- Top subtitle (first line of caption) | |
local bottom_subtitle = {} -- Bottom subtitle (second line of caption) | |
local timestamp = {} -- Combined SRT-formatted timestamp (start --> end) | |
-- Initialize iterator for subtitle entries. | |
local i = 0 | |
local line_index = 1 | |
local first_timestamp_skipped = false -- Flag to track if the first timestamp has been skipped. | |
-- Loop through the VTT lines until the end of the file. | |
while line_index <= #lines do | |
local line = lines[line_index] | |
-- Detect a line with a timestamp (pattern: HH:MM:SS.mmm followed by whitespace) | |
if string.match(line, "%d%d:%d%d:%d%d%.%d%d%d%s") then | |
-- If the first timestamp has not been skipped yet, skip this one. | |
if not first_timestamp_skipped then | |
first_timestamp_skipped = true | |
else | |
-- Extract and store the starting timestamp. | |
timestamp_str_start[i] = line:match("(%d%d:%d%d:%d%d%.%d%d%d)%s") | |
-- Save the length of the starting timestamp as required. | |
timestamp_str_start_len[i] = #timestamp_str_start[i] | |
-- Read the following line as the top subtitle. | |
line_index = line_index + 1 | |
top_subtitle[i] = lines[line_index] or "" | |
-- Skip lines until three blank lines are encountered. | |
local blank_count = 0 | |
while blank_count < 3 and line_index < #lines do | |
line_index = line_index + 1 | |
if lines[line_index] == "" then | |
blank_count = blank_count + 1 | |
end | |
end | |
-- After three blank lines, read the next line for the ending timestamp snippet. | |
line_index = line_index + 1 | |
if lines[line_index] then | |
timestamp_str_ending[i] = lines[line_index]:match("(%d%d:%d%d:%d%d%.%d%d%d)") | |
else | |
timestamp_str_ending[i] = nil | |
end | |
-- Read the next line as the bottom subtitle. | |
line_index = line_index + 1 | |
bottom_subtitle[i] = lines[line_index] or "" | |
-- Combine the starting and ending timestamps into proper SRT format. | |
-- Replace periods with commas. | |
if timestamp_str_start[i] and timestamp_str_ending[i] then | |
timestamp[i] = string.gsub(timestamp_str_start[i], "%.", ",") .. " --> " .. | |
string.gsub(timestamp_str_ending[i], "%.", ",") | |
end | |
-- Increase the iterator to process the next subtitle block. | |
i = i + 1 | |
end | |
end | |
-- Move to the next line in the file. | |
line_index = line_index + 1 | |
end | |
-- Write the parsed subtitles into the SRT output file. | |
local out = io.open(output_file, "w") | |
for j = 0, i - 1 do | |
if timestamp[j] then | |
-- Write the entry number. | |
out:write(j + 1 .. "\n") | |
-- Write the combined timestamp. | |
out:write(timestamp[j] .. "\n") | |
-- Write the top subtitle (first line of caption). | |
out:write(top_subtitle[j] .. "\n") | |
-- Write the bottom subtitle (second line) if it exists. | |
if bottom_subtitle[j] ~= "" then | |
out:write(bottom_subtitle[j] .. "\n") | |
end | |
-- Blank line separating entries. | |
out:write("\n") | |
end | |
end | |
out:close() | |
print("Conversion complete. Output saved as " .. output_file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment