[dl:ytdl] improve error detection

- intercept ytdl logging messages and signal error when it
  emits an error message
- remove "ERROR:" etc from ytdl logging messages
This commit is contained in:
Mike Fährmann
2025-12-12 15:59:18 +01:00
parent 05817c523f
commit b891c0301e

View File

@@ -42,6 +42,7 @@ class YoutubeDLDownloader(DownloaderBase):
if ytdl_instance := kwdict.pop("_ytdl_instance", None):
# 'ytdl' extractor
self._prepare(ytdl_instance)
info_dict = kwdict.pop("_ytdl_info_dict")
else:
# other extractors
@@ -69,6 +70,7 @@ class YoutubeDLDownloader(DownloaderBase):
module, self, self.ytdl_opts)
if self.outtmpl == "default":
self.outtmpl = module.DEFAULT_OUTTMPL
self._prepare(ytdl_instance)
if self.forward_cookies:
self.log.debug("Forwarding cookies to %s",
@@ -80,8 +82,10 @@ class YoutubeDLDownloader(DownloaderBase):
tries = 0
url = url[5:]
manifest = kwdict.get("_ytdl_manifest")
while True:
tries += 1
self.error = None
try:
if manifest is None:
info_dict = self._extract_url(
@@ -89,45 +93,63 @@ class YoutubeDLDownloader(DownloaderBase):
else:
info_dict = self._extract_manifest(
ytdl_instance, url, kwdict)
if info_dict:
break
except Exception as exc:
self.log.traceback(exc)
self.log.error("%s: %s (%s/%s)",
exc.__class__.__name__, exc,
tries, self.retries+1)
cls = exc.__class__
if cls.__module__ == "builtins":
tries = False
msg = f"{cls.__name__}: {exc}"
else:
self.log.error("Empty 'info_dict' data (%s/%s)",
tries, self.retries+1)
if self.error is not None:
msg = self.error
elif not info_dict:
msg = "Empty 'info_dict' data"
else:
break
if tries:
self.log.error("%s (%s/%s)", msg, tries, self.retries+1)
else:
self.log.error(msg)
return False
if tries > self.retries:
return False
if "__gdl_initialize" in ytdl_instance.params:
del ytdl_instance.params["__gdl_initialize"]
if self.progress is not None:
ytdl_instance.add_progress_hook(self._progress_hook)
if rlf := ytdl_instance.params.pop("__gdl_ratelimit_func", False):
self.rate_dyn = rlf
if extra := kwdict.get("_ytdl_extra"):
info_dict.update(extra)
while True:
tries += 1
self.error = None
try:
if "entries" in info_dict:
return self._download_playlist(
success = self._download_playlist(
ytdl_instance, pathfmt, info_dict)
else:
success = self._download_video(
ytdl_instance, pathfmt, info_dict)
return self._download_video(
ytdl_instance, pathfmt, info_dict)
except Exception as exc:
tries += 1
self.log.traceback(exc)
self.log.error("%s: %s (%s/%s)",
exc.__class__.__name__, exc,
tries, self.retries+1)
if tries > self.retries:
return False
cls = exc.__class__
if cls.__module__ == "builtins":
tries = False
msg = f"{cls.__name__}: {exc}"
else:
if self.error is not None:
msg = self.error
elif not success:
msg = "Error"
else:
break
if tries:
self.log.error("%s (%s/%s)", msg, tries, self.retries+1)
else:
self.log.error(msg)
return False
if tries > self.retries:
return False
return True
def _extract_url(self, ytdl, url):
return ytdl.extract_info(url, download=False)
@@ -281,6 +303,17 @@ class YoutubeDLDownloader(DownloaderBase):
self.log.error("%s: %s", exc.__class__.__name__, exc)
return status
def _prepare(self, ytdl_instance):
if "__gdl_initialize" not in ytdl_instance.params:
return
del ytdl_instance.params["__gdl_initialize"]
if self.progress is not None:
ytdl_instance.add_progress_hook(self._progress_hook)
if rlf := ytdl_instance.params.pop("__gdl_ratelimit_func", False):
self.rate_dyn = rlf
ytdl_instance.params["logger"] = LoggerAdapter(self, ytdl_instance)
def _progress_hook(self, info):
if info["status"] == "downloading" and \
info["elapsed"] >= self.progress:
@@ -304,6 +337,31 @@ class YoutubeDLDownloader(DownloaderBase):
ytdl_instance.params["outtmpl"] = {"default": outtmpl}
class LoggerAdapter():
__slots__ = ("obj", "log")
def __init__(self, obj, ytdl_instance):
self.obj = obj
self.log = ytdl_instance.params.get("logger")
def debug(self, msg):
if self.log is not None:
if msg[0] == "[":
msg = msg[msg.find("]")+2:]
self.log.debug(msg)
def warning(self, msg):
if self.log is not None:
if "WARNING:" in msg:
msg = msg[msg.find(" ")+1:]
self.log.warning(msg)
def error(self, msg):
if "ERROR:" in msg:
msg = msg[msg.find(" ")+1:]
self.obj.error = msg
def compatible_formats(formats):
"""Returns True if 'formats' are compatible for merge"""
video_ext = formats[0].get("ext")