Skip to content

Instantly share code, notes, and snippets.

@Backsoon0
Created May 24, 2026 04:54
Show Gist options
  • Select an option

  • Save Backsoon0/0d19a1c00ff210a95261cb94d4b4a3fb to your computer and use it in GitHub Desktop.

Select an option

Save Backsoon0/0d19a1c00ff210a95261cb94d4b4a3fb to your computer and use it in GitHub Desktop.
-- tc2sc_sub.lua
-- 快捷键: Ctrl+t
-- 依赖: opencc (必须), ffmpeg (仅提取内封字幕时需要)
local mp = require 'mp'
local utils = require 'mp.utils'
local msg = require 'mp.msg'
-- OpenCC 配置文件,默认为繁转简 (Traditional to Simplified)
local OPENCC_CONFIG = "t2s.json"
-- 获取文件扩展名
local function get_extension(path)
return path:match("^.+(%..+)$") or ""
end
-- 获取去除了扩展名的文件名
local function strip_extension(path)
return path:match("^(.+)%..+$") or path
end
-- 核心转换函数
local function convert_sub()
local sid = mp.get_property_number("sid")
if not sid then
mp.osd_message("没有选择任何字幕 (No subtitle selected)")
return
end
local track_list = mp.get_property_native("track-list")
local current_sub = nil
-- 找到当前的字幕轨道
for _, track in ipairs(track_list) do
if track.type == "sub" and track.id == sid then
current_sub = track
break
end
end
if not current_sub then
mp.osd_message("未找到字幕轨道信息")
return
end
local is_external = current_sub.external
local in_file = current_sub["external-filename"]
local out_file = ""
local video_path = mp.get_property("path")
local dir, filename = utils.split_path(video_path)
if is_external and in_file then
-- ========== 处理外封字幕 ==========
local in_dir, in_name = utils.split_path(in_file)
local base_name = strip_extension(in_name)
local ext = get_extension(in_name)
-- 重命名逻辑:将 .tc 或 .TC 替换为 .tc2sc,如果没有则直接追加 .tc2sc
if string.match(base_name:lower(), "%.tc$") then
base_name = string.gsub(base_name, "%.tc$", ".tc2sc")
base_name = string.gsub(base_name, "%.TC$", ".tc2sc")
else
base_name = base_name .. ".tc2sc"
end
out_file = utils.join_path(in_dir, base_name .. ext)
mp.osd_message("正在使用 OpenCC 转换外封字幕...")
run_opencc(in_file, out_file)
else
-- ========== 处理内封字幕 ==========
local ff_index = current_sub["ff-index"]
if not ff_index then
mp.osd_message("无法获取内封字幕的流索引")
return
end
-- 判断字幕格式 (ASS 或 SRT)
local codec = current_sub["codec"]
local ext = ".ass"
if codec == "subrip" then ext = ".srt" end
local base_video_name = strip_extension(filename)
-- 临时文件和输出文件路径
local temp_file = utils.join_path(dir, base_video_name .. "_track_" .. tostring(sid) .. "_temp" .. ext)
out_file = utils.join_path(dir, base_video_name .. ".tc2sc" .. ext)
mp.osd_message("正在使用 FFmpeg 提取内封字幕...")
-- 步骤1: 用 FFmpeg 提取字幕
local ext_res = mp.command_native({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = {"ffmpeg", "-y", "-i", video_path, "-map", "0:" .. tostring(ff_index), "-c:s", "copy", temp_file}
})
if ext_res.status ~= 0 then
mp.osd_message("提取内封字幕失败!(请确保已安装 FFmpeg)")
msg.error("FFmpeg error: " .. (ext_res.stderr or ""))
return
end
mp.osd_message("正在使用 OpenCC 转换内封字幕...")
-- 步骤2: 用 OpenCC 转换
run_opencc(temp_file, out_file)
-- 步骤3: 清理提取出的临时文件
os.remove(temp_file)
end
end
-- 调用 OpenCC 执行转换并加载字幕
function run_opencc(in_file, out_file)
local res = mp.command_native({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = {"opencc", "-i", in_file, "-o", out_file, "-c", OPENCC_CONFIG}
})
if res.status == 0 then
mp.osd_message("繁简转换成功!已加载新字幕。")
-- 挂载新生成的字幕并选中它 ("select" 标志表示立即切换过去)
mp.commandv("sub-add", out_file, "select")
else
mp.osd_message("OpenCC 转换失败!(请确保 opencc 在系统变量中)")
msg.error("OpenCC error: " .. (res.stderr or ""))
end
end
-- 绑定快捷键 Ctrl+T
mp.add_key_binding("ctrl+t", "convert_sub_t2s", convert_sub)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment