update
This commit is contained in:
+175
-5
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user