alldebrid plugin optimization and mpv playlist fix

This commit is contained in:
2026-04-26 13:48:18 -07:00
parent 67c272db4b
commit c724cb36b1
7 changed files with 147 additions and 31 deletions
+3 -3
View File
@@ -375,7 +375,7 @@
"(filespace\\.com/[a-zA-Z0-9]{12})"
],
"regexp": "(filespace\\.com/fd/([a-zA-Z0-9]{12}))|((filespace\\.com/[a-zA-Z0-9]{12}))",
"status": true
"status": false
},
"filezip": {
"name": "filezip",
@@ -463,7 +463,7 @@
"isra\\.cloud/\\?op=report_file&id=([0-9a-zA-Z]{12})"
],
"regexp": "((isra\\.cloud/[0-9a-zA-Z]{12}))|(isra\\.cloud/\\?op=report_file&id=([0-9a-zA-Z]{12}))",
"status": true,
"status": false,
"hardRedirect": [
"isra\\.cloud/([0-9a-zA-Z]{12})"
]
@@ -494,7 +494,7 @@
"mediafire\\.com/(\\?|download/|file/|download\\.php\\?)([0-9a-z]{15})"
],
"regexp": "mediafire\\.com/(\\?|download/|file/|download\\.php\\?)([0-9a-z]{15})",
"status": false
"status": true
},
"mixdrop": {
"name": "mixdrop",
+6 -1
View File
@@ -5683,13 +5683,18 @@ mp.register_event('file-loaded', function()
mp.add_timeout(0.1, function()
M._reset_uosc_input_state('file-loaded-web')
end)
_format_cache_poll_generation = _format_cache_poll_generation + 1
if _extract_store_hash(url) or not _is_ytdlp_url(url) then
return
end
local ok, err = _cache_formats_from_current_playback('file-loaded')
if ok then
_lua_log('formats: file-loaded cache succeeded for url=' .. url)
else
_lua_log('formats: file-loaded cache pending reason=' .. tostring(err or 'unknown'))
end
_format_cache_poll_generation = _format_cache_poll_generation + 1
_schedule_playback_format_cache_poll(url, _format_cache_poll_generation, 1)
_prefetch_formats_for_url(url)
end)
+7 -6
View File
@@ -7,13 +7,14 @@ border=no
cache=yes
# Give HTTP store streams more room to absorb Hydrus/network jitter before
# mpv restarts audio after an underrun.
cache-secs=90
cache-secs=300
cache-pause=yes
cache-pause-wait=12
demuxer-readahead-secs=90
demuxer-max-bytes=512MiB
demuxer-max-back-bytes=256MiB
audio-buffer=1.0
cache-pause-initial=yes
cache-pause-wait=30
demuxer-readahead-secs=300
demuxer-max-bytes=1GiB
demuxer-max-back-bytes=512MiB
audio-buffer=2.0
# Ensure uosc texture/icon fonts are discoverable by libass.
osd-fonts-dir=~~/scripts/uosc/fonts
+29 -15
View File
@@ -1248,11 +1248,15 @@ class AllDebrid(TableProviderMixin, Provider):
log(f"AllDebrid magnet {magnet_id} has no downloadable files", file=sys.stderr)
return 0
try:
if progress is not None and hasattr(progress, "begin_steps"):
progress.begin_steps(total_files)
except Exception:
pass
magnet_path_metadata: Dict[str, Any] = {}
magnet_folder_name = str(
magnet_files.get("filename")
or magnet_files.get("name")
or magnet_files.get("hash")
or f"magnet-{magnet_id}"
).strip()
if magnet_folder_name:
magnet_path_metadata["folder"] = magnet_folder_name
downloaded = 0
for file_idx, node in enumerate(file_entries, 1):
@@ -1261,8 +1265,10 @@ class AllDebrid(TableProviderMixin, Provider):
relpath = str(node.get("_relpath") or file_name or "").strip()
try:
if progress is not None and hasattr(progress, "step"):
progress.step(f"file {file_idx}/{total_files}: {relpath or file_name or 'download'}")
if progress is not None and hasattr(progress, "set_status"):
progress.set_status(
f"downloading file {file_idx}/{total_files}: {relpath or file_name or 'download'}"
)
except Exception:
pass
@@ -1282,21 +1288,23 @@ class AllDebrid(TableProviderMixin, Provider):
except Exception as exc:
debug(f"[alldebrid] unlock_link failed: {exc}, trying locked URL")
target_path = output_dir
rel_path_obj = Path(relpath)
if rel_path_obj.parent:
target_path = output_dir / rel_path_obj.parent
try:
target_path.mkdir(parents=True, exist_ok=True)
except Exception:
target_path = output_dir
target_path = adjust_output_dir_for_alldebrid(
output_dir,
{**magnet_path_metadata, "relpath": relpath},
magnet_files,
)
suggested_name = sanitize_filename(rel_path_obj.name) or sanitize_filename(file_name)
if not suggested_name:
suggested_name = rel_path_obj.name or file_name or f"file-{file_idx}"
try:
result_obj = _download_direct_file(
file_url,
target_path,
quiet=quiet_mode,
suggested_filename=rel_path_obj.name,
suggested_filename=suggested_name,
pipeline_progress=progress,
)
except Exception as exc:
@@ -1315,6 +1323,12 @@ class AllDebrid(TableProviderMixin, Provider):
if downloaded == 0:
log(f"AllDebrid magnet {magnet_id} produced no downloads", file=sys.stderr)
try:
if progress is not None and hasattr(progress, "clear_status"):
progress.clear_status()
except Exception:
pass
return downloaded
def search(
+80 -3
View File
@@ -6,6 +6,7 @@ import json
import sqlite3
import time
import os
import re
import datetime
import sys
import tempfile
@@ -30,6 +31,7 @@ _LAST_SAVED_CONFIG: Dict[str, Any] = {}
_CONFIG_SAVE_MAX_RETRIES = 5
_CONFIG_SAVE_RETRY_DELAY = 0.15
_CONFIG_MISSING = object()
_PATH_ALIAS_TOKEN_RE = re.compile(r"^\$(?:\((?P<braced>[^)]+)\)|(?P<plain>[A-Za-z0-9_.-]+))$")
class ConfigSaveConflict(Exception):
@@ -62,6 +64,20 @@ def global_config() -> List[Dict[str, Any]]:
"group": "Display",
"default": "rainbow",
"choices": ["plain", "bw-striped", "rainbow"],
},
{
"key": "download_path_default",
"label": "Default Download Path",
"group": "Downloads",
"type": "string",
"default": "",
},
{
"key": "path_aliases",
"label": "Path Aliases",
"group": "Downloads",
"type": "json",
"default": {},
}
]
@@ -82,6 +98,56 @@ def get_nested_config_value(config: Dict[str, Any], *path: str) -> Any:
return cur
def _normalize_path_alias_name(value: Any) -> Optional[str]:
raw = str(value or "").strip()
if not raw:
return None
match = _PATH_ALIAS_TOKEN_RE.match(raw)
if match:
raw = str(match.group("braced") or match.group("plain") or "").strip()
candidate = raw.strip().strip("()")
if not candidate:
return None
return candidate.lower()
def get_path_aliases(config: Dict[str, Any]) -> Dict[str, str]:
aliases: Dict[str, str] = {}
if not isinstance(config, dict):
return aliases
for block_name in ("path_aliases", "download_paths"):
block = config.get(block_name)
if not isinstance(block, dict):
continue
for key, value in block.items():
alias = _normalize_path_alias_name(key)
if not alias:
continue
if isinstance(value, str) and value.strip():
aliases[alias] = value.strip()
return aliases
def resolve_path_alias(config: Dict[str, Any], value: Any) -> Optional[Path]:
raw = str(value or "").strip()
if not raw.startswith("$"):
return None
alias = _normalize_path_alias_name(raw)
if not alias:
return None
target = get_path_aliases(config).get(alias)
if not target:
return None
return expand_path(target)
def coerce_config_value(
value: Any,
existing_value: Any = _CONFIG_MISSING,
@@ -271,13 +337,24 @@ def resolve_output_dir(config: Dict[str, Any]) -> Path:
"""Resolve output directory from config with single source of truth.
Priority:
1. config["temp"] - explicitly set temp/output directory
2. config["outfile"] - fallback to outfile setting
3. System Temp - default fallback directory
1. config["download_path_default"] - default download/output directory
2. config["temp"] - explicitly set temp/output directory
3. config["outfile"] - fallback to outfile setting
4. System Temp - default fallback directory
Returns:
Path to output directory
"""
default_output = config.get("download_path_default")
if default_output:
try:
aliased = resolve_path_alias(config, default_output)
path = aliased if aliased is not None else expand_path(default_output)
if path.exists() or path.parent.exists():
return path
except Exception as exc:
logger.debug("resolve_output_dir: failed to expand download_path_default value %r: %s", default_output, exc, exc_info=True)
# First try explicit temp setting from config
temp_value = config.get("temp")
if temp_value:
+13 -1
View File
@@ -804,7 +804,19 @@ def resolve_target_dir(
target = parsed.get("path")
if target:
try:
p = Path(str(target)).expanduser().resolve()
from SYS.config import resolve_path_alias
from SYS.utils import expand_path
raw_target = str(target or "").strip()
aliased = resolve_path_alias(config, raw_target)
if raw_target.startswith("$") and aliased is None:
log(
f"Unknown path alias {raw_target}. Set it with .config path_aliases.<name> <path>",
file=sys.stderr,
)
return None
p = aliased if aliased is not None else expand_path(raw_target)
if handle_creations:
p.mkdir(parents=True, exist_ok=True)
return p
+9 -2
View File
@@ -1454,6 +1454,13 @@ def _queue_items(
except Exception:
pass
# Batched queue operations should not block on one IPC reply per item.
# On Windows named pipes, waiting for every `loadfile`/`loadlist` ack can
# make multi-select `.mpv` calls stall for several seconds.
command_wait = bool(wait)
if len(items) > 1:
command_wait = False
# Just verify cookies are configured, don't try to set via IPC
_ensure_ytdl_cookies(config)
@@ -1683,8 +1690,8 @@ def _queue_items(
"request_id": 200
}
try:
debug(f"Sending MPV {command_name}: {target_to_send} mode={mode} wait={wait}")
resp = _send_ipc_command(cmd, silent=True, wait=wait)
debug(f"Sending MPV {command_name}: {target_to_send} mode={mode} wait={command_wait}")
resp = _send_ipc_command(cmd, silent=True, wait=command_wait)
debug(f"MPV {command_name} response: {resp}")
except Exception as e:
debug(f"Exception sending {command_name} to MPV: {e}", file=sys.stderr)