vtt.lua (5300B)
1 local mp = require 'mp' 2 3 local function convert_vtt_subtitles() 4 local sid = mp.get_property_native("sid") 5 local tracks = mp.get_property_native("track-list") 6 local current_subtitle_track 7 8 if sid and sid ~= "no" then 9 for _, track in ipairs(tracks) do 10 if track["type"] == "sub" and track.id == sid then 11 current_subtitle_track = track 12 break 13 end 14 end 15 end 16 if not current_subtitle_track then 17 mp.osd_message("No selected subtitle track") 18 return 19 end 20 21 local path = current_subtitle_track["external-filename"] 22 if not current_subtitle_track.external or not path or not (path:match("%.vtt$") or path:match("^edl://")) then 23 mp.osd_message("Selected subtitle is not an external VTT") 24 return 25 end 26 27 if path:match("^edl://") then 28 local body = path:sub(7) 29 local url 30 31 -- ytdl_hook adds subtitles as EDL with the real URL in a 32 -- length-prefixed segment after the delay_open headers. 33 for entry in body:gmatch("[^;]+") do 34 if not entry:match("^!") then 35 local len, value = entry:match("^%%(%d+)%%(.*)") 36 37 if len then 38 url = value:sub(1, tonumber(len)) 39 else 40 url = entry:match("^[^,]+") 41 end 42 43 break 44 end 45 end 46 47 if url then 48 if url:match("[?&]fmt=") then 49 url = url:gsub("([?&])fmt=[^&]*", "%1fmt=vtt") 50 elseif url:match("%?") then 51 url = url .. "&fmt=vtt" 52 else 53 url = url .. "?fmt=vtt" 54 end 55 56 local res = mp.command_native({ 57 name = "subprocess", 58 args = {"curl", "-L", "-s", url}, 59 capture_stdout = true, 60 capture_stderr = true, 61 }) 62 63 if not res or res.status ~= 0 or res.stdout == "" then 64 mp.msg.warn("Could not download VTT subtitle") 65 return 66 end 67 68 path = os.tmpname() .. ".vtt" 69 local file_vtt = io.open(path, "w") 70 file_vtt:write(res.stdout) 71 file_vtt:close() 72 else 73 path = nil 74 end 75 end 76 77 local f = path and io.open(path, "r") 78 if not f then 79 mp.msg.warn("Could not open VTT subtitle") 80 return 81 end 82 83 local path_new = os.tmpname() .. ".srt" 84 local file_new = io.open(path_new, 'w') 85 local path_sentences = os.tmpname() .. ".srt" 86 local file_sentences = io.open(path_sentences, 'w') 87 88 local str_start 89 local str_end 90 local index = 1 91 local index_sentence = 1 92 local i_line = 0 93 local sentence = {} 94 local previous_timestamp_sentence = "00:00:00.000" 95 for line in f:lines() do 96 if i_line % 8 == 4 then 97 str_start, str_end = line:match("(%d%d:%d%d:%d%d%.%d+)%s+-->%s+(%d%d:%d%d:%d%d%.%d+)") 98 end 99 if i_line % 8 == 6 then 100 local line = line 101 102 -- remove <c> tags 103 line = line:gsub("</?c>", "") 104 105 -- prepend start time 106 line = " " .. line .. "<" .. str_end .. ">" 107 108 local previous_timestamp = str_start 109 for content, timestamp in line:gmatch("([^<]*)<(%d%d:%d%d:%d%d%.%d+)>") do 110 local word = content:gsub(">", ">"):gsub(" ", " ") 111 112 file_new:write(index, '\n') 113 file_new:write(previous_timestamp .. " --> " .. timestamp, '\n') 114 file_new:write(word, '\n') 115 file_new:write('\n') 116 117 if word:sub(1, 3) == " >>" then 118 file_sentences:write(index_sentence, '\n') 119 file_sentences:write(previous_timestamp_sentence .. " --> " .. previous_timestamp, '\n') 120 file_sentences:write(table.concat(sentence), '\n') 121 file_sentences:write('\n') 122 index_sentence = index_sentence + 1 123 previous_timestamp_sentence = previous_timestamp 124 sentence = {} 125 end 126 127 table.insert(sentence, word) 128 129 if word:sub(-1) == "." or word:sub(-1) == "?" or word:sub(-1) == ":" or word:sub(-2) == ".\"" or word:sub(-2) == "?\"" then 130 file_sentences:write(index_sentence, '\n') 131 file_sentences:write(previous_timestamp_sentence .. " --> " .. timestamp, '\n') 132 file_sentences:write(table.concat(sentence), '\n') 133 file_sentences:write('\n') 134 index_sentence = index_sentence + 1 135 previous_timestamp_sentence = timestamp 136 sentence = {} 137 end 138 139 previous_timestamp = timestamp 140 index = index + 1 141 end 142 end 143 i_line = i_line + 1 144 end 145 file_new:close() 146 file_sentences:close() 147 f:close() 148 149 mp.commandv("sub-add", path_new, "select") 150 mp.commandv("sub-add", path_sentences, "select") 151 152 mp.osd_message("Loaded converted VTT subtitles") 153 mp.msg.info("Loaded converted VTT subtitles") 154 end 155 156 mp.add_key_binding(nil, "convert-vtt", convert_vtt_subtitles) 157 158 -- vim: sts=4 sw=4 et