From 4106822a0f8e9177d6fad4af5ef8db0ac4e2a8e7 Mon Sep 17 00:00:00 2001 From: Nose Date: Mon, 16 Mar 2026 04:43:46 -0700 Subject: [PATCH] f --- MPV/LUA/main.lua | 215 ++++++++++++++++++++++++++++++++++------------- cmdnat/pipe.py | 2 - 2 files changed, 158 insertions(+), 59 deletions(-) diff --git a/MPV/LUA/main.lua b/MPV/LUA/main.lua index 6e2d827..640c2c2 100644 --- a/MPV/LUA/main.lua +++ b/MPV/LUA/main.lua @@ -52,6 +52,7 @@ local _sleep_timer = nil local PIPELINE_REQ_PROP = 'user-data/medeia-pipeline-request' local PIPELINE_RESP_PROP = 'user-data/medeia-pipeline-response' local PIPELINE_READY_PROP = 'user-data/medeia-pipeline-ready' +local CURRENT_WEB_URL_PROP = 'user-data/medeia-current-web-url' -- Dedicated Lua log: write directly to logs.db database for unified logging -- Fallback to stderr if database unavailable @@ -1885,6 +1886,21 @@ function FileState.new() }, FileState) end +function FileState:set_url(url) + local normalized = trim(tostring(url or '')) + if normalized == '' then + self.url = nil + self.formats = nil + self.formats_table = nil + return + end + if self.url ~= normalized then + self.url = normalized + self.formats = nil + self.formats_table = nil + end +end + function FileState:has_formats() return type(self.formats) == 'table' and type(self.formats.rows) == 'table' @@ -1892,7 +1908,7 @@ function FileState:has_formats() end function FileState:set_formats(url, tbl) - self.url = url + self:set_url(url) self.formats = tbl self.formats_table = tbl end @@ -1903,6 +1919,7 @@ M.file = M.file or FileState.new() local _formats_cache = {} local _formats_inflight = {} local _formats_waiters = {} +local _get_cached_formats_table local _ipc_async_busy = false local _ipc_async_queue = {} @@ -1983,6 +2000,70 @@ local function _is_ytdlp_url(u) return false end +local function _set_current_web_url(url) + local normalized = trim(tostring(url or '')) + if normalized ~= '' and _is_http_url(normalized) then + pcall(mp.set_property, CURRENT_WEB_URL_PROP, normalized) + if type(M.file) == 'table' and M.file.set_url then + M.file:set_url(normalized) + end + return normalized + end + pcall(mp.set_property, CURRENT_WEB_URL_PROP, '') + if type(M.file) == 'table' and M.file.set_url then + M.file:set_url(nil) + end + return nil +end + +local function _get_current_web_url() + local current = trim(tostring(mp.get_property(CURRENT_WEB_URL_PROP) or '')) + if current ~= '' and _is_http_url(current) then + return current + end + return nil +end + +local function _current_url_for_web_actions() + local current = _get_current_web_url() + if current and current ~= '' then + return current + end + local target = _current_target() + if not target or target == '' then + return nil + end + return tostring(target) +end + +local function _sync_current_web_url_from_playback() + local target = _current_target() + local target_str = trim(tostring(target or '')) + if target_str ~= '' and _extract_store_hash(target_str) then + _set_current_web_url(nil) + return + end + if target_str ~= '' and _is_http_url(target_str) and _is_ytdlp_url(target_str) then + _set_current_web_url(target_str) + return + end + + local current = _get_current_web_url() + if current and current ~= '' then + local raw = mp.get_property_native('ytdl-raw-info') + if type(raw) == 'table' then + if type(M.file) == 'table' and M.file.set_url then + M.file:set_url(current) + end + return + end + end + + if target_str == '' or not _is_http_url(target_str) then + _set_current_web_url(nil) + end +end + local function _cache_formats_for_url(url, tbl) if type(url) ~= 'string' or url == '' then return @@ -2000,7 +2081,7 @@ local function _cache_formats_for_url(url, tbl) end end -local function _get_cached_formats_table(url) +_get_cached_formats_table = function(url) if type(url) ~= 'string' or url == '' then return nil end @@ -2111,8 +2192,13 @@ local function _prefetch_formats_for_url(url) if url == '' or not _is_http_url(url) then return end + _set_current_web_url(url) if type(M.file) == 'table' then - M.file.url = url + if M.file.set_url then + M.file:set_url(url) + else + M.file.url = url + end if M.file.fetch_formats then M.file:fetch_formats(nil) end @@ -2307,8 +2393,11 @@ local function _apply_ytdl_format_and_reload(url, fmt) local pos = mp.get_property_number('time-pos') local paused = mp.get_property_native('pause') and true or false - _lua_log('change-format: setting options/ytdl-format=' .. tostring(fmt)) + _lua_log('change-format: setting ytdl format=' .. tostring(fmt)) + _set_current_web_url(url) pcall(mp.set_property, 'options/ytdl-format', tostring(fmt)) + pcall(mp.set_property, 'file-local-options/ytdl-format', tostring(fmt)) + pcall(mp.set_property, 'ytdl-format', tostring(fmt)) if pos and pos > 0 then mp.commandv('loadfile', url, 'replace', 'start=' .. tostring(pos)) @@ -2322,7 +2411,7 @@ local function _apply_ytdl_format_and_reload(url, fmt) end local function _start_download_flow_for_current() - local target = _current_target() + local target = _current_url_for_web_actions() or _current_target() if not target or target == '' then mp.osd_message('No current item', 2) return @@ -2371,7 +2460,7 @@ mp.register_script_message('medios-download-current', function() end) mp.register_script_message('medios-change-format-current', function() - local target = _current_target() + local target = _current_url_for_web_actions() or _current_target() if not target or target == '' then mp.osd_message('No current item', 2) return @@ -2384,15 +2473,22 @@ mp.register_script_message('medios-change-format-current', function() end local url = tostring(target) + _set_current_web_url(url) -- Ensure file state is tracking the current URL. if type(M.file) == 'table' then - M.file.url = url + if M.file.set_url then + M.file:set_url(url) + else + M.file.url = url + end end -- If formats were already prefetched for this URL, open instantly. local cached_tbl = nil - if type(M.file) == 'table' and type(M.file.formats) == 'table' then + if type(M.file) == 'table' + and M.file.url == url + and type(M.file.formats) == 'table' then cached_tbl = M.file.formats else cached_tbl = _get_cached_formats_table(url) @@ -2506,7 +2602,8 @@ end) -- Prefetch formats for yt-dlp-supported URLs on load so Change Format is instant. mp.register_event('file-loaded', function() - local target = _current_target() + _sync_current_web_url_from_playback() + local target = _current_url_for_web_actions() or _current_target() if not target or target == '' then return end @@ -3188,6 +3285,7 @@ mp.register_script_message('medios-load-url-event', function(json) mp.osd_message('Loading URL...', 1) _log_all('INFO', 'Load URL started: ' .. url) _lua_log('[LOAD-URL] Starting to load: ' .. url) + _set_current_web_url(url) local function close_menu() _lua_log('[LOAD-URL] Closing menu') @@ -3199,16 +3297,21 @@ mp.register_script_message('medios-load-url-event', function(json) end end + -- Close the URL prompt immediately once the user submits. Playback may still + -- take time to resolve, but the modal should not stay stuck on screen. + close_menu() + -- First, always try direct loadfile. This is the fastest path. local can_direct = _url_can_direct_load(url) + local prefer_direct = can_direct or _is_ytdlp_url(url) _lua_log('[LOAD-URL] Checking if URL can be loaded directly: ' .. tostring(can_direct)) + _lua_log('[LOAD-URL] Prefer direct load: ' .. tostring(prefer_direct)) - local direct_ok, direct_loaded = _try_direct_loadfile(url, false) + local direct_ok, direct_loaded = _try_direct_loadfile(url, prefer_direct) if direct_ok and direct_loaded then _lua_log('[LOAD-URL] Direct loadfile command sent successfully (forced)') _log_all('INFO', 'Load URL succeeded via direct load') mp.osd_message('URL loaded', 2) - close_menu() return end if direct_ok then @@ -3223,6 +3326,47 @@ mp.register_script_message('medios-load-url-event', function(json) local helper_ready = ensure_pipeline_helper_running() _lua_log('[LOAD-URL] Pipeline helper ready: ' .. tostring(helper_ready)) + local function start_pipeline_load() + -- Use pipeline to download/prepare the URL + local pipeline_cmd = '.mpv -url ' .. quote_pipeline_arg(url) .. ' -play' + _lua_log('[LOAD-URL] Sending to pipeline: ' .. pipeline_cmd) + _lua_log('[LOAD-URL] Pipeline helper ready: ' .. tostring(_is_pipeline_helper_ready())) + + local timeout_timer = nil + timeout_timer = mp.add_timeout(5, function() + if timeout_timer then + mp.osd_message('Still loading... (helper may be resolving URL)', 2) + _log_all('WARN', 'Load URL still processing after 5 seconds') + _lua_log('[LOAD-URL] Timeout message shown (helper still processing)') + end + end) + + M.run_pipeline(pipeline_cmd, nil, function(resp, err) + if timeout_timer then + timeout_timer:kill() + timeout_timer = nil + end + + _lua_log('[LOAD-URL] Pipeline callback received: resp=' .. tostring(resp) .. ', err=' .. tostring(err)) + if err then + _lua_log('[LOAD-URL] Pipeline error: ' .. tostring(err)) + _log_all('ERROR', 'Load URL pipeline failed: ' .. tostring(err)) + mp.osd_message('Load URL failed: ' .. tostring(err), 3) + return + end + _lua_log('[LOAD-URL] URL loaded successfully') + _log_all('INFO', 'Load URL succeeded') + mp.osd_message('URL loaded', 2) + + if _is_ytdlp_url(url) then + _lua_log('[LOAD-URL] URL is yt-dlp compatible, prefetching formats in background') + mp.add_timeout(0.5, function() + _prefetch_formats_for_url(url) + end) + end + end) + end + if not helper_ready then _lua_log('[LOAD-URL] Pipeline helper not available, attempting to start...') _log_all('WARN', 'Pipeline helper not running, attempting auto-start') @@ -3231,62 +3375,19 @@ mp.register_script_message('medios-load-url-event', function(json) -- Attempt to start the helper asynchronously attempt_start_pipeline_helper_async(function(success) if success then - _lua_log('[LOAD-URL] Helper started successfully, retry Load URL from menu') + _lua_log('[LOAD-URL] Helper started successfully, continuing load') _log_all('INFO', 'Pipeline helper started successfully') - mp.osd_message('Helper started! Try Load URL again', 2) + start_pipeline_load() else _lua_log('[LOAD-URL] Failed to start helper') _log_all('ERROR', 'Failed to start pipeline helper') mp.osd_message('Could not start pipeline helper', 3) end - close_menu() end) return end - -- Use pipeline to download/prepare the URL - local pipeline_cmd = '.mpv -url ' .. quote_pipeline_arg(url) .. ' -play' - _lua_log('[LOAD-URL] Sending to pipeline: ' .. pipeline_cmd) - _lua_log('[LOAD-URL] Pipeline helper ready: ' .. tostring(_is_pipeline_helper_ready())) - - -- Add a timeout message after a delay to give user feedback - local timeout_timer = nil - timeout_timer = mp.add_timeout(5, function() - if timeout_timer then - mp.osd_message('Still loading... (helper may be resolving URL)', 2) - _log_all('WARN', 'Load URL still processing after 5 seconds') - _lua_log('[LOAD-URL] Timeout message shown (helper still processing)') - end - end) - - M.run_pipeline(pipeline_cmd, nil, function(resp, err) - if timeout_timer then - timeout_timer:kill() - timeout_timer = nil - end - - _lua_log('[LOAD-URL] Pipeline callback received: resp=' .. tostring(resp) .. ', err=' .. tostring(err)) - if err then - _lua_log('[LOAD-URL] Pipeline error: ' .. tostring(err)) - _log_all('ERROR', 'Load URL pipeline failed: ' .. tostring(err)) - mp.osd_message('Load URL failed: ' .. tostring(err), 3) - close_menu() - return - end - _lua_log('[LOAD-URL] URL loaded successfully') - _log_all('INFO', 'Load URL succeeded') - mp.osd_message('URL loaded', 2) - - -- Prefetch formats for yt-dlp URLs so "Change Format" menu is instant - if _is_ytdlp_url(url) then - _lua_log('[LOAD-URL] URL is yt-dlp compatible, prefetching formats in background') - mp.add_timeout(0.5, function() - _prefetch_formats_for_url(url) - end) - end - - close_menu() - end) + start_pipeline_load() end) -- Menu integration with UOSC diff --git a/cmdnat/pipe.py b/cmdnat/pipe.py index 7c53747..a2a868a 100644 --- a/cmdnat/pipe.py +++ b/cmdnat/pipe.py @@ -1679,8 +1679,6 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int: if save_mode: # Avoid `shell=True` / `date /t` on Windows (can flash a cmd.exe window). # Use Python's datetime instead. - from datetime import datetime - playlist_name = index_arg or f"Playlist {datetime.now().strftime('%Y-%m-%d')}" # If index_arg was used for name, clear it so it doesn't trigger index logic if index_arg: