fix streaming with lyric notes in mpv

This commit is contained in:
2026-03-15 01:51:10 -07:00
parent d7e42b9563
commit 4dd7556e85
3 changed files with 233 additions and 57 deletions

View File

@@ -92,7 +92,7 @@
"(hitfile\\.net/[a-z0-9A-Z]{4,9})" "(hitfile\\.net/[a-z0-9A-Z]{4,9})"
], ],
"regexp": "(hitf\\.(to|cc)/([a-z0-9A-Z]{4,9}))|(htfl\\.(net|to|cc)/([a-z0-9A-Z]{4,9}))|(hitfile\\.(net)/download/free/([a-z0-9A-Z]{4,9}))|((hitfile\\.net/[a-z0-9A-Z]{4,9}))", "regexp": "(hitf\\.(to|cc)/([a-z0-9A-Z]{4,9}))|(htfl\\.(net|to|cc)/([a-z0-9A-Z]{4,9}))|(hitfile\\.(net)/download/free/([a-z0-9A-Z]{4,9}))|((hitfile\\.net/[a-z0-9A-Z]{4,9}))",
"status": true "status": false
}, },
"mega": { "mega": {
"name": "mega", "name": "mega",
@@ -618,7 +618,7 @@
"(upload42\\.com/[0-9a-zA-Z]{12})" "(upload42\\.com/[0-9a-zA-Z]{12})"
], ],
"regexp": "(upload42\\.com/[0-9a-zA-Z]{12})", "regexp": "(upload42\\.com/[0-9a-zA-Z]{12})",
"status": true "status": false
}, },
"uploadbank": { "uploadbank": {
"name": "uploadbank", "name": "uploadbank",
@@ -690,7 +690,7 @@
"uploadrar\\.(net|com)/([0-9a-z]{12})" "uploadrar\\.(net|com)/([0-9a-z]{12})"
], ],
"regexp": "((get|cloud)\\.rahim-soft\\.com/([0-9a-z]{12}))|((fingau\\.com/([0-9a-z]{12})))|((tech|miui|cloud|flash)\\.getpczone\\.com/([0-9a-z]{12}))|(miui.rahim-soft\\.com/([0-9a-z]{12}))|(uploadrar\\.(net|com)/([0-9a-z]{12}))", "regexp": "((get|cloud)\\.rahim-soft\\.com/([0-9a-z]{12}))|((fingau\\.com/([0-9a-z]{12})))|((tech|miui|cloud|flash)\\.getpczone\\.com/([0-9a-z]{12}))|(miui.rahim-soft\\.com/([0-9a-z]{12}))|(uploadrar\\.(net|com)/([0-9a-z]{12}))",
"status": false, "status": true,
"hardRedirect": [ "hardRedirect": [
"uploadrar.com/([0-9a-zA-Z]{12})" "uploadrar.com/([0-9a-zA-Z]{12})"
] ]

View File

@@ -46,6 +46,8 @@ local DOWNLOAD_STORE_MENU_TYPE = 'medios_download_pick_store'
-- Menu types for the command submenu and trim prompt -- Menu types for the command submenu and trim prompt
local CMD_MENU_TYPE = 'medios_cmd_menu' local CMD_MENU_TYPE = 'medios_cmd_menu'
local TRIM_PROMPT_MENU_TYPE = 'medios_trim_prompt' local TRIM_PROMPT_MENU_TYPE = 'medios_trim_prompt'
local SLEEP_PROMPT_MENU_TYPE = 'medeia_sleep_timer_prompt'
local _sleep_timer = nil
local PIPELINE_REQ_PROP = 'user-data/medeia-pipeline-request' local PIPELINE_REQ_PROP = 'user-data/medeia-pipeline-request'
local PIPELINE_RESP_PROP = 'user-data/medeia-pipeline-response' local PIPELINE_RESP_PROP = 'user-data/medeia-pipeline-response'
@@ -277,6 +279,66 @@ local function find_file_upwards(start_dir, relative_path, max_levels)
return nil return nil
end end
local function _append_unique_path(out, seen, path)
path = trim(tostring(path or ''))
if path == '' then
return
end
local key = path:gsub('\\', '/'):lower()
if seen[key] then
return
end
seen[key] = true
out[#out + 1] = path
end
local function _build_sibling_script_candidates(file_name)
local candidates = {}
local seen = {}
local script_dir = mp.get_script_directory() or ''
local cwd = utils.getcwd() or ''
if script_dir ~= '' then
_append_unique_path(candidates, seen, script_dir .. '/' .. file_name)
_append_unique_path(candidates, seen, script_dir .. '/LUA/' .. file_name)
_append_unique_path(candidates, seen, script_dir .. '/../' .. file_name)
_append_unique_path(candidates, seen, find_file_upwards(script_dir, 'MPV/LUA/' .. file_name, 8))
end
if cwd ~= '' then
_append_unique_path(candidates, seen, find_file_upwards(cwd, 'MPV/LUA/' .. file_name, 8))
end
return candidates
end
local function _load_lua_chunk_from_candidates(label, file_name)
local candidates = _build_sibling_script_candidates(file_name)
local last_error = nil
for _, candidate in ipairs(candidates) do
local ok_load, chunk_or_err, load_err = pcall(loadfile, candidate)
if ok_load and chunk_or_err then
local ok_run, result_or_err = pcall(chunk_or_err)
if ok_run then
_lua_log(label .. ': loaded from ' .. candidate)
return true, result_or_err, candidate
end
last_error = tostring(result_or_err or 'runtime error')
_lua_log(label .. ': runtime error at ' .. candidate .. ' (' .. last_error .. ')')
elseif ok_load then
last_error = tostring(load_err or 'loadfile failed')
_lua_log(label .. ': load failed at ' .. candidate .. ' (' .. last_error .. ')')
else
last_error = tostring(chunk_or_err or 'loadfile failed')
_lua_log(label .. ': load failed at ' .. candidate .. ' (' .. last_error .. ')')
end
end
_lua_log(label .. ': load failed; candidates=' .. tostring(#candidates) .. ' last_error=' .. tostring(last_error or 'not found'))
return false, nil, nil, last_error
end
-- Forward declaration (defined later) used by helper auto-start. -- Forward declaration (defined later) used by helper auto-start.
local _resolve_python_exe local _resolve_python_exe
@@ -1309,6 +1371,153 @@ mp.register_script_message('medeia-audio-only', function()
_audio_only() _audio_only()
end) end)
local function _cancel_sleep_timer(show_message)
if _sleep_timer ~= nil then
pcall(function()
_sleep_timer:kill()
end)
_sleep_timer = nil
end
if show_message then
mp.osd_message('Sleep timer cancelled', 1.5)
end
end
local function _parse_sleep_minutes(text)
local s = trim(tostring(text or '')):lower()
if s == '' then
return nil
end
if s == 'off' or s == 'cancel' or s == 'stop' or s == '0' then
return 0
end
local hours = s:match('^([%d%.]+)%s*h$')
if hours then
local value = tonumber(hours)
if value and value > 0 then
return value * 60
end
return nil
end
local mins = s:match('^([%d%.]+)%s*m$')
if mins then
local value = tonumber(mins)
if value and value >= 0 then
return value
end
return nil
end
local value = tonumber(s)
if value and value >= 0 then
return value
end
return nil
end
local function _open_sleep_timer_prompt()
local items = {
{
title = '15 minutes',
hint = 'Quick preset',
value = { 'script-message-to', mp.get_script_name(), 'medeia-sleep-timer-event', utils.format_json({ type = 'search', query = '15' }) },
},
{
title = '30 minutes',
hint = 'Quick preset',
value = { 'script-message-to', mp.get_script_name(), 'medeia-sleep-timer-event', utils.format_json({ type = 'search', query = '30' }) },
},
{
title = '60 minutes',
hint = 'Quick preset',
value = { 'script-message-to', mp.get_script_name(), 'medeia-sleep-timer-event', utils.format_json({ type = 'search', query = '60' }) },
},
{
title = 'Cancel timer',
hint = 'Also accepts off / 0 / cancel',
value = { 'script-message-to', mp.get_script_name(), 'medeia-sleep-timer-event', utils.format_json({ type = 'search', query = '0' }) },
},
}
local menu_data = {
type = SLEEP_PROMPT_MENU_TYPE,
title = 'Sleep Timer',
search_style = 'palette',
search_debounce = 'submit',
on_search = { 'script-message-to', mp.get_script_name(), 'medeia-sleep-timer-search' },
footnote = 'Enter minutes (30), or use 1h / 1.5h. Enter 0 to cancel.',
items = items,
}
if ensure_uosc_loaded() then
mp.commandv('script-message-to', 'uosc', 'open-menu', utils.format_json(menu_data))
else
mp.osd_message('Sleep timer unavailable (uosc not loaded)', 2.0)
end
end
local function _apply_sleep_timer_query(query)
local minutes = _parse_sleep_minutes(query)
if minutes == nil then
mp.osd_message('Sleep timer: enter minutes, 1h, or 0 to cancel', 2.0)
return
end
if minutes <= 0 then
_cancel_sleep_timer(true)
pcall(function()
mp.commandv('script-message-to', 'uosc', 'close-menu', SLEEP_PROMPT_MENU_TYPE)
end)
return
end
_cancel_sleep_timer(false)
local seconds = math.max(1, math.floor(minutes * 60))
_sleep_timer = mp.add_timeout(seconds, function()
_sleep_timer = nil
mp.osd_message('Sleep timer: closing mpv', 1.5)
mp.commandv('quit')
end)
mp.osd_message(string.format('Sleep timer set: %d min', math.floor(minutes + 0.5)), 1.5)
_lua_log('sleep: timer set minutes=' .. tostring(minutes) .. ' seconds=' .. tostring(seconds))
pcall(function()
mp.commandv('script-message-to', 'uosc', 'close-menu', SLEEP_PROMPT_MENU_TYPE)
end)
end
local function _handle_sleep_timer_event(json)
local ok, ev = pcall(utils.parse_json, json)
if not ok or type(ev) ~= 'table' then
_lua_log('sleep: invalid event payload=' .. tostring(json))
return
end
if ev.type ~= 'search' then
return
end
_apply_sleep_timer_query(ev.query)
end
mp.register_script_message('medeia-sleep-timer', function()
_open_sleep_timer_prompt()
end)
mp.register_script_message('medeia-sleep-timer-event', function(json)
_handle_sleep_timer_event(json)
end)
mp.register_script_message('medeia-sleep-timer-search', function(query)
_apply_sleep_timer_query(query)
end)
local function _bind_image_key(key, name, fn, opts) local function _bind_image_key(key, name, fn, opts)
opts = opts or {} opts = opts or {}
if ImageControl.binding_names[name] then if ImageControl.binding_names[name] then
@@ -2680,43 +2889,22 @@ local function _start_trim_with_range(range)
_lua_log('=== TRIM START: range=' .. tostring(range)) _lua_log('=== TRIM START: range=' .. tostring(range))
mp.osd_message('Trimming...', 10) mp.osd_message('Trimming...', 10)
-- Load the trim module for direct FFmpeg trimming
local script_dir = mp.get_script_directory()
_lua_log('trim: script_dir=' .. tostring(script_dir))
-- Try multiple locations for trim.lua
local trim_paths = {}
if script_dir and script_dir ~= '' then
table.insert(trim_paths, script_dir .. '/trim.lua')
table.insert(trim_paths, script_dir .. '/LUA/trim.lua') -- if called from parent
table.insert(trim_paths, script_dir .. '/../trim.lua')
end
-- Also try absolute path
table.insert(trim_paths, '/medios/Medios-Macina/MPV/LUA/trim.lua')
table.insert(trim_paths, 'C:/medios/Medios-Macina/MPV/LUA/trim.lua')
local trim_module = nil local trim_module = nil
local trim_path = nil
local load_err = nil local load_err = nil
local ok_trim = false
for _, trim_path in ipairs(trim_paths) do ok_trim, trim_module, trim_path, load_err = _load_lua_chunk_from_candidates('trim', 'trim.lua')
_lua_log('trim: trying path=' .. trim_path)
local ok, result = pcall(loadfile, trim_path)
if ok and result then
trim_module = result()
_lua_log('trim: loaded successfully from ' .. trim_path)
break
else
load_err = tostring(result or 'unknown error')
_lua_log('trim: failed to load from ' .. trim_path .. ' (' .. load_err .. ')')
end
end
if not trim_module or not trim_module.trim_file then if not trim_module or not trim_module.trim_file then
mp.osd_message('ERROR: Could not load trim module from any path', 3) mp.osd_message('ERROR: Could not load trim module from any path', 3)
_lua_log('trim: FAILED - all paths exhausted, last error=' .. tostring(load_err)) _lua_log('trim: FAILED - all paths exhausted, last error=' .. tostring(load_err))
return return
end end
if ok_trim and trim_path then
_lua_log('trim: using module at ' .. tostring(trim_path))
end
range = trim(tostring(range or '')) range = trim(tostring(range or ''))
_lua_log('trim: after_trim range=' .. tostring(range)) _lua_log('trim: after_trim range=' .. tostring(range))
@@ -3200,13 +3388,18 @@ mp.add_timeout(0, function()
pcall(ensure_mpv_ipc_server) pcall(ensure_mpv_ipc_server)
pcall(_lua_log, 'medeia-lua loaded version=' .. MEDEIA_LUA_VERSION) pcall(_lua_log, 'medeia-lua loaded version=' .. MEDEIA_LUA_VERSION)
attempt_start_pipeline_helper_async(function(success) local ok_helper, helper_err = pcall(function()
if success then attempt_start_pipeline_helper_async(function(success)
_lua_log('helper-auto-start succeeded') if success then
else _lua_log('helper-auto-start succeeded')
_lua_log('helper-auto-start failed') else
end _lua_log('helper-auto-start failed')
end
end)
end) end)
if not ok_helper then
_lua_log('helper-auto-start raised: ' .. tostring(helper_err))
end
-- Try to re-register right-click after UOSC loads (might override its binding) -- Try to re-register right-click after UOSC loads (might override its binding)
mp.add_timeout(1.0, function() mp.add_timeout(1.0, function()
@@ -3218,25 +3411,6 @@ mp.add_timeout(0, function()
end, {repeatable=false}) end, {repeatable=false})
end) end)
end) end)
-- Load optional modules (kept in separate files).
pcall(function()
local script_dir = mp.get_script_directory() or ''
local candidates = {}
if script_dir ~= '' then
table.insert(candidates, script_dir .. '/sleep_timer.lua')
table.insert(candidates, script_dir .. '/LUA/sleep_timer.lua')
table.insert(candidates, script_dir .. '/../sleep_timer.lua')
end
table.insert(candidates, 'C:/medios/Medios-Macina/MPV/LUA/sleep_timer.lua')
for _, p in ipairs(candidates) do
local ok, chunk = pcall(loadfile, p)
if ok and chunk then
pcall(chunk)
break
end
end
end)
end) end)
return M return M

View File

@@ -1208,6 +1208,8 @@ def run_auto_overlay(
autofetch_enabled = bool(cfg.get("lyric_autofetch", True)) autofetch_enabled = bool(cfg.get("lyric_autofetch", True))
now = time.time() now = time.time()
if ( if (
not lrc_text
and
autofetch_enabled autofetch_enabled
and state.key != state.fetch_attempt_key and state.key != state.fetch_attempt_key
and (now - state.fetch_attempt_at) > 2.0 and (now - state.fetch_attempt_at) > 2.0