aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'yt_dlp/utils.py')
-rw-r--r--yt_dlp/utils.py48
1 files changed, 29 insertions, 19 deletions
diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py
index 62a1800d4..6663583fc 100644
--- a/yt_dlp/utils.py
+++ b/yt_dlp/utils.py
@@ -1040,7 +1040,7 @@ def make_HTTPS_handler(params, **kwargs):
def bug_reports_message(before=';'):
- msg = ('please report this issue on https://github.com/yt-dlp/yt-dlp , '
+ msg = ('please report this issue on https://github.com/yt-dlp/yt-dlp/issues?q= , '
'filling out the appropriate issue template. '
'Confirm you are on the latest version using yt-dlp -U')
@@ -2418,11 +2418,14 @@ def parse_count(s):
return str_to_int(mobj.group(1))
-def parse_resolution(s):
+def parse_resolution(s, *, lenient=False):
if s is None:
return {}
- mobj = re.search(r'(?<![a-zA-Z0-9])(?P<w>\d+)\s*[xX×,]\s*(?P<h>\d+)(?![a-zA-Z0-9])', s)
+ if lenient:
+ mobj = re.search(r'(?P<w>\d+)\s*[xX×,]\s*(?P<h>\d+)', s)
+ else:
+ mobj = re.search(r'(?<![a-zA-Z0-9])(?P<w>\d+)\s*[xX×,]\s*(?P<h>\d+)(?![a-zA-Z0-9])', s)
if mobj:
return {
'width': int(mobj.group('w')),
@@ -2880,6 +2883,7 @@ class PagedList:
class OnDemandPagedList(PagedList):
+ """Download pages until a page with less than maximum results"""
def _getslice(self, start, end):
for pagenum in itertools.count(start // self._pagesize):
firstid = pagenum * self._pagesize
@@ -2919,6 +2923,7 @@ class OnDemandPagedList(PagedList):
class InAdvancePagedList(PagedList):
+ """PagedList with total number of pages known in advance"""
def __init__(self, pagefunc, pagecount, pagesize):
PagedList.__init__(self, pagefunc, pagesize, True)
self._pagecount = pagecount
@@ -3087,24 +3092,25 @@ def multipart_encode(data, boundary=None):
def dict_get(d, key_or_keys, default=None, skip_false_values=True):
- if isinstance(key_or_keys, (list, tuple)):
- for key in key_or_keys:
- if key not in d or d[key] is None or skip_false_values and not d[key]:
- continue
- return d[key]
- return default
- return d.get(key_or_keys, default)
+ for val in map(d.get, variadic(key_or_keys)):
+ if val is not None and (val or not skip_false_values):
+ return val
+ return default
-def try_get(src, getter, expected_type=None):
- for get in variadic(getter):
+def try_call(*funcs, expected_type=None, args=[], kwargs={}):
+ for f in funcs:
try:
- v = get(src)
- except (AttributeError, KeyError, TypeError, IndexError):
+ val = f(*args, **kwargs)
+ except (AttributeError, KeyError, TypeError, IndexError, ZeroDivisionError):
pass
else:
- if expected_type is None or isinstance(v, expected_type):
- return v
+ if expected_type is None or isinstance(val, expected_type):
+ return val
+
+
+def try_get(src, getter, expected_type=None):
+ return try_call(*variadic(getter), args=(src,), expected_type=expected_type)
def filter_dict(dct, cndn=lambda _, v: v is not None):
@@ -3317,6 +3323,10 @@ def error_to_compat_str(err):
return err_str
+def error_to_str(err):
+ return f'{type(err).__name__}: {err}'
+
+
def mimetype2ext(mt):
if mt is None:
return None
@@ -5148,8 +5158,8 @@ def traverse_obj(
@param path_list A list of paths which are checked one by one.
Each path is a list of keys where each key is a string,
a function, a tuple of strings/None or "...".
- When a fuction is given, it takes the key as argument and
- returns whether the key matches or not. When a tuple is given,
+ When a fuction is given, it takes the key and value as arguments
+ and returns whether the key matches or not. When a tuple is given,
all the keys given in the tuple are traversed, and
"..." traverses all the keys in the object
"None" returns the object without traversal
@@ -5194,7 +5204,7 @@ def traverse_obj(
obj = str(obj)
_current_depth += 1
depth = max(depth, _current_depth)
- return [_traverse_obj(v, path[i + 1:], _current_depth) for k, v in obj if key(k)]
+ return [_traverse_obj(v, path[i + 1:], _current_depth) for k, v in obj if try_call(key, args=(k, v))]
elif isinstance(obj, dict) and not (is_user_input and key == ':'):
obj = (obj.get(key) if casesense or (key in obj)
else next((v for k, v in obj.items() if _lower(k) == key), None))