This commit is contained in:
2026-05-16 15:03:33 -07:00
parent 717cb13dda
commit 5048729b0c
10 changed files with 1646 additions and 241 deletions
+2
View File
@@ -6535,6 +6535,7 @@ mp.register_script_message('medios-load-url-event', function(json)
if not M._reset_uosc_input_state('load-url-submit') then
_lua_log('[LOAD-URL] UOSC not loaded, cannot close menu')
end
M._schedule_uosc_cursor_resync('load-url-submit')
end
-- Close the URL prompt immediately once the user submits. Playback may still
@@ -6602,6 +6603,7 @@ mp.register_script_message('medios-load-url-event', function(json)
_lua_log('[LOAD-URL] URL is yt-dlp compatible, prefetching formats in background')
mp.add_timeout(0.5, function()
_prefetch_formats_for_url(url)
M._schedule_uosc_cursor_resync('file-loaded-web')
end)
end
end)
+175 -5
View File
@@ -895,7 +895,7 @@ def _get_playlist(silent: bool = False) -> Optional[List[Dict[str, Any]]]:
def _extract_title_from_item(item: Dict[str, Any]) -> str:
"""Extract a clean title from an MPV playlist item, handling memory:// M3U hacks."""
title = item.get("title")
filename = item.get("filename") or ""
filename = item.get("filename") or item.get("playlist-path") or ""
# Special handling for memory:// M3U playlists (used to pass titles via IPC)
if "memory://" in filename and "#EXTINF:" in filename:
@@ -923,6 +923,163 @@ def _extract_title_from_item(item: Dict[str, Any]) -> str:
return title or filename or "Unknown"
def _looks_like_raw_playlist_title(
title: Optional[str],
target: Optional[str],
) -> bool:
text = str(title or "").strip()
if not text or text == "Unknown":
return True
target_text = str(target or "").strip()
if target_text and text == target_text:
return True
lower = text.lower()
if lower.startswith(("http://", "https://", "hydrus://", "file://", "memory://")):
return True
if _WINDOWS_PATH_RE.match(text) or text.startswith("\\\\"):
return True
return False
def _resolve_hydrus_playlist_title(
target: str,
*,
store_name: Optional[str],
file_hash: Optional[str],
config: Optional[Dict[str, Any]],
) -> Optional[str]:
raw_target = str(target or "").strip()
if not raw_target:
return None
resolved_store = str(store_name or "").strip() or None
resolved_hash = str(file_hash or "").strip().lower() or None
looks_hydrus = bool(resolved_store) or bool(
_SHA256_FULL_RE.fullmatch(raw_target.lower())
) or raw_target.lower().startswith("hydrus://") or _is_hydrus_path(raw_target, None)
if not looks_hydrus:
return None
try:
hydrus_plugin = get_plugin("hydrusnetwork", config or {})
except Exception:
hydrus_plugin = None
if hydrus_plugin is None:
return None
try:
parsed_store, parsed_hash = hydrus_plugin.parse_hydrus_url(raw_target)
except Exception:
parsed_store, parsed_hash = None, ""
if not resolved_store and parsed_store:
resolved_store = str(parsed_store).strip() or None
if not resolved_hash and parsed_hash:
resolved_hash = str(parsed_hash).strip().lower() or None
if not resolved_store:
try:
inferred_store = hydrus_plugin.infer_playlist_store(
None,
target=raw_target,
file_storage=None,
)
except Exception:
inferred_store = None
if inferred_store:
resolved_store = str(inferred_store).strip() or None
if not resolved_hash:
try:
hashes = hydrus_plugin.find_hashes_by_url(
raw_target,
store_name=resolved_store,
)
except TypeError:
try:
hashes = hydrus_plugin.find_hashes_by_url(raw_target)
except Exception:
hashes = []
except Exception:
hashes = []
if isinstance(hashes, list) and hashes:
resolved_hash = str(hashes[0] or "").strip().lower() or None
if not resolved_hash:
return None
try:
resolved_title = hydrus_plugin.get_title(
resolved_hash,
store_name=resolved_store,
)
except Exception:
resolved_title = ""
title_text = str(resolved_title or "").strip()
if not title_text:
return None
if title_text.lower() in {resolved_hash, resolved_hash[:16] + "..."}:
return None
return title_text
def _resolve_playlist_display_title(
item: Dict[str, Any],
*,
config: Optional[Dict[str, Any]] = None,
file_storage: Optional[Any] = None,
store_name: Optional[str] = None,
file_hash: Optional[str] = None,
title_cache: Optional[Dict[tuple[str, str, str], Optional[str]]] = None,
) -> str:
title = _extract_title_from_item(item)
filename = item.get("filename") or item.get("playlist-path") or ""
real_path = _extract_target_from_memory_uri(filename) or filename
if not _looks_like_raw_playlist_title(title, real_path):
return title
resolved_store = str(store_name or "").strip() or None
resolved_hash = str(file_hash or "").strip().lower() or None
if not resolved_store or not resolved_hash:
extracted_store, extracted_hash = _extract_store_and_hash(
{
"store": resolved_store,
"hash": resolved_hash,
"path": real_path,
"filename": filename,
"title": title,
},
config=config,
)
if not resolved_store and extracted_store:
resolved_store = str(extracted_store).strip() or None
if not resolved_hash and extracted_hash:
resolved_hash = str(extracted_hash).strip().lower() or None
cache_key = (
str(real_path or "").strip().lower(),
str(resolved_store or "").strip().lower(),
str(resolved_hash or "").strip().lower(),
)
if title_cache is not None and cache_key in title_cache:
cached_title = title_cache[cache_key]
return cached_title or title
resolved_title = _resolve_hydrus_playlist_title(
real_path,
store_name=resolved_store,
file_hash=resolved_hash,
config=config,
)
if title_cache is not None:
title_cache[cache_key] = resolved_title
return resolved_title or title
def _extract_target_from_memory_uri(text: str) -> Optional[str]:
"""Extract the real target URL/path from a memory:// M3U payload."""
if not isinstance(text, str) or not text.startswith("memory://"):
@@ -1927,7 +2084,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
return 1
# Build result object with file info
title = _extract_title_from_item(current_item)
title = _resolve_playlist_display_title(current_item, config=config)
filename = current_item.get("filename", "")
# Emit the current item to pipeline
@@ -2340,7 +2497,11 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
return 1
item = items[idx]
title = _extract_title_from_item(item)
title = _resolve_playlist_display_title(
item,
config=config,
file_storage=file_storage,
)
filename = item.get("filename", "") if isinstance(item, dict) else ""
hydrus_header = _build_hydrus_header(config or {})
hydrus_url = None
@@ -2446,9 +2607,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
# Convert MPV items to PipeObjects with proper hash and store
pipe_objects = []
title_cache: Dict[tuple[str, str, str], Optional[str]] = {}
for i, item in enumerate(items):
is_current = item.get("current", False)
title = _extract_title_from_item(item)
filename = item.get("filename", "")
# Extract the real path/URL from memory:// wrapper if present
@@ -2458,7 +2619,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
store_name, file_hash = _extract_store_and_hash(
{
"path": real_path,
"title": title,
"filename": filename,
},
config=config,
)
@@ -2480,6 +2641,15 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
config=config,
)
title = _resolve_playlist_display_title(
item,
config=config,
file_storage=file_storage,
store_name=store_name,
file_hash=file_hash,
title_cache=title_cache,
)
# Build PipeObject with proper metadata
pipe_obj = PipeObject(
hash=file_hash or "unknown",