Files
mpv-config/scripts/uosc_danmaku/sites/bilibili.lua
T
2026-08-15 17:50:48 +02:00

246 lines
8.1 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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'
local function build_curl_args(url, extra_headers)
local args = {
'curl', '-L', '-s', '--compressed', '--user-agent', user_agent
}
extra_headers = extra_headers or {}
for _, h in ipairs(extra_headers) do
table.insert(args, '-H')
table.insert(args, h)
end
if options.cookie_file and options.cookie_file ~= '' then
table.insert(args, '-b')
table.insert(args, mp.command_native({'expand-path', options.cookie_file}))
end
if options.proxy and options.proxy ~= '' then
table.insert(args, '-x')
table.insert(args, options.proxy)
end
table.insert(args, url)
return args
end
local function get_cid()
local cid, danmaku_id = nil, nil
local tracks = mp.get_property_native("track-list")
for _, track in ipairs(tracks) do
if track["lang"] == "danmaku" then
cid = track["external-filename"]:match("/(%d-)%.xml$")
danmaku_id = track["id"]
break
end
end
return cid, danmaku_id
end
local function get_bilibili_id_and_page(path)
local bvid, aid, page = nil, nil, nil
if not bvid then
bvid = path:match("/video/(BV[%w]+)")
or path:match("[?&]bvid=(BV[%w]+)")
end
if not aid then
aid = path:match("/video/av([%d]+)")
end
if not page then
page = tonumber(path:match("[?&]p=(%d+)"))
end
return bvid, aid, page or 1
end
local function get_bilibili_pagelist_args(bvid, aid)
local url
if bvid ~= nil then
url = "https://api.bilibili.com/x/player/pagelist?bvid=" .. bvid
else
url = "https://api.bilibili.com/x/player/pagelist?aid=" .. aid
end
local headers = {"Referer: https://www.bilibili.com/video/" .. (bvid or ("av" .. aid))}
return build_curl_args(url, headers)
end
local function resolve_bilibili_cid(path, callback)
-- 扩展支持:普通视频(BV/av)、番剧(ep)、课程(cheese)
local api_bangumi_season = "https://api.bilibili.com/pgc/view/web/season"
local api_cheese_season = "https://api.bilibili.com/pugv/view/web/season"
local q = path
-- 解析普通投稿视频
local bvid, aid, p = get_bilibili_id_and_page(q)
if bvid or aid then
local args = get_bilibili_pagelist_args(bvid, aid)
call_cmd_async(args, function(error, json)
if error then
msg.warn("Failed to request bilibili pagelist: " .. tostring(error))
callback(nil)
return
end
local data = utils.parse_json(json)
local pages = data and data["data"]
if type(pages) ~= "table" then
callback(nil)
return
end
local page_info = pages[p] or pages[1]
local cid = page_info and page_info["cid"]
local part = page_info and page_info["part"]
callback(cid and tostring(cid) or nil, part and tostring(part) or nil)
end)
return
end
-- 番剧、番外等(含 ep
if q:find("bangumi/") and q:find("ep") then
local epid = q:match("ep(%d+)") or q:match("ep(%d+)$")
if not epid then
callback(nil)
return
end
local url = api_bangumi_season .. "?ep_id=" .. epid
local arg = build_curl_args(url)
call_cmd_async(arg, function(error, json)
if error then
msg.warn("Failed to request bilibili bangumi info: " .. tostring(error))
callback(nil)
return
end
local data = utils.parse_json(json)
if not data or data.code ~= 0 or not data.result then
msg.warn("bilibili bangumi api returned error")
callback(nil)
return
end
-- 查找正片
local episodes = data.result.episodes or {}
for _, ep in ipairs(episodes) do
if tostring(ep.id) == tostring(epid) then
callback(tostring(ep.cid), tostring(ep.share_copy or ep.title or ""))
return
end
end
-- 查找 section(花絮等)
if type(data.result.section) == "table" then
for _, sec in ipairs(data.result.section) do
if sec.episodes then
for _, ep in ipairs(sec.episodes) do
if tostring(ep.id) == tostring(epid) then
callback(tostring(ep.cid), tostring(ep.share_copy or ep.title or ""))
return
end
end
end
end
end
callback(nil)
end)
return
end
-- cheese 课程
if q:find("cheese/") and q:find("ep") then
local epid = q:match("ep(%d+)") or q:match("ep(%d+)$")
if not epid then
callback(nil)
return
end
local url = api_cheese_season .. "?ep_id=" .. epid
local arg = build_curl_args(url)
call_cmd_async(arg, function(error, json)
if error then
msg.warn("Failed to request bilibili cheese info: " .. tostring(error))
callback(nil)
return
end
local data = utils.parse_json(json)
if not data or data.code ~= 0 or not data.data then
msg.warn("bilibili cheese api returned error")
callback(nil)
return
end
local episodes = data.data.episodes or {}
for _, ep in ipairs(episodes) do
if tostring(ep.id) == tostring(epid) then
callback(tostring(ep.cid), tostring(ep.title or ""))
return
end
end
callback(nil)
end)
return
end
-- 其它情况返回 nil
callback(nil)
end
local function download_bilibili_danmaku(path, cid, from_menu, callback)
local url = "https://comment.bilibili.com/" .. cid .. ".xml"
local args = build_curl_args(url)
call_cmd_async(args, function(error, out)
if error then
show_message("HTTP request failed, see console for details", 5)
msg.error(error)
callback(false)
return
end
if not out or out == '' then
callback(false)
return
end
save_danmaku_xml(path, out)
load_danmaku(from_menu == nil and true or from_menu)
callback(true)
end)
end
-- 为 bilibli 网站的视频播放加载弹幕
function load_danmaku_for_bilibili(path, callback)
callback = callback or function() end
local cid, danmaku_id = get_cid()
if danmaku_id ~= nil then
mp.commandv('sub-remove', danmaku_id)
end
if cid == nil then
cid = mp.get_opt('cid')
if not cid then
local patterns = {
"bilivideo%.c[nom]+.*/resource/(%d+)%D+.*",
"bilivideo%.c[nom]+.*/(%d+)-%d+-%d+%..*%?",
}
local urls = {
path,
mp.get_property("stream-open-filename", ''),
}
for _, pattern in ipairs(patterns) do
for _, url in ipairs(urls) do
if url:find(pattern) then
cid = url:match(pattern)
break
end
end
end
end
end
if cid == nil then
resolve_bilibili_cid(path, function(resolved_cid)
if resolved_cid then
download_bilibili_danmaku(path, resolved_cid, true, callback)
else
show_message("获取哔哩哔哩视频cid失败", 3)
msg.error("获取哔哩哔哩视频cid失败")
callback(false)
end
end)
return
end
if cid ~= nil then
download_bilibili_danmaku(path, cid, true, callback)
end
end