update
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
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
|
||||
Reference in New Issue
Block a user