update
This commit is contained in:
+114
-103
@@ -25,11 +25,11 @@ DANMAKU_PATH = os.getenv("TEMP") or "/tmp/"
|
||||
HISTORY_PATH = mp.command_native({"expand-path", options.history_path})
|
||||
PID = utils.getpid()
|
||||
DANMAKU = {sources = {}, count = 1}
|
||||
DELAYS = {}
|
||||
ENABLED, COMMENTS, DELAY = false, nil, 0
|
||||
DELAY_PROPERTY = string.format("user-data/%s/danmaku-delay", mp.get_script_name())
|
||||
mp.set_property_native(DELAY_PROPERTY, 0)
|
||||
|
||||
HAS_DANMAKU = string.format("user-data/%s/has-danmaku", mp.get_script_name())
|
||||
mp.set_property_bool(HAS_DANMAKU, false)
|
||||
KEY = table_to_zero_indexed({
|
||||
0x00,0x01,0x02,0x03,0x04,
|
||||
0x05,0x06,0x07,0x08,0x09,
|
||||
@@ -58,6 +58,8 @@ PLATFORM = (function()
|
||||
return "linux"
|
||||
end)()
|
||||
|
||||
local rebuild_convert_timer = nil
|
||||
|
||||
function get_danmaku_visibility()
|
||||
local history_json = read_file(HISTORY_PATH)
|
||||
local history
|
||||
@@ -140,21 +142,6 @@ local function extract_between_colons(input_string)
|
||||
end
|
||||
end
|
||||
|
||||
local function hex_to_int_color(hex_color)
|
||||
-- 移除颜色代码中的'#'字符
|
||||
hex_color = hex_color:sub(2) -- 只保留颜色代码部分
|
||||
|
||||
-- 提取R, G, B的十六进制值并转为整数
|
||||
local r = tonumber(hex_color:sub(1, 2), 16)
|
||||
local g = tonumber(hex_color:sub(3, 4), 16)
|
||||
local b = tonumber(hex_color:sub(5, 6), 16)
|
||||
|
||||
-- 计算32位整数值
|
||||
local color_int = (r * 256 * 256) + (g * 256) + b
|
||||
|
||||
return color_int
|
||||
end
|
||||
|
||||
local function get_type_from_position(position)
|
||||
if position == 0 then
|
||||
return 1
|
||||
@@ -170,11 +157,13 @@ end
|
||||
function get_delay_for_time(delay_segments, time)
|
||||
if not delay_segments or #delay_segments == 0 then return 0 end
|
||||
|
||||
table.sort(delay_segments, function(a, b) return a.start < b.start end)
|
||||
local segs = {}
|
||||
for i = 1, #delay_segments do segs[i] = delay_segments[i] end
|
||||
table.sort(segs, function(a, b) return a.start < b.start end)
|
||||
|
||||
local applied_delay = 0
|
||||
for i = 1, #delay_segments do
|
||||
local seg = delay_segments[i]
|
||||
for i = 1, #segs do
|
||||
local seg = segs[i]
|
||||
local delay = tonumber(seg.delay)
|
||||
if time >= seg.start and delay then
|
||||
applied_delay = applied_delay + delay
|
||||
@@ -244,9 +233,29 @@ local function merge_delay_segments(segments)
|
||||
return merged
|
||||
end
|
||||
|
||||
local function set_danmaku_delay(dly, time)
|
||||
for url, source in pairs(DANMAKU.sources) do
|
||||
if source.fname and not source.blocked then
|
||||
function parse_delay_input(text)
|
||||
if not text then return nil end
|
||||
local s = tostring(text):gsub("%s+", "")
|
||||
if s == "" then return nil end
|
||||
-- XmYs 格式,允许负号在分钟部分
|
||||
local m, sec = string.match(s, "^(%-?%d+)m(%d+)s$")
|
||||
if m and sec then
|
||||
m = tonumber(m)
|
||||
sec = tonumber(sec)
|
||||
if not m or not sec then return nil end
|
||||
if m < 0 then sec = -sec end
|
||||
return m * 60 + sec
|
||||
end
|
||||
-- 普通数字(整数或小数),支持负数
|
||||
local n = tonumber(s)
|
||||
if n ~= nil then return n end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function set_danmaku_delay(dly, time, specific_source)
|
||||
if specific_source then
|
||||
local source = DANMAKU.sources[specific_source]
|
||||
if source and source.data and not source.blocked then
|
||||
source.delay_segments = source.delay_segments or {}
|
||||
if dly == 0 then
|
||||
source.delay_segments = {}
|
||||
@@ -255,32 +264,52 @@ local function set_danmaku_delay(dly, time)
|
||||
else
|
||||
table.insert(source.delay_segments, {start = 0, delay = dly})
|
||||
end
|
||||
|
||||
source.delay = nil
|
||||
table.sort(source.delay_segments, function(a, b) return a.start < b.start end)
|
||||
add_source_to_history(url, source)
|
||||
source.delay_segments = merge_delay_segments(source.delay_segments)
|
||||
add_source_to_history(specific_source, source)
|
||||
end
|
||||
end
|
||||
|
||||
if time then
|
||||
table.insert(DELAYS, {start = time, delay = dly})
|
||||
else
|
||||
table.insert(DELAYS, {start = 0, delay = dly})
|
||||
for url, source in pairs(DANMAKU.sources) do
|
||||
if source.data and not source.blocked then
|
||||
source.delay_segments = source.delay_segments or {}
|
||||
if dly == 0 then
|
||||
source.delay_segments = {}
|
||||
elseif time then
|
||||
table.insert(source.delay_segments, {start = time, delay = dly})
|
||||
else
|
||||
table.insert(source.delay_segments, {start = 0, delay = dly})
|
||||
end
|
||||
|
||||
source.delay = nil
|
||||
source.delay_segments = merge_delay_segments(source.delay_segments)
|
||||
add_source_to_history(url, source)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if dly == 0 then
|
||||
DELAY = 0
|
||||
DELAYS = {}
|
||||
else
|
||||
DELAY = DELAY + dly
|
||||
end
|
||||
|
||||
DELAYS = merge_delay_segments(DELAYS)
|
||||
|
||||
if ENABLED and COMMENTS ~= nil then
|
||||
render()
|
||||
end
|
||||
|
||||
-- 防抖:批量重建 ASS 事件并渲染,避免频繁变更导致重复重建
|
||||
if rebuild_convert_timer then
|
||||
rebuild_convert_timer:kill()
|
||||
rebuild_convert_timer = nil
|
||||
end
|
||||
rebuild_convert_timer = mp.add_timeout(0.1, function()
|
||||
if convert_danmaku_to_ass_events then
|
||||
convert_danmaku_to_ass_events(true)
|
||||
end
|
||||
render()
|
||||
rebuild_convert_timer = nil
|
||||
end)
|
||||
|
||||
show_message('设置弹幕延迟: ' .. string.format("%.1f", DELAY + 1e-10) .. ' s')
|
||||
mp.set_property_native(DELAY_PROPERTY, DELAY)
|
||||
end
|
||||
@@ -299,9 +328,6 @@ local function clear_source()
|
||||
|
||||
for url, source in pairs(DANMAKU.sources) do
|
||||
if source.from == "user_custom" then
|
||||
if source.fname and file_exists(source.fname) then
|
||||
os.remove(source.fname)
|
||||
end
|
||||
DANMAKU.sources[url] = nil
|
||||
end
|
||||
end
|
||||
@@ -312,7 +338,7 @@ local function clear_source()
|
||||
msg.verbose("已重置当前视频所有弹幕源更改")
|
||||
end
|
||||
|
||||
function write_history(episodeid)
|
||||
function write_history(episodeid, api_server)
|
||||
local history = {}
|
||||
local path = mp.get_property("path")
|
||||
local dir = get_parent_directory(path)
|
||||
@@ -353,6 +379,9 @@ function write_history(episodeid)
|
||||
elseif DANMAKU.extra then
|
||||
history[dir].extra = DANMAKU.extra
|
||||
end
|
||||
if api_server then
|
||||
history[dir].api_server = api_server
|
||||
end
|
||||
write_json_file(HISTORY_PATH, history)
|
||||
end
|
||||
end
|
||||
@@ -401,6 +430,11 @@ function add_source_to_history(add_url, add_source)
|
||||
local record = history[path]["sources"][add_url]
|
||||
record.from = add_source.from or "user_custom"
|
||||
record.blocked = add_source.blocked or false
|
||||
if record.from == "api_server" then
|
||||
record.api_server = add_source.api_server or options.api_server
|
||||
else
|
||||
record.api_server = nil
|
||||
end
|
||||
|
||||
local delay_segments = shallow_copy(add_source.delay_segments or {})
|
||||
if #delay_segments > 0 then
|
||||
@@ -455,6 +489,7 @@ function read_danmaku_source_record(path)
|
||||
blocked = blocked,
|
||||
delay_segments = delay_segments,
|
||||
from_history = true,
|
||||
api_server = data.api_server,
|
||||
}
|
||||
end
|
||||
else
|
||||
@@ -484,6 +519,7 @@ function read_danmaku_source_record(path)
|
||||
blocked = blocked,
|
||||
delay_segments = delay_segments,
|
||||
from_history = true,
|
||||
api_server = record.api_server,
|
||||
}
|
||||
|
||||
upgraded_sources[source] = shallow_copy(DANMAKU.sources[source])
|
||||
@@ -496,39 +532,8 @@ function read_danmaku_source_record(path)
|
||||
end
|
||||
end
|
||||
|
||||
-- 收集现有的弹幕文件和延迟记录
|
||||
local function collect_danmaku_sources()
|
||||
local danmaku_input = {}
|
||||
local delays = {}
|
||||
|
||||
for _, source in pairs(DANMAKU.sources) do
|
||||
if not source.blocked and source.fname then
|
||||
if not file_exists(source.fname) then
|
||||
show_message("未找到弹幕文件", 3)
|
||||
msg.info("未找到弹幕文件")
|
||||
return
|
||||
end
|
||||
table.insert(danmaku_input, source.fname)
|
||||
|
||||
if source.delay_segments and #source.delay_segments > 0 then
|
||||
table.insert(delays, source.delay_segments)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return danmaku_input, delays
|
||||
end
|
||||
|
||||
-- 视频播放时保存弹幕
|
||||
function save_danmaku(not_forced)
|
||||
local danmaku_input, delays = collect_danmaku_sources()
|
||||
if #danmaku_input == 0 then
|
||||
show_message("弹幕内容为空,无法保存", 3)
|
||||
msg.verbose("弹幕内容为空,无法保存")
|
||||
COMMENTS = {}
|
||||
return
|
||||
end
|
||||
|
||||
local path = mp.get_property("path")
|
||||
local dir = get_parent_directory(path) or ""
|
||||
local filename = mp.get_property('filename/no-ext')
|
||||
@@ -544,7 +549,7 @@ function save_danmaku(not_forced)
|
||||
msg.info("已存在同名弹幕文件:" .. danmaku_out)
|
||||
return
|
||||
else
|
||||
convert_danmaku_to_xml(danmaku_input, danmaku_out, delays)
|
||||
convert_danmaku_to_xml(danmaku_out)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -552,19 +557,8 @@ end
|
||||
-- 加载弹幕
|
||||
function load_danmaku(from_menu, no_osd)
|
||||
if not ENABLED then return end
|
||||
local temp_file = "danmaku-" .. PID .. ".ass"
|
||||
local danmaku_file = utils.join_path(DANMAKU_PATH, temp_file)
|
||||
local danmaku_input, delays = collect_danmaku_sources()
|
||||
-- 如果没有弹幕文件,退出加载
|
||||
if #danmaku_input == 0 then
|
||||
show_message("该集弹幕内容为空,结束加载", 3)
|
||||
msg.verbose("该集弹幕内容为空,结束加载")
|
||||
COMMENTS = {}
|
||||
return
|
||||
end
|
||||
|
||||
convert_danmaku_format(danmaku_input, danmaku_file, delays)
|
||||
parse_danmaku(danmaku_file, from_menu, no_osd)
|
||||
convert_danmaku_to_ass_events()
|
||||
render_danmaku(from_menu, no_osd)
|
||||
end
|
||||
|
||||
-- 为 bilibli 网站的视频播放加载弹幕
|
||||
@@ -620,6 +614,11 @@ function load_danmaku_for_bilibili(path)
|
||||
url,
|
||||
}
|
||||
|
||||
if options.cookie_file and options.cookie_file ~= "" then
|
||||
table.insert(arg, '-b')
|
||||
table.insert(arg, mp.command_native({"expand-path", options.cookie_file}))
|
||||
end
|
||||
|
||||
call_cmd_async(arg, function(error)
|
||||
async_running = false
|
||||
if error then
|
||||
@@ -673,6 +672,11 @@ function load_danmaku_for_bahamut(path)
|
||||
table.insert(arg, options.proxy)
|
||||
end
|
||||
|
||||
if options.cookie_file and options.cookie_file ~= "" then
|
||||
table.insert(arg, '-b')
|
||||
table.insert(arg, mp.command_native({"expand-path", options.cookie_file}))
|
||||
end
|
||||
|
||||
call_cmd_async(arg, function(error)
|
||||
async_running = false
|
||||
if error then
|
||||
@@ -688,30 +692,33 @@ function load_danmaku_for_bahamut(path)
|
||||
end
|
||||
|
||||
local comments_json = read_file(danmaku_json)
|
||||
os.remove(danmaku_json)
|
||||
local comments = utils.parse_json(comments_json)
|
||||
if not comments then
|
||||
return
|
||||
end
|
||||
|
||||
local output_table = {}
|
||||
for _, comment in ipairs(comments) do
|
||||
local color = hex_to_int_color(comment["color"])
|
||||
local mode = get_type_from_position(comment["position"])
|
||||
local time = tonumber(comment["time"]) / 10
|
||||
local c_param = string.format("%s,%s,%s,25,,,", time, color, mode)
|
||||
table.insert(output_table, {
|
||||
c = c_param,
|
||||
m = comment["text"]
|
||||
})
|
||||
end
|
||||
|
||||
local final_json_str = utils.format_json(output_table)
|
||||
|
||||
temp_file = "danmaku-" .. PID .. DANMAKU.count .. ".json"
|
||||
local json_filename = utils.join_path(DANMAKU_PATH, temp_file)
|
||||
DANMAKU.count = DANMAKU.count + 1
|
||||
|
||||
local json_file = io.open(json_filename, "w")
|
||||
|
||||
if json_file then
|
||||
json_file:write("[\n")
|
||||
for _, comment in ipairs(comments) do
|
||||
local m = comment["text"]
|
||||
local color = hex_to_int_color(comment["color"])
|
||||
local mode = get_type_from_position(comment["position"])
|
||||
local time = tonumber(comment["time"]) / 10
|
||||
local c = time .. "," .. color .. "," .. mode .. ",25,,,"
|
||||
|
||||
-- Write the JSON object as a single line, no spaces or extra formatting
|
||||
local json_entry = string.format('{"c":"%s","m":"%s"},\n', c, m)
|
||||
json_file:write(json_entry)
|
||||
end
|
||||
json_file:write("]")
|
||||
json_file:write(final_json_str)
|
||||
json_file:close()
|
||||
end
|
||||
|
||||
@@ -890,22 +897,27 @@ end)
|
||||
mp.register_script_message("danmaku-delay", function(...)
|
||||
local commands = {...}
|
||||
local delay_str, time_str = commands[1], commands[2]
|
||||
local dly = tonumber(delay_str)
|
||||
local source_arg = commands[3]
|
||||
local dly = parse_delay_input(delay_str)
|
||||
local time = time_str and tonumber(time_str)
|
||||
if type(dly) ~= "number" then
|
||||
show_message("参数错误:缺少有效的延迟秒数", 3)
|
||||
return
|
||||
end
|
||||
set_danmaku_delay(dly, time)
|
||||
if source_arg and source_arg ~= "nil" then
|
||||
set_danmaku_delay(dly, time, source_arg)
|
||||
else
|
||||
set_danmaku_delay(dly, time)
|
||||
end
|
||||
end)
|
||||
|
||||
mp.register_script_message("show_danmaku_keyboard", function()
|
||||
ENABLED = not ENABLED
|
||||
if ENABLED then
|
||||
mp.commandv("script-message-to", "uosc", "set", "show_danmaku", "on")
|
||||
set_danmaku_visibility(true)
|
||||
if COMMENTS == nil then
|
||||
show_message("加载弹幕初始化...", 3)
|
||||
set_danmaku_visibility(true)
|
||||
local path = mp.get_property("path")
|
||||
init(path)
|
||||
else
|
||||
@@ -915,7 +927,6 @@ mp.register_script_message("show_danmaku_keyboard", function()
|
||||
else
|
||||
show_message("关闭弹幕", 2)
|
||||
mp.commandv("script-message-to", "uosc", "set", "show_danmaku", "off")
|
||||
set_danmaku_visibility(false)
|
||||
hide_danmaku_func()
|
||||
end
|
||||
end)
|
||||
@@ -923,7 +934,7 @@ end)
|
||||
mp.register_script_message("check-update", check_for_update)
|
||||
mp.register_script_message("clear-source", clear_source)
|
||||
mp.register_script_message("immediately_save_danmaku", save_danmaku)
|
||||
mp.register_script_message("open_source_delay_menu", danmaku_delay_setup)
|
||||
mp.register_script_message("open_source_delay_menu", open_delay_menu)
|
||||
mp.register_script_message("open_search_danmaku_menu", open_input_menu)
|
||||
mp.register_script_message("open_add_source_menu", open_add_menu)
|
||||
mp.register_script_message("open_add_total_menu", open_add_total_menu)
|
||||
mp.register_script_message("open_add_total_menu", open_add_total_menu)
|
||||
Reference in New Issue
Block a user