This commit is contained in:
2026-08-15 17:50:48 +02:00
parent 22246060e6
commit 4dc6687de7
35 changed files with 4978 additions and 1509 deletions
+146
View File
@@ -0,0 +1,146 @@
local msg = require('mp.msg')
local utils = require('mp.utils')
local user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
-- 解析多种 time 表示为秒数(支持数字、带小数、HH:MM:SS、MM:SS
local function parse_mgtv_time(time_str)
if time_str == nil then return 0 end
if type(time_str) == 'number' then return time_str end
local s = tostring(time_str):gsub('^%s*(.-)%s*$', '%1')
local n = tonumber(s)
if n then return n end
local h, m, sec = s:match('^(%d+):(%d+):([%d%.]+)$')
if h and m and sec then
return tonumber(h) * 3600 + tonumber(m) * 60 + tonumber(sec)
end
local mm, ss = s:match('^(%d+):([%d%.]+)$')
if mm and ss then
return tonumber(mm) * 60 + tonumber(ss)
end
return 0
end
-- 生成分段请求列表(每段以 ms 为单位的起点)
local function generate_mgtv_segments(api_base, total_seconds, step_ms)
local segments = {}
local end_time_ms = math.floor(total_seconds * 1000)
for i = 0, math.max(0, end_time_ms - 1), step_ms do
table.insert(segments, api_base .. tostring(i))
end
return segments
end
-- 构建通用 curl 请求参数
local function build_mgtv_curl_args(target_url)
local args = {
'curl', '-s', '-L', '--compressed',
'--user-agent', user_agent,
'-H', 'Accept: application/json',
target_url,
}
return args
end
-- 解析单个分段返回并把弹幕追加到 output_table
local function parse_mgtv_segment(out, output_table)
if not out then return end
local j = utils.parse_json(out)
if not j or not j.data or not j.data.items then return end
for _, item in ipairs(j.data.items) do
local t_ms = tonumber(item.time) or 0
local time_s = t_ms / 1000
local content = item.content or ''
local mode = 1
local color = 16777215
local c_param = string.format('%.2f,%d,%d,25,,,', time_s, color, mode)
table.insert(output_table, { c = c_param, m = content })
end
end
local function extract_mgtv_ids(path)
if not path then return nil, nil end
-- 常见格式: /b/<cid>/<vid>.html
local cid, vid = path:match('/b/(%d+)/([%w%._-]+)%.html')
if cid and vid then
vid = vid:match('([^.]+)') or vid
return cid, vid
end
-- 回退:取最后两个 path segment
local segs = {}
for seg in path:gmatch('/([^/]+)') do table.insert(segs, seg) end
if #segs >= 2 then
cid = segs[#segs - 1]
vid = segs[#segs]
vid = vid and vid:match('([^.]+)') or nil
return cid, vid
end
return nil, nil
end
-- 为 芒果TV 加载弹幕
function load_danmaku_for_mgtv(path, callback)
callback = callback or function() end
local url = path or mp.get_property('stream-open-filename', '')
if not url or url == '' then
msg.error('mgtv: 无效的 url')
return
end
local cid, vid = extract_mgtv_ids(url)
if not cid or not vid then
msg.error('mgtv: 无法解析 cid/vid: ' .. tostring(url))
return
end
local info_api = 'https://pcweb.api.mgtv.com/video/info?cid=' .. cid .. '&vid=' .. vid
local api_danmaku_base = 'https://galaxy.bz.mgtv.com/rdbarrage?vid=' .. vid .. '&cid=' .. cid .. '&time='
local args = build_mgtv_curl_args(info_api)
call_cmd_async(args, function(err, out)
if err then
msg.error('mgtv: 请求 video/info 失败: ' .. tostring(err))
callback(false)
return
end
local data = utils.parse_json(out)
if not data or data.code ~= 200 or not data.data or not data.data.info then
msg.info('mgtv: video/info 返回无效')
callback(false)
return
end
local time_str = data.data.info.time
local total_seconds = parse_mgtv_time(time_str)
local step = 60 * 1000
local segments = generate_mgtv_segments(api_danmaku_base, total_seconds, step)
if #segments == 0 then
msg.info('mgtv: 未生成任何弹幕分段请求')
callback(false)
return
end
local output_table = {}
local function per_response_cb(server, err, out)
if err then
msg.debug('mgtv segment request failed: ' .. tostring(server) .. ' err: ' .. tostring(err))
return
end
parse_mgtv_segment(out, output_table)
end
local function final_cb()
local ok = #output_table > 0
local final_json_str = utils.format_json(output_table)
save_danmaku_json(url, final_json_str)
load_danmaku(true)
callback(ok)
end
parallel_requests(segments, build_mgtv_curl_args, per_response_cb, final_cb, { concurrency = 6, per_request_timeout = 10 })
end)
end