alldebrid plugin optimization and mpv playlist fix
This commit is contained in:
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user