kl
This commit is contained in:
246
MPV/LUA/main.lua
246
MPV/LUA/main.lua
@@ -1876,6 +1876,212 @@ local function _download_url_for_current_item(url)
|
||||
return base, true
|
||||
end
|
||||
|
||||
function M._extract_youtube_video_id(url)
|
||||
url = trim(tostring(url or ''))
|
||||
if url == '' then
|
||||
return nil
|
||||
end
|
||||
|
||||
local lower = url:lower()
|
||||
local video_id = nil
|
||||
if lower:match('youtu%.be/') then
|
||||
video_id = url:match('youtu%.be/([^%?&#/]+)')
|
||||
elseif lower:match('youtube%.com/watch') or lower:match('youtube%-nocookie%.com/watch') then
|
||||
video_id = _extract_query_param(url, 'v')
|
||||
elseif lower:match('youtube%.com/shorts/') or lower:match('youtube%-nocookie%.com/shorts/') then
|
||||
video_id = url:match('/shorts/([^%?&#/]+)')
|
||||
elseif lower:match('youtube%.com/live/') or lower:match('youtube%-nocookie%.com/live/') then
|
||||
video_id = url:match('/live/([^%?&#/]+)')
|
||||
elseif lower:match('youtube%.com/embed/') or lower:match('youtube%-nocookie%.com/embed/') then
|
||||
video_id = url:match('/embed/([^%?&#/]+)')
|
||||
end
|
||||
|
||||
video_id = trim(tostring(video_id or ''))
|
||||
if video_id == '' or not video_id:match('^[%w_-]+$') then
|
||||
return nil
|
||||
end
|
||||
return video_id
|
||||
end
|
||||
|
||||
function M._suspicious_ytdl_format_reason(fmt, url, raw)
|
||||
fmt = trim(tostring(fmt or ''))
|
||||
url = trim(tostring(url or ''))
|
||||
if fmt == '' then
|
||||
return nil
|
||||
end
|
||||
|
||||
local lower_fmt = fmt:lower()
|
||||
if lower_fmt:match('^https?://') or lower_fmt:match('^rtmp') or (url ~= '' and fmt == url) then
|
||||
return 'format string is a url'
|
||||
end
|
||||
|
||||
local youtube_id = M._extract_youtube_video_id(url)
|
||||
if youtube_id and fmt == youtube_id then
|
||||
return 'format matches current youtube video id'
|
||||
end
|
||||
|
||||
if type(raw) == 'table' and youtube_id then
|
||||
local raw_id = trim(tostring(raw.id or ''))
|
||||
if raw_id ~= '' and raw_id == youtube_id and fmt == raw_id then
|
||||
return 'format matches raw youtube video id'
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function M._clear_suspicious_ytdl_format_for_url(url, reason)
|
||||
url = trim(tostring(url or ''))
|
||||
if url == '' then
|
||||
return false
|
||||
end
|
||||
|
||||
local raw = mp.get_property_native('ytdl-raw-info')
|
||||
local bad_props = {}
|
||||
local bad_value = nil
|
||||
local bad_reason = nil
|
||||
local checks = {
|
||||
{
|
||||
prop = 'ytdl-format',
|
||||
value = mp.get_property_native('ytdl-format'),
|
||||
},
|
||||
{
|
||||
prop = 'file-local-options/ytdl-format',
|
||||
value = mp.get_property('file-local-options/ytdl-format'),
|
||||
},
|
||||
{
|
||||
prop = 'options/ytdl-format',
|
||||
value = mp.get_property('options/ytdl-format'),
|
||||
},
|
||||
}
|
||||
|
||||
for _, item in ipairs(checks) do
|
||||
local candidate = trim(tostring(item.value or ''))
|
||||
local why = M._suspicious_ytdl_format_reason(candidate, url, raw)
|
||||
if why then
|
||||
if not bad_value then
|
||||
bad_value = candidate
|
||||
end
|
||||
if not bad_reason then
|
||||
bad_reason = why
|
||||
end
|
||||
bad_props[#bad_props + 1] = tostring(item.prop)
|
||||
end
|
||||
end
|
||||
|
||||
if #bad_props == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
pcall(mp.set_property, 'options/ytdl-format', '')
|
||||
pcall(mp.set_property, 'file-local-options/ytdl-format', '')
|
||||
pcall(mp.set_property, 'ytdl-format', '')
|
||||
_lua_log(
|
||||
'ytdl-format: cleared suspicious selector=' .. tostring(bad_value or '')
|
||||
.. ' props=' .. table.concat(bad_props, ',')
|
||||
.. ' reason=' .. tostring(bad_reason or reason or 'invalid')
|
||||
.. ' url=' .. tostring(url)
|
||||
)
|
||||
return true
|
||||
end
|
||||
|
||||
function M._prepare_ytdl_format_for_web_load(url, reason)
|
||||
url = trim(tostring(url or ''))
|
||||
if url == '' then
|
||||
return false
|
||||
end
|
||||
|
||||
if M._clear_suspicious_ytdl_format_for_url(url, reason) then
|
||||
return true
|
||||
end
|
||||
|
||||
local normalized_url = url:gsub('#.*$', '')
|
||||
local base, query = normalized_url:match('^([^?]+)%?(.*)$')
|
||||
if base then
|
||||
local kept = {}
|
||||
for pair in query:gmatch('[^&]+') do
|
||||
local raw_key = pair:match('^([^=]+)') or pair
|
||||
local key = tostring(_percent_decode(raw_key) or raw_key or ''):lower()
|
||||
local keep = true
|
||||
if key == 't' or key == 'start' or key == 'time_continue' or key == 'timestamp' or key == 'time' or key == 'begin' then
|
||||
keep = false
|
||||
elseif key:match('^utm_') then
|
||||
keep = false
|
||||
end
|
||||
if keep then
|
||||
kept[#kept + 1] = pair
|
||||
end
|
||||
end
|
||||
if #kept > 0 then
|
||||
normalized_url = base .. '?' .. table.concat(kept, '&')
|
||||
else
|
||||
normalized_url = base
|
||||
end
|
||||
end
|
||||
local explicit_reload_url = normalized_url
|
||||
explicit_reload_url = explicit_reload_url:gsub('^[%a][%w+%.%-]*://', '')
|
||||
explicit_reload_url = explicit_reload_url:gsub('^www%.', '')
|
||||
explicit_reload_url = explicit_reload_url:gsub('/+$', '')
|
||||
explicit_reload_url = explicit_reload_url:lower()
|
||||
|
||||
local is_explicit_reload = (
|
||||
explicit_reload_url ~= ''
|
||||
and _skip_next_store_check_url ~= ''
|
||||
and explicit_reload_url == _skip_next_store_check_url
|
||||
)
|
||||
|
||||
local active_props = {}
|
||||
local first_value = nil
|
||||
local checks = {
|
||||
{
|
||||
prop = 'ytdl-format',
|
||||
value = mp.get_property_native('ytdl-format'),
|
||||
},
|
||||
{
|
||||
prop = 'file-local-options/ytdl-format',
|
||||
value = mp.get_property('file-local-options/ytdl-format'),
|
||||
},
|
||||
{
|
||||
prop = 'options/ytdl-format',
|
||||
value = mp.get_property('options/ytdl-format'),
|
||||
},
|
||||
}
|
||||
|
||||
for _, item in ipairs(checks) do
|
||||
local candidate = trim(tostring(item.value or ''))
|
||||
if candidate ~= '' then
|
||||
if not first_value then
|
||||
first_value = candidate
|
||||
end
|
||||
active_props[#active_props + 1] = tostring(item.prop) .. '=' .. candidate
|
||||
end
|
||||
end
|
||||
|
||||
if #active_props == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
if is_explicit_reload then
|
||||
_lua_log(
|
||||
'ytdl-format: preserving explicit reload selector reason=' .. tostring(reason or 'on-load')
|
||||
.. ' url=' .. tostring(url)
|
||||
.. ' values=' .. table.concat(active_props, '; ')
|
||||
)
|
||||
return false
|
||||
end
|
||||
|
||||
pcall(mp.set_property, 'options/ytdl-format', '')
|
||||
pcall(mp.set_property, 'file-local-options/ytdl-format', '')
|
||||
pcall(mp.set_property, 'ytdl-format', '')
|
||||
_lua_log(
|
||||
'ytdl-format: cleared stale selector=' .. tostring(first_value or '')
|
||||
.. ' reason=' .. tostring(reason or 'on-load')
|
||||
.. ' url=' .. tostring(url)
|
||||
.. ' values=' .. table.concat(active_props, '; ')
|
||||
)
|
||||
return true
|
||||
end
|
||||
|
||||
local function _normalize_url_for_store_lookup(url)
|
||||
url = trim(tostring(url or ''))
|
||||
if url == '' then
|
||||
@@ -3742,6 +3948,8 @@ function M._apply_web_subtitle_load_defaults(reason)
|
||||
return false
|
||||
end
|
||||
|
||||
M._prepare_ytdl_format_for_web_load(target, reason or 'on-load')
|
||||
|
||||
local raw = M._build_web_ytdl_raw_options()
|
||||
if raw and raw ~= '' then
|
||||
pcall(mp.set_property, 'file-local-options/ytdl-raw-options', raw)
|
||||
@@ -4664,22 +4872,35 @@ _show_format_list_osd = function(items, max_items)
|
||||
end
|
||||
|
||||
local function _current_ytdl_format_string()
|
||||
local url = _current_url_for_web_actions() or _current_target() or ''
|
||||
local raw = mp.get_property_native('ytdl-raw-info')
|
||||
|
||||
-- Preferred: mpv exposes the active ytdl format string.
|
||||
local fmt = trim(tostring(mp.get_property_native('ytdl-format') or ''))
|
||||
if fmt ~= '' then
|
||||
local suspicious_reason = M._suspicious_ytdl_format_reason(fmt, url, raw)
|
||||
if fmt ~= '' and not suspicious_reason then
|
||||
return fmt
|
||||
elseif fmt ~= '' then
|
||||
_lua_log('ytdl-format: ignoring suspicious current format source=ytdl-format value=' .. tostring(fmt) .. ' reason=' .. tostring(suspicious_reason))
|
||||
end
|
||||
|
||||
-- Fallbacks: option value, or raw info if available.
|
||||
local opt = trim(tostring(mp.get_property('options/ytdl-format') or ''))
|
||||
if opt ~= '' then
|
||||
suspicious_reason = M._suspicious_ytdl_format_reason(opt, url, raw)
|
||||
if opt ~= '' and not suspicious_reason then
|
||||
return opt
|
||||
elseif opt ~= '' then
|
||||
_lua_log('ytdl-format: ignoring suspicious current format source=options/ytdl-format value=' .. tostring(opt) .. ' reason=' .. tostring(suspicious_reason))
|
||||
end
|
||||
|
||||
local raw = mp.get_property_native('ytdl-raw-info')
|
||||
if type(raw) == 'table' then
|
||||
if raw.format_id and tostring(raw.format_id) ~= '' then
|
||||
return tostring(raw.format_id)
|
||||
local raw_format_id = tostring(raw.format_id)
|
||||
suspicious_reason = M._suspicious_ytdl_format_reason(raw_format_id, url, raw)
|
||||
if not suspicious_reason then
|
||||
return raw_format_id
|
||||
end
|
||||
_lua_log('ytdl-format: ignoring suspicious current format source=ytdl-raw-info.format_id value=' .. tostring(raw_format_id) .. ' reason=' .. tostring(suspicious_reason))
|
||||
end
|
||||
local rf = raw.requested_formats
|
||||
if type(rf) == 'table' then
|
||||
@@ -4690,7 +4911,12 @@ local function _current_ytdl_format_string()
|
||||
end
|
||||
end
|
||||
if #parts >= 1 then
|
||||
return table.concat(parts, '+')
|
||||
local joined = table.concat(parts, '+')
|
||||
suspicious_reason = M._suspicious_ytdl_format_reason(joined, url, raw)
|
||||
if not suspicious_reason then
|
||||
return joined
|
||||
end
|
||||
_lua_log('ytdl-format: ignoring suspicious current format source=ytdl-raw-info.requested_formats value=' .. tostring(joined) .. ' reason=' .. tostring(suspicious_reason))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4957,6 +5183,16 @@ local function _apply_ytdl_format_and_reload(url, fmt)
|
||||
return
|
||||
end
|
||||
|
||||
local suspicious_reason = M._suspicious_ytdl_format_reason(fmt, url, mp.get_property_native('ytdl-raw-info'))
|
||||
if suspicious_reason then
|
||||
pcall(mp.set_property, 'options/ytdl-format', '')
|
||||
pcall(mp.set_property, 'file-local-options/ytdl-format', '')
|
||||
pcall(mp.set_property, 'ytdl-format', '')
|
||||
_lua_log('change-format: rejected suspicious format=' .. tostring(fmt) .. ' reason=' .. tostring(suspicious_reason) .. ' url=' .. tostring(url))
|
||||
mp.osd_message('Invalid format selection', 3)
|
||||
return
|
||||
end
|
||||
|
||||
local pos = mp.get_property_number('time-pos')
|
||||
local paused = mp.get_property_native('pause') and true or false
|
||||
local media_title = trim(tostring(mp.get_property('media-title') or ''))
|
||||
|
||||
@@ -1831,8 +1831,7 @@ def main(argv: Optional[list[str]] = None) -> int:
|
||||
try:
|
||||
if target_client.sock is None:
|
||||
if use_shared_ipc_client:
|
||||
if note_ipc_unavailable is not None:
|
||||
note_ipc_unavailable(f"helper-command-connect:{label or '?'}")
|
||||
_note_ipc_unavailable(f"helper-command-connect:{label or '?'}")
|
||||
return False
|
||||
if not target_client.connect():
|
||||
_append_helper_log(
|
||||
|
||||
Reference in New Issue
Block a user