From 06d489c5228d33e673c3f9c9551ae105b5973ce7 Mon Sep 17 00:00:00 2001 From: df Date: Sun, 22 Aug 2021 02:57:02 +0100 Subject: [PATCH 01/18] [utils] Small fixes to utils and compat and test --- test/test_compat.py | 6 +++++- test/test_utils.py | 4 ++-- youtube_dl/compat.py | 9 ++++++--- youtube_dl/utils.py | 10 +++++++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/test/test_compat.py b/test/test_compat.py index b83c8cb41..7606d022f 100644 --- a/test/test_compat.py +++ b/test/test_compat.py @@ -41,8 +41,12 @@ class TestCompat(unittest.TestCase): self.assertEqual(compat_getenv(test_var), test_str) def test_compat_expanduser(self): + from youtube_dl.compat import compat_os_name old_home = os.environ.get('HOME') - test_str = r'C:\Documents and Settings\тест\Application Data' + if compat_os_name in ('nt', 'ce'): + test_str = r'C:\Documents and Settings\тест\Application Data' + else: + test_str = '/home/тест' compat_setenv('HOME', test_str) self.assertEqual(compat_expanduser('~'), test_str) compat_setenv('HOME', old_home or '') diff --git a/test/test_utils.py b/test/test_utils.py index ca36909a8..870032d6c 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -514,7 +514,7 @@ class TestUtil(unittest.TestCase): args = ['ffmpeg', '-i', encodeFilename('ñ€ß\'.mp4')] self.assertEqual( shell_quote(args), - """ffmpeg -i 'ñ€ß'"'"'.mp4'""" if compat_os_name != 'nt' else '''ffmpeg -i "ñ€ß'.mp4"''') + """ffmpeg -i 'ñ€ß'"'"'.mp4'""" if not (compat_os_name in ('nt', 'ce')) else '''ffmpeg -i "ñ€ß'.mp4"''') def test_float_or_none(self): self.assertEqual(float_or_none('42.42'), 42.42) @@ -1241,7 +1241,7 @@ class TestUtil(unittest.TestCase): def test_args_to_str(self): self.assertEqual( args_to_str(['foo', 'ba/r', '-baz', '2 be', '']), - 'foo ba/r -baz \'2 be\' \'\'' if compat_os_name != 'nt' else 'foo ba/r -baz "2 be" ""' + 'foo ba/r -baz \'2 be\' \'\'' if not(compat_os_name in ('nt', 'ce')) else 'foo ba/r -baz "2 be" ""' ) def test_parse_filesize(self): diff --git a/youtube_dl/compat.py b/youtube_dl/compat.py index 818ccebd0..cc43172e2 100644 --- a/youtube_dl/compat.py +++ b/youtube_dl/compat.py @@ -2776,16 +2776,19 @@ else: # Otherwise it will fail if any non-ASCII characters present (see #3854 #3217 #2918) def compat_getenv(key, default=None): - from .utils import get_filesystem_encoding env = os.getenv(key, default) if env: - env = env.decode(get_filesystem_encoding()) + from .utils import get_filesystem_encoding + encoding = get_filesystem_encoding() + env = env.decode(encoding) + if not encoding.lower().startswith('ut'): + env = env.encode('utf-8').decode('unicode-escape') return env def compat_setenv(key, value, env=os.environ): def encode(v): from .utils import get_filesystem_encoding - return v.encode(get_filesystem_encoding()) if isinstance(v, compat_str) else v + return v.encode(get_filesystem_encoding(), 'backslashreplace') if isinstance(v, compat_str) else v env[encode(key)] = encode(value) # HACK: The default implementations of os.path.expanduser from cpython do not decode diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 03c73dff3..970bc591a 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -3566,8 +3566,7 @@ class locked_file(object): def get_filesystem_encoding(): - encoding = sys.getfilesystemencoding() - return encoding if encoding is not None else 'utf-8' + return sys.getfilesystemencoding() or sys.getdefaultencoding() or 'utf-8' def shell_quote(args): @@ -3576,6 +3575,11 @@ def shell_quote(args): for a in args: # We may get a filename encoded with 'encodeFilename' a = _decode_compat_str(a, encoding) + if isinstance(a, bytes): + # We may get a filename encoded with 'encodeFilename' + a = a.decode(encoding) + if not encoding.lower().startswith('ut'): + a = a.encode('utf-8').decode('unicode-escape') quoted_args.append(compat_shlex_quote(a)) return ' '.join(quoted_args) @@ -5065,7 +5069,7 @@ def dfxp2srt(dfxp_data): continue default_style.update(style) - for para, index in zip(paras, itertools.count(1)): + for index, para in enumerate(paras, 1): begin_time = parse_dfxp_time_expr(para.attrib.get('begin')) end_time = parse_dfxp_time_expr(para.attrib.get('end')) dur = parse_dfxp_time_expr(para.attrib.get('dur')) From d87e2ad040ff5a09bf2d804527aab13eb105bc4a Mon Sep 17 00:00:00 2001 From: df Date: Sun, 29 Aug 2021 05:34:20 +0100 Subject: [PATCH 02/18] [utils] Fix urlhandle_detect_ext() non-ASCII error in Py2, with test --- test/test_utils.py | 25 +++++++++++++++++++++++++ youtube_dl/utils.py | 8 +++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/test/test_utils.py b/test/test_utils.py index 870032d6c..3928173c8 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -102,6 +102,7 @@ from youtube_dl.utils import ( url_or_none, urljoin, urlencode_postdata, + urlhandle_detect_ext, urshift, update_url_query, variadic, @@ -2039,6 +2040,30 @@ Line 1 'a', 'b', 'c', 'd', from_dict={'a': 'c', 'c': [], 'b': 'd', 'd': None}), 'c-d') + def test_urlhandle_detect_ext(self): + + class UrlHandle(object): + _info = {} + + def __init__(self, info): + self._info = info + + @property + def headers(self): + return self._info + + # header with non-ASCII character and contradictory Content-Type + urlh = UrlHandle({ + 'Content-Disposition': b'attachment; filename="Epis\xf3dio contains non-ASCI ISO 8859-1 character.mp3"', + 'Content-Type': b'audio/aac', + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + # header with no Content-Disposition + urlh = UrlHandle({ + 'Content-Type': b'audio/mp3', + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + if __name__ == '__main__': unittest.main() diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 970bc591a..f35c71601 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -4743,7 +4743,8 @@ def parse_codecs(codecs_str): def urlhandle_detect_ext(url_handle): - getheader = url_handle.headers.get + getheader = lambda x: _decode_compat_str( + url_handle.headers.get(x), encoding='iso-8859-1', errors='ignore', or_none=True) cd = getheader('Content-Disposition') if cd: @@ -4753,6 +4754,11 @@ def urlhandle_detect_ext(url_handle): if e: return e + # from yt-dlp/2647c933b8: thx bashonly + meta_ext = (getheader('x-amz-meta-name') or '').rpartition('.')[2] + if meta_ext: + return meta_ext + return mimetype2ext(getheader('Content-Type')) From 7990d1e6308c875e6d8e1940b957be5d7171be92 Mon Sep 17 00:00:00 2001 From: df Date: Mon, 13 Sep 2021 01:00:04 +0100 Subject: [PATCH 03/18] [utils] Disambiguate 4-digit year and time-zone suffix Restore check omitted from extract_timezone(); adjust DATE_FORMATS_DAY/MONTH_FIRST; add tests. --- test/test_utils.py | 6 ++++++ youtube_dl/utils.py | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 3928173c8..58a79c8a8 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -405,6 +405,12 @@ class TestUtil(unittest.TestCase): self.assertEqual(unified_timestamp('December 31 1969 20:00:01 EDT'), 1) self.assertEqual(unified_timestamp('Wednesday 31 December 1969 18:01:26 MDT'), 86) self.assertEqual(unified_timestamp('12/31/1969 20:01:18 EDT', False), 78) + self.assertEqual(unified_timestamp('11:31 17-Jun-2021'), 1623929460) + self.assertEqual(unified_timestamp('11:31 17-Jun-2021-0000'), 1623929460) + from youtube_dl.utils import DATE_FORMATS_DAY_FIRST + DATE_FORMATS_DAY_FIRST.append('%H:%M %d-%m-%Y') + self.assertEqual(unified_timestamp('17:30 27-02-2016'), 1456594200) + self.assertEqual(unified_timestamp('17:30 27-02-2016-0000'), 1456594200) def test_determine_ext(self): self.assertEqual(determine_ext('http://example.com/foo/bar.mp4/?download'), 'mp4') diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index f35c71601..ff3479fbd 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # coding: utf-8 from __future__ import unicode_literals @@ -1734,8 +1733,6 @@ ACCENT_CHARS = dict(zip('ÂÃÄÀÁÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖŐ،٠'aaaaaa', ['ae'], 'ceeeeiiiionooooooo', ['oe'], 'uuuuuy', ['th'], 'y'))) DATE_FORMATS = ( - '%d %B %Y', - '%d %b %Y', '%B %d %Y', '%B %dst %Y', '%B %dnd %Y', @@ -1787,6 +1784,11 @@ DATE_FORMATS_DAY_FIRST.extend([ '%d/%m/%y', '%d/%m/%Y %H:%M:%S', '%d-%m-%Y %H:%M', + '%d %B %Y', + '%d %b %Y', + '%d-%b-%Y', + '%H:%M %d-%b-%Y', + '%H:%M:%S %d-%b-%Y', ]) DATE_FORMATS_MONTH_FIRST = list(DATE_FORMATS) @@ -1796,6 +1798,11 @@ DATE_FORMATS_MONTH_FIRST.extend([ '%m/%d/%Y', '%m/%d/%y', '%m/%d/%Y %H:%M:%S', + '%B %d %Y', + '%b %d %Y', + '%b-%d-%Y', + '%H:%M %b-%d-%Y', + '%H:%M:%S %b-%d-%Y', ]) PACKED_CODES_RE = r"}\('(.+)',(\d+),(\d+),'([^']+)'\.split\('\|'\)" From 973f76cf7b2b02426d4d5335cd149aabe38c5bbb Mon Sep 17 00:00:00 2001 From: df Date: Sun, 10 Oct 2021 12:42:51 +0100 Subject: [PATCH 04/18] [utils] Detect extension from any RFC Content-Disposition syntax Add support for unquoted token and RFC 5987 extended parameter syntax --- test/test_utils.py | 27 +++++++++++++++++++++++++++ youtube_dl/utils.py | 20 +++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 58a79c8a8..8df794c13 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -2069,6 +2069,33 @@ Line 1 'Content-Type': b'audio/mp3', }) self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + # header with Content-Disposition and unquoted filename + urlh = UrlHandle({ + 'Content-Disposition': b'attachment; filename=unquoted_filename_token.mp3', + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + # header with Content-Disposition including spacing and uppercase + urlh = UrlHandle({ + 'Content-Disposition': b'ATTACHMENT; FileName = unquoted_filename_token.mp3', + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + # header with Content-Disposition and extended filename parameter syntax + urlh = UrlHandle({ + 'Content-Disposition': b"attachment; filename*=iso8859-15''costs%201%A4%20filename.mp3", + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + # header with Content-Disposition and both filename parameter syntaxes + urlh = UrlHandle({ + 'Content-Disposition': b'''attachment; filename="should ignore.mp4"; + FileName* = iso8859-15''costs%201%A4%20filename.mp3''', + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') + # header with Content-Disposition and 'wrong' order of both syntaxes + urlh = UrlHandle({ + 'Content-Disposition': b'''attachment; filename*=iso8859-15''costs%201%A4%20filename.mp3; + filename="should ignore.mp4"''', + }) + self.assertEqual(urlhandle_detect_ext(urlh), 'mp3') if __name__ == '__main__': diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index ff3479fbd..e059f4a72 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -66,9 +66,10 @@ from .compat import ( compat_urllib_HTTPError, compat_urllib_parse, compat_urllib_parse_parse_qs as compat_parse_qs, + compat_urllib_parse_unquote, + compat_urllib_parse_unquote_plus, compat_urllib_parse_urlencode, compat_urllib_parse_urlparse, - compat_urllib_parse_unquote_plus, compat_urllib_request, compat_xpath, ) @@ -4755,9 +4756,22 @@ def urlhandle_detect_ext(url_handle): cd = getheader('Content-Disposition') if cd: - m = re.match(r'attachment;\s*filename="(?P[^"]+)"', cd) + m = re.match(r'''(?xi) + attachment;\s* + (?:filename\s*=[^;]+?;\s*)? # possible initial filename=...;, ignored + filename(?P\*)?\s*=\s* # filename/filename* = + (?(x)(?P\S+?)'[\w-]*'|(?P")?) # if * then charset'...' else maybe " + (?P(?(q)[^"]+(?=")|[^\s;]+)) # actual name of file + ''', cd) if m: - e = determine_ext(m.group('filename'), default_ext=None) + m = m.groupdict() + filename = m.get('filename') + if m.get('x'): + try: + filename = compat_urllib_parse_unquote(filename, encoding=m.get('charset', 'utf-8')) + except LookupError: # unrecognised character set name + pass + e = determine_ext(filename, default_ext=None) if e: return e From a3fe1d1dc645aeb12ee99baf957e6b1a6d154d75 Mon Sep 17 00:00:00 2001 From: df Date: Mon, 11 Oct 2021 13:10:50 +0100 Subject: [PATCH 05/18] [utils] Avoid scrubbing supplied cookie file on failed update --- youtube_dl/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index e059f4a72..653fe9fcd 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -2953,7 +2953,8 @@ class YoutubeDLCookieJar(compat_cookiejar.MozillaCookieJar): if cookie.expires is None: cookie.expires = 0 - with io.open(filename, 'w', encoding='utf-8') as f: + with io.open(filename, 'r+', encoding='utf-8') as f: + assert 0 == f.seek(0) f.write(self._HEADER) now = time.time() for cookie in self: @@ -2985,6 +2986,7 @@ class YoutubeDLCookieJar(compat_cookiejar.MozillaCookieJar): f.write( '\t'.join([cookie.domain, initial_dot, cookie.path, secure, expires, name, value]) + '\n') + assert f.tell() == f.truncate() def load(self, filename=None, ignore_discard=False, ignore_expires=False): """Load cookies from a file.""" From 58f15bb6c8733635cbb2486ebb49bde3b17675a2 Mon Sep 17 00:00:00 2001 From: df Date: Sat, 13 Nov 2021 22:03:19 +0000 Subject: [PATCH 06/18] [utils] Don't find classname as part of class="... x-classname ...", etc Eg, in [1], the class with name 'plist-info' was found when searching for 'info'. 1. https://github.com/ytdl-org/youtube-dl/issues/30230 --- test/test_utils.py | 5 ++++- youtube_dl/utils.py | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 8df794c13..1186dd46b 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1619,7 +1619,10 @@ Line 1 def test_get_elements_by_class(self): html = ''' - nicealso nice + nasty + nice + "also nice" + also nasty ''' self.assertEqual(get_elements_by_class('foo', html), ['nice', 'also nice']) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 653fe9fcd..19bdd3049 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -1986,7 +1986,9 @@ def get_element_by_attribute(attribute, value, html, escape_value=True): def get_elements_by_class(class_name, html): """Return the content of all tags with the specified class in the passed HTML document as a list""" return get_elements_by_attribute( - 'class', r'[^\'"]*\b%s\b[^\'"]*' % re.escape(class_name), + # class names can contain alphanumeric, -, _ and \ for escapes + # don't allow a word break at - + 'class', r'(?:[\w\s\\-]*?[\w\s])?\b%s\b(?:[\w\s\\][\w\s\\-]*?)?' % re.escape(class_name), html, escape_value=False) @@ -1997,11 +1999,13 @@ def get_elements_by_attribute(attribute, value, html, escape_value=True): retlist = [] for m in re.finditer(r'''(?xs) - <([a-zA-Z0-9:._-]+) + <([a-zA-Z0-9:._-]+) # conservative pattern: HTML tags don't have :._- + # (?:\s[^>]+) # this seems to be simpler than the below and work the same? (?:\s+[a-zA-Z0-9:._-]+(?:=[a-zA-Z0-9:._-]*|="[^"]*"|='[^']*'|))*? - \s+%s=['"]?%s['"]? + \s*\b%s\s*=\s*(?P<__q>'|"|\b)%s(?P=__q) + # (?:\s[^>]+)? # as above (?:\s+[a-zA-Z0-9:._-]+(?:=[a-zA-Z0-9:._-]*|="[^"]*"|='[^']*'|))*? - \s*> + \s*> (?P.*?) ''' % (re.escape(attribute), value), html): From eb93aaf702016c5a197ddb51553b6a539a323a74 Mon Sep 17 00:00:00 2001 From: dirkf Date: Wed, 26 Jan 2022 14:54:43 +0000 Subject: [PATCH 07/18] [utils] Improve ExtractorError with msg IV and ie constructor param --- youtube_dl/utils.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 19bdd3049..7505c4a18 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -2412,26 +2412,28 @@ class YoutubeDLError(Exception): class ExtractorError(YoutubeDLError): """Error during info extraction.""" - def __init__(self, msg, tb=None, expected=False, cause=None, video_id=None): + def __init__(self, msg, tb=None, expected=False, cause=None, video_id=None, ie=None): """ tb, if given, is the original traceback (so that it can be printed out). If expected is set, this is a normal error message and most likely not a bug in youtube-dl. """ - if sys.exc_info()[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError): - expected = True - if video_id is not None: - msg = video_id + ': ' + msg - if cause: - msg += ' (caused by %r)' % cause - if not expected: - msg += bug_reports_message() - super(ExtractorError, self).__init__(msg) - + self.msg = compat_str(msg) self.traceback = tb self.exc_info = sys.exc_info() # preserve original exception self.cause = cause self.video_id = video_id + expected = expected or ( + self.exc_info[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError)) + msg = ''.join(( + '[%s] ' % ie if ie is not None else '', + video_id + ': ' if video_id is not None else '', + self.msg or 'Extractor error', + (' (caused by %r)' % (cause, )) if cause else '', + bug_reports_message() if not expected else '', + )) + super(ExtractorError, self).__init__(msg) + def format_traceback(self): if self.traceback is None: return None From 045ff706ee31c72b489ab2ae3053652328e8197d Mon Sep 17 00:00:00 2001 From: dirkf Date: Wed, 26 Jan 2022 17:00:08 +0000 Subject: [PATCH 08/18] [utils] Work-around for yt-dlp issue 1060 (skip bad certs from Windows, Py>=3.7) --- youtube_dl/utils.py | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 7505c4a18..f010e733d 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -2361,19 +2361,48 @@ def make_HTTPS_handler(params, **kwargs): # https://github.com/python/cpython/issues/85140 # https://github.com/yt-dlp/yt-dlp/issues/3878 try: + # fails on Python < 2.7.10, not ssl.HAS_ALPN ctx.set_alpn_protocols(ALPN_PROTOCOLS) except (AttributeError, NotImplementedError): - # Python < 2.7.10, not ssl.HAS_ALPN pass - opts_no_check_certificate = params.get('nocheckcertificate', False) + opts_check_certificate = not params.get('nocheckcertificate', False) + + if opts_check_certificate and sys.version_info >= (3, 7) and sys.platform == 'win32' and hasattr(ssl, 'enum_certificates'): + # From yt-dlp: work around issue in load_default_certs if there are bad certificates. See: + # https://github.com/yt-dlp/yt-dlp/issues/1060, + # https://bugs.python.org/issue35665, https://bugs.python.org/issue4531 + # but not with MingW (no enum_certificates()) + from types import MethodType + + def ssl_load_windows_store_certs(ssl_context, storename): + # Code adapted from _load_windows_store_certs in https://github.com/python/cpython/blob/main/Lib/ssl.py + try: + certs = [cert for cert, encoding, trust in ssl.enum_certificates(storename) + if encoding == 'x509_asn' and ( + trust is True or ssl.Purpose.SERVER_AUTH.oid in trust)] + except PermissionError: + return + for cert in certs: + try: + ssl_context.load_verify_locations(cadata=cert) + # no warning on error, as the problem is probably a permanent unfixable feature of the platform + except ssl.SSLError: + pass + + ssl.SSLContext._ssl_load_windows_store_certs = MethodType(ssl_load_windows_store_certs, ssl.SSLContext) + ssl_cert_verify_mode = True + else: + ssl_cert_verify_mode = ssl.CERT_REQUIRED if opts_check_certificate else ssl.CERT_NONE + if hasattr(ssl, 'create_default_context'): # Python >= 3.4 or 2.7.9 + # To avoid mentioning SSL options by name (varying by Python version) + # we ask for the *default* settings when possible, relying on + # Python ssl to select the best settings known to that version context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) set_alpn_protocols(context) - if opts_no_check_certificate: - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - + context.check_hostname = opts_check_certificate + context.verify_mode = ssl_cert_verify_mode try: return YoutubeDLHTTPSHandler(params, context=context, **kwargs) except TypeError: @@ -2385,9 +2414,7 @@ def make_HTTPS_handler(params, **kwargs): return YoutubeDLHTTPSHandler(params, **kwargs) else: # Python3 < 3.4 context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) - context.verify_mode = (ssl.CERT_NONE - if opts_no_check_certificate - else ssl.CERT_REQUIRED) + context.verify_mode = ssl_cert_verify_mode context.set_default_verify_paths() set_alpn_protocols(context) return YoutubeDLHTTPSHandler(params, context=context, **kwargs) From 7a438da3b12459a6e9df2490c190a64775766863 Mon Sep 17 00:00:00 2001 From: dirkf Date: Wed, 26 Jan 2022 18:12:55 +0000 Subject: [PATCH 09/18] [utils] Ensure a value from determine_protocol() --- youtube_dl/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index f010e733d..e7e6bdbcd 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -4871,7 +4871,7 @@ def determine_protocol(info_dict): elif ext == 'f4m': return 'f4m' - return compat_urllib_parse_urlparse(url).scheme + return compat_urllib_parse_urlparse(url).scheme or 'http' def render_table(header_row, data): From 5988a39483565407b9c952b1d24c8af48d46e822 Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 27 Jan 2022 01:09:00 +0000 Subject: [PATCH 10/18] [utils] Simplify int_or_none(), based on yt-dlp 9e907ebddf9c9c3084fb1b24156c9e3786ab428e Also swallow inf, nan --- youtube_dl/utils.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index e7e6bdbcd..5a1c78f4c 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -3900,16 +3900,16 @@ class PUTRequest(compat_urllib_request.Request): def int_or_none(v, scale=1, default=None, get_attr=None, invscale=1, base=None): - if get_attr: - if v is not None: - v = getattr(v, get_attr, None) - if v in (None, ''): - return default - try: - # like int, raise if base is specified and v is not a string - return (int(v) if base is None else int(v, base=base)) * invscale // scale - except (ValueError, TypeError, OverflowError): - return default + if get_attr and v is not None: + v = getattr(v, get_attr, None) + result = default + if v not in (None, ''): + try: + # like int, raise if base is specified and v is not a string + result = (int(v) if base is None else int(v, base=base)) * invscale // scale + except (ValueError, TypeError, OverflowError): + pass + return result def str_or_none(v, default=None): From 77c778b838fd255d8b1d153be673c6fd11215eff Mon Sep 17 00:00:00 2001 From: dirkf Date: Wed, 26 Jan 2022 20:33:04 +0000 Subject: [PATCH 11/18] [utils] Sort Chrome versions used for UAs; drop obsolete `Accept-Charset` header --- youtube_dl/utils.py | 3148 +++++++++++++++++++++---------------------- 1 file changed, 1574 insertions(+), 1574 deletions(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 5a1c78f4c..3fc78cf42 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -96,1582 +96,1582 @@ compiled_regex_type = compat_re_Pattern def random_user_agent(): _USER_AGENT_TPL = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36' _CHROME_VERSIONS = ( - '74.0.3729.129', - '76.0.3780.3', - '76.0.3780.2', - '74.0.3729.128', - '76.0.3780.1', - '76.0.3780.0', - '75.0.3770.15', - '74.0.3729.127', - '74.0.3729.126', - '76.0.3779.1', - '76.0.3779.0', - '75.0.3770.14', - '74.0.3729.125', - '76.0.3778.1', - '76.0.3778.0', - '75.0.3770.13', - '74.0.3729.124', - '74.0.3729.123', - '73.0.3683.121', - '76.0.3777.1', - '76.0.3777.0', - '75.0.3770.12', - '74.0.3729.122', - '76.0.3776.4', - '75.0.3770.11', - '74.0.3729.121', - '76.0.3776.3', - '76.0.3776.2', - '73.0.3683.120', - '74.0.3729.120', - '74.0.3729.119', - '74.0.3729.118', - '76.0.3776.1', - '76.0.3776.0', - '76.0.3775.5', - '75.0.3770.10', - '74.0.3729.117', - '76.0.3775.4', - '76.0.3775.3', - '74.0.3729.116', - '75.0.3770.9', - '76.0.3775.2', - '76.0.3775.1', - '76.0.3775.0', - '75.0.3770.8', - '74.0.3729.115', - '74.0.3729.114', - '76.0.3774.1', - '76.0.3774.0', - '75.0.3770.7', - '74.0.3729.113', - '74.0.3729.112', - '74.0.3729.111', - '76.0.3773.1', - '76.0.3773.0', - '75.0.3770.6', - '74.0.3729.110', - '74.0.3729.109', - '76.0.3772.1', - '76.0.3772.0', - '75.0.3770.5', - '74.0.3729.108', - '74.0.3729.107', - '76.0.3771.1', - '76.0.3771.0', - '75.0.3770.4', - '74.0.3729.106', - '74.0.3729.105', - '75.0.3770.3', - '74.0.3729.104', - '74.0.3729.103', - '74.0.3729.102', - '75.0.3770.2', - '74.0.3729.101', - '75.0.3770.1', - '75.0.3770.0', - '74.0.3729.100', - '75.0.3769.5', - '75.0.3769.4', - '74.0.3729.99', - '75.0.3769.3', - '75.0.3769.2', - '75.0.3768.6', - '74.0.3729.98', - '75.0.3769.1', - '75.0.3769.0', - '74.0.3729.97', - '73.0.3683.119', - '73.0.3683.118', - '74.0.3729.96', - '75.0.3768.5', - '75.0.3768.4', - '75.0.3768.3', - '75.0.3768.2', - '74.0.3729.95', - '74.0.3729.94', - '75.0.3768.1', - '75.0.3768.0', - '74.0.3729.93', - '74.0.3729.92', - '73.0.3683.117', - '74.0.3729.91', - '75.0.3766.3', - '74.0.3729.90', - '75.0.3767.2', - '75.0.3767.1', - '75.0.3767.0', - '74.0.3729.89', - '73.0.3683.116', - '75.0.3766.2', - '74.0.3729.88', - '75.0.3766.1', - '75.0.3766.0', - '74.0.3729.87', - '73.0.3683.115', - '74.0.3729.86', - '75.0.3765.1', - '75.0.3765.0', - '74.0.3729.85', - '73.0.3683.114', - '74.0.3729.84', - '75.0.3764.1', - '75.0.3764.0', - '74.0.3729.83', - '73.0.3683.113', - '75.0.3763.2', - '75.0.3761.4', - '74.0.3729.82', - '75.0.3763.1', - '75.0.3763.0', - '74.0.3729.81', - '73.0.3683.112', - '75.0.3762.1', - '75.0.3762.0', - '74.0.3729.80', - '75.0.3761.3', - '74.0.3729.79', - '73.0.3683.111', - '75.0.3761.2', - '74.0.3729.78', - '74.0.3729.77', - '75.0.3761.1', - '75.0.3761.0', - '73.0.3683.110', - '74.0.3729.76', - '74.0.3729.75', - '75.0.3760.0', - '74.0.3729.74', - '75.0.3759.8', - '75.0.3759.7', - '75.0.3759.6', - '74.0.3729.73', - '75.0.3759.5', - '74.0.3729.72', - '73.0.3683.109', - '75.0.3759.4', - '75.0.3759.3', - '74.0.3729.71', - '75.0.3759.2', - '74.0.3729.70', - '73.0.3683.108', - '74.0.3729.69', - '75.0.3759.1', - '75.0.3759.0', - '74.0.3729.68', - '73.0.3683.107', - '74.0.3729.67', - '75.0.3758.1', - '75.0.3758.0', - '74.0.3729.66', - '73.0.3683.106', - '74.0.3729.65', - '75.0.3757.1', - '75.0.3757.0', - '74.0.3729.64', - '73.0.3683.105', - '74.0.3729.63', - '75.0.3756.1', - '75.0.3756.0', - '74.0.3729.62', - '73.0.3683.104', - '75.0.3755.3', - '75.0.3755.2', - '73.0.3683.103', - '75.0.3755.1', - '75.0.3755.0', - '74.0.3729.61', - '73.0.3683.102', - '74.0.3729.60', - '75.0.3754.2', - '74.0.3729.59', - '75.0.3753.4', - '74.0.3729.58', - '75.0.3754.1', - '75.0.3754.0', - '74.0.3729.57', - '73.0.3683.101', - '75.0.3753.3', - '75.0.3752.2', - '75.0.3753.2', - '74.0.3729.56', - '75.0.3753.1', - '75.0.3753.0', - '74.0.3729.55', - '73.0.3683.100', - '74.0.3729.54', - '75.0.3752.1', - '75.0.3752.0', - '74.0.3729.53', - '73.0.3683.99', - '74.0.3729.52', - '75.0.3751.1', - '75.0.3751.0', - '74.0.3729.51', - '73.0.3683.98', - '74.0.3729.50', - '75.0.3750.0', - '74.0.3729.49', - '74.0.3729.48', - '74.0.3729.47', - '75.0.3749.3', - '74.0.3729.46', - '73.0.3683.97', - '75.0.3749.2', - '74.0.3729.45', - '75.0.3749.1', - '75.0.3749.0', - '74.0.3729.44', - '73.0.3683.96', - '74.0.3729.43', - '74.0.3729.42', - '75.0.3748.1', - '75.0.3748.0', - '74.0.3729.41', - '75.0.3747.1', - '73.0.3683.95', - '75.0.3746.4', - '74.0.3729.40', - '74.0.3729.39', - '75.0.3747.0', - '75.0.3746.3', - '75.0.3746.2', - '74.0.3729.38', - '75.0.3746.1', - '75.0.3746.0', - '74.0.3729.37', - '73.0.3683.94', - '75.0.3745.5', - '75.0.3745.4', - '75.0.3745.3', - '75.0.3745.2', - '74.0.3729.36', - '75.0.3745.1', - '75.0.3745.0', - '75.0.3744.2', - '74.0.3729.35', - '73.0.3683.93', - '74.0.3729.34', - '75.0.3744.1', - '75.0.3744.0', - '74.0.3729.33', - '73.0.3683.92', - '74.0.3729.32', - '74.0.3729.31', - '73.0.3683.91', - '75.0.3741.2', - '75.0.3740.5', - '74.0.3729.30', - '75.0.3741.1', - '75.0.3741.0', - '74.0.3729.29', - '75.0.3740.4', - '73.0.3683.90', - '74.0.3729.28', - '75.0.3740.3', - '73.0.3683.89', - '75.0.3740.2', - '74.0.3729.27', - '75.0.3740.1', - '75.0.3740.0', - '74.0.3729.26', - '73.0.3683.88', - '73.0.3683.87', - '74.0.3729.25', - '75.0.3739.1', - '75.0.3739.0', - '73.0.3683.86', - '74.0.3729.24', - '73.0.3683.85', - '75.0.3738.4', - '75.0.3738.3', - '75.0.3738.2', - '75.0.3738.1', - '75.0.3738.0', - '74.0.3729.23', - '73.0.3683.84', - '74.0.3729.22', - '74.0.3729.21', - '75.0.3737.1', - '75.0.3737.0', - '74.0.3729.20', - '73.0.3683.83', - '74.0.3729.19', - '75.0.3736.1', - '75.0.3736.0', - '74.0.3729.18', - '73.0.3683.82', - '74.0.3729.17', - '75.0.3735.1', - '75.0.3735.0', - '74.0.3729.16', - '73.0.3683.81', - '75.0.3734.1', - '75.0.3734.0', - '74.0.3729.15', - '73.0.3683.80', - '74.0.3729.14', - '75.0.3733.1', - '75.0.3733.0', - '75.0.3732.1', - '74.0.3729.13', - '74.0.3729.12', - '73.0.3683.79', - '74.0.3729.11', - '75.0.3732.0', - '74.0.3729.10', - '73.0.3683.78', - '74.0.3729.9', - '74.0.3729.8', - '74.0.3729.7', - '75.0.3731.3', - '75.0.3731.2', - '75.0.3731.0', - '74.0.3729.6', - '73.0.3683.77', - '73.0.3683.76', - '75.0.3730.5', - '75.0.3730.4', - '73.0.3683.75', - '74.0.3729.5', - '73.0.3683.74', - '75.0.3730.3', - '75.0.3730.2', - '74.0.3729.4', - '73.0.3683.73', - '73.0.3683.72', - '75.0.3730.1', - '75.0.3730.0', - '74.0.3729.3', - '73.0.3683.71', - '74.0.3729.2', - '73.0.3683.70', - '74.0.3729.1', - '74.0.3729.0', - '74.0.3726.4', - '73.0.3683.69', - '74.0.3726.3', - '74.0.3728.0', - '74.0.3726.2', - '73.0.3683.68', - '74.0.3726.1', - '74.0.3726.0', - '74.0.3725.4', - '73.0.3683.67', - '73.0.3683.66', - '74.0.3725.3', - '74.0.3725.2', - '74.0.3725.1', - '74.0.3724.8', - '74.0.3725.0', - '73.0.3683.65', - '74.0.3724.7', - '74.0.3724.6', - '74.0.3724.5', - '74.0.3724.4', - '74.0.3724.3', - '74.0.3724.2', - '74.0.3724.1', - '74.0.3724.0', - '73.0.3683.64', - '74.0.3723.1', - '74.0.3723.0', - '73.0.3683.63', - '74.0.3722.1', - '74.0.3722.0', - '73.0.3683.62', - '74.0.3718.9', - '74.0.3702.3', - '74.0.3721.3', - '74.0.3721.2', - '74.0.3721.1', - '74.0.3721.0', - '74.0.3720.6', - '73.0.3683.61', - '72.0.3626.122', - '73.0.3683.60', - '74.0.3720.5', - '72.0.3626.121', - '74.0.3718.8', - '74.0.3720.4', - '74.0.3720.3', - '74.0.3718.7', - '74.0.3720.2', - '74.0.3720.1', - '74.0.3720.0', - '74.0.3718.6', - '74.0.3719.5', - '73.0.3683.59', - '74.0.3718.5', - '74.0.3718.4', - '74.0.3719.4', - '74.0.3719.3', - '74.0.3719.2', - '74.0.3719.1', - '73.0.3683.58', - '74.0.3719.0', - '73.0.3683.57', - '73.0.3683.56', - '74.0.3718.3', - '73.0.3683.55', - '74.0.3718.2', - '74.0.3718.1', - '74.0.3718.0', - '73.0.3683.54', - '74.0.3717.2', - '73.0.3683.53', - '74.0.3717.1', - '74.0.3717.0', - '73.0.3683.52', - '74.0.3716.1', - '74.0.3716.0', - '73.0.3683.51', - '74.0.3715.1', - '74.0.3715.0', - '73.0.3683.50', - '74.0.3711.2', - '74.0.3714.2', - '74.0.3713.3', - '74.0.3714.1', - '74.0.3714.0', - '73.0.3683.49', - '74.0.3713.1', - '74.0.3713.0', - '72.0.3626.120', - '73.0.3683.48', - '74.0.3712.2', - '74.0.3712.1', - '74.0.3712.0', - '73.0.3683.47', - '72.0.3626.119', - '73.0.3683.46', - '74.0.3710.2', - '72.0.3626.118', - '74.0.3711.1', - '74.0.3711.0', - '73.0.3683.45', - '72.0.3626.117', - '74.0.3710.1', - '74.0.3710.0', - '73.0.3683.44', - '72.0.3626.116', - '74.0.3709.1', - '74.0.3709.0', - '74.0.3704.9', - '73.0.3683.43', - '72.0.3626.115', - '74.0.3704.8', - '74.0.3704.7', - '74.0.3708.0', - '74.0.3706.7', - '74.0.3704.6', - '73.0.3683.42', - '72.0.3626.114', - '74.0.3706.6', - '72.0.3626.113', - '74.0.3704.5', - '74.0.3706.5', - '74.0.3706.4', - '74.0.3706.3', - '74.0.3706.2', - '74.0.3706.1', - '74.0.3706.0', - '73.0.3683.41', - '72.0.3626.112', - '74.0.3705.1', - '74.0.3705.0', - '73.0.3683.40', - '72.0.3626.111', - '73.0.3683.39', - '74.0.3704.4', - '73.0.3683.38', - '74.0.3704.3', - '74.0.3704.2', - '74.0.3704.1', - '74.0.3704.0', - '73.0.3683.37', - '72.0.3626.110', - '72.0.3626.109', - '74.0.3703.3', - '74.0.3703.2', - '73.0.3683.36', - '74.0.3703.1', - '74.0.3703.0', - '73.0.3683.35', - '72.0.3626.108', - '74.0.3702.2', - '74.0.3699.3', - '74.0.3702.1', - '74.0.3702.0', - '73.0.3683.34', - '72.0.3626.107', - '73.0.3683.33', - '74.0.3701.1', - '74.0.3701.0', - '73.0.3683.32', - '73.0.3683.31', - '72.0.3626.105', - '74.0.3700.1', - '74.0.3700.0', - '73.0.3683.29', - '72.0.3626.103', - '74.0.3699.2', - '74.0.3699.1', - '74.0.3699.0', - '73.0.3683.28', - '72.0.3626.102', - '73.0.3683.27', - '73.0.3683.26', - '74.0.3698.0', - '74.0.3696.2', - '72.0.3626.101', - '73.0.3683.25', - '74.0.3696.1', - '74.0.3696.0', - '74.0.3694.8', - '72.0.3626.100', - '74.0.3694.7', - '74.0.3694.6', - '74.0.3694.5', - '74.0.3694.4', - '72.0.3626.99', - '72.0.3626.98', - '74.0.3694.3', - '73.0.3683.24', - '72.0.3626.97', - '72.0.3626.96', - '72.0.3626.95', - '73.0.3683.23', - '72.0.3626.94', - '73.0.3683.22', - '73.0.3683.21', - '72.0.3626.93', - '74.0.3694.2', - '72.0.3626.92', - '74.0.3694.1', - '74.0.3694.0', - '74.0.3693.6', - '73.0.3683.20', - '72.0.3626.91', - '74.0.3693.5', - '74.0.3693.4', - '74.0.3693.3', - '74.0.3693.2', - '73.0.3683.19', - '74.0.3693.1', - '74.0.3693.0', - '73.0.3683.18', - '72.0.3626.90', - '74.0.3692.1', - '74.0.3692.0', - '73.0.3683.17', - '72.0.3626.89', - '74.0.3687.3', - '74.0.3691.1', - '74.0.3691.0', - '73.0.3683.16', - '72.0.3626.88', - '72.0.3626.87', - '73.0.3683.15', - '74.0.3690.1', - '74.0.3690.0', - '73.0.3683.14', - '72.0.3626.86', - '73.0.3683.13', - '73.0.3683.12', - '74.0.3689.1', - '74.0.3689.0', - '73.0.3683.11', - '72.0.3626.85', - '73.0.3683.10', - '72.0.3626.84', - '73.0.3683.9', - '74.0.3688.1', - '74.0.3688.0', - '73.0.3683.8', - '72.0.3626.83', - '74.0.3687.2', - '74.0.3687.1', - '74.0.3687.0', - '73.0.3683.7', - '72.0.3626.82', - '74.0.3686.4', - '72.0.3626.81', - '74.0.3686.3', - '74.0.3686.2', - '74.0.3686.1', - '74.0.3686.0', - '73.0.3683.6', - '72.0.3626.80', - '74.0.3685.1', - '74.0.3685.0', - '73.0.3683.5', - '72.0.3626.79', - '74.0.3684.1', - '74.0.3684.0', - '73.0.3683.4', - '72.0.3626.78', - '72.0.3626.77', - '73.0.3683.3', - '73.0.3683.2', - '72.0.3626.76', - '73.0.3683.1', - '73.0.3683.0', - '72.0.3626.75', - '71.0.3578.141', - '73.0.3682.1', - '73.0.3682.0', - '72.0.3626.74', - '71.0.3578.140', - '73.0.3681.4', - '73.0.3681.3', - '73.0.3681.2', - '73.0.3681.1', - '73.0.3681.0', - '72.0.3626.73', - '71.0.3578.139', - '72.0.3626.72', - '72.0.3626.71', - '73.0.3680.1', - '73.0.3680.0', - '72.0.3626.70', - '71.0.3578.138', - '73.0.3678.2', - '73.0.3679.1', - '73.0.3679.0', - '72.0.3626.69', - '71.0.3578.137', - '73.0.3678.1', - '73.0.3678.0', - '71.0.3578.136', - '73.0.3677.1', - '73.0.3677.0', - '72.0.3626.68', - '72.0.3626.67', - '71.0.3578.135', - '73.0.3676.1', - '73.0.3676.0', - '73.0.3674.2', - '72.0.3626.66', - '71.0.3578.134', - '73.0.3674.1', - '73.0.3674.0', - '72.0.3626.65', - '71.0.3578.133', - '73.0.3673.2', - '73.0.3673.1', - '73.0.3673.0', - '72.0.3626.64', - '71.0.3578.132', - '72.0.3626.63', - '72.0.3626.62', - '72.0.3626.61', - '72.0.3626.60', - '73.0.3672.1', - '73.0.3672.0', - '72.0.3626.59', - '71.0.3578.131', - '73.0.3671.3', - '73.0.3671.2', - '73.0.3671.1', - '73.0.3671.0', - '72.0.3626.58', - '71.0.3578.130', - '73.0.3670.1', - '73.0.3670.0', - '72.0.3626.57', - '71.0.3578.129', - '73.0.3669.1', - '73.0.3669.0', - '72.0.3626.56', - '71.0.3578.128', - '73.0.3668.2', - '73.0.3668.1', - '73.0.3668.0', - '72.0.3626.55', - '71.0.3578.127', - '73.0.3667.2', - '73.0.3667.1', - '73.0.3667.0', - '72.0.3626.54', - '71.0.3578.126', - '73.0.3666.1', - '73.0.3666.0', - '72.0.3626.53', - '71.0.3578.125', - '73.0.3665.4', - '73.0.3665.3', - '72.0.3626.52', - '73.0.3665.2', - '73.0.3664.4', - '73.0.3665.1', - '73.0.3665.0', - '72.0.3626.51', - '71.0.3578.124', - '72.0.3626.50', - '73.0.3664.3', - '73.0.3664.2', - '73.0.3664.1', - '73.0.3664.0', - '73.0.3663.2', - '72.0.3626.49', - '71.0.3578.123', - '73.0.3663.1', - '73.0.3663.0', - '72.0.3626.48', - '71.0.3578.122', - '73.0.3662.1', - '73.0.3662.0', - '72.0.3626.47', - '71.0.3578.121', - '73.0.3661.1', - '72.0.3626.46', - '73.0.3661.0', - '72.0.3626.45', - '71.0.3578.120', - '73.0.3660.2', - '73.0.3660.1', - '73.0.3660.0', - '72.0.3626.44', - '71.0.3578.119', - '73.0.3659.1', - '73.0.3659.0', - '72.0.3626.43', - '71.0.3578.118', - '73.0.3658.1', - '73.0.3658.0', - '72.0.3626.42', - '71.0.3578.117', - '73.0.3657.1', - '73.0.3657.0', - '72.0.3626.41', - '71.0.3578.116', - '73.0.3656.1', - '73.0.3656.0', - '72.0.3626.40', - '71.0.3578.115', - '73.0.3655.1', - '73.0.3655.0', - '72.0.3626.39', - '71.0.3578.114', - '73.0.3654.1', - '73.0.3654.0', - '72.0.3626.38', - '71.0.3578.113', - '73.0.3653.1', - '73.0.3653.0', - '72.0.3626.37', - '71.0.3578.112', - '73.0.3652.1', - '73.0.3652.0', - '72.0.3626.36', - '71.0.3578.111', - '73.0.3651.1', - '73.0.3651.0', - '72.0.3626.35', - '71.0.3578.110', - '73.0.3650.1', - '73.0.3650.0', - '72.0.3626.34', - '71.0.3578.109', - '73.0.3649.1', - '73.0.3649.0', - '72.0.3626.33', - '71.0.3578.108', - '73.0.3648.2', - '73.0.3648.1', - '73.0.3648.0', - '72.0.3626.32', - '71.0.3578.107', - '73.0.3647.2', - '73.0.3647.1', - '73.0.3647.0', - '72.0.3626.31', - '71.0.3578.106', - '73.0.3635.3', - '73.0.3646.2', - '73.0.3646.1', - '73.0.3646.0', - '72.0.3626.30', - '71.0.3578.105', - '72.0.3626.29', - '73.0.3645.2', - '73.0.3645.1', - '73.0.3645.0', - '72.0.3626.28', - '71.0.3578.104', - '72.0.3626.27', - '72.0.3626.26', - '72.0.3626.25', - '72.0.3626.24', - '73.0.3644.0', - '73.0.3643.2', - '72.0.3626.23', - '71.0.3578.103', - '73.0.3643.1', - '73.0.3643.0', - '72.0.3626.22', - '71.0.3578.102', - '73.0.3642.1', - '73.0.3642.0', - '72.0.3626.21', - '71.0.3578.101', - '73.0.3641.1', - '73.0.3641.0', - '72.0.3626.20', - '71.0.3578.100', - '72.0.3626.19', - '73.0.3640.1', - '73.0.3640.0', - '72.0.3626.18', - '73.0.3639.1', - '71.0.3578.99', - '73.0.3639.0', - '72.0.3626.17', - '73.0.3638.2', - '72.0.3626.16', - '73.0.3638.1', - '73.0.3638.0', - '72.0.3626.15', - '71.0.3578.98', - '73.0.3635.2', - '71.0.3578.97', - '73.0.3637.1', - '73.0.3637.0', - '72.0.3626.14', - '71.0.3578.96', - '71.0.3578.95', - '72.0.3626.13', - '71.0.3578.94', - '73.0.3636.2', - '71.0.3578.93', - '73.0.3636.1', - '73.0.3636.0', - '72.0.3626.12', - '71.0.3578.92', - '73.0.3635.1', - '73.0.3635.0', - '72.0.3626.11', - '71.0.3578.91', - '73.0.3634.2', - '73.0.3634.1', - '73.0.3634.0', - '72.0.3626.10', - '71.0.3578.90', - '71.0.3578.89', - '73.0.3633.2', - '73.0.3633.1', - '73.0.3633.0', - '72.0.3610.4', - '72.0.3626.9', - '71.0.3578.88', - '73.0.3632.5', - '73.0.3632.4', - '73.0.3632.3', - '73.0.3632.2', - '73.0.3632.1', - '73.0.3632.0', - '72.0.3626.8', - '71.0.3578.87', - '73.0.3631.2', - '73.0.3631.1', - '73.0.3631.0', - '72.0.3626.7', - '71.0.3578.86', - '72.0.3626.6', - '73.0.3630.1', - '73.0.3630.0', - '72.0.3626.5', - '71.0.3578.85', - '72.0.3626.4', - '73.0.3628.3', - '73.0.3628.2', - '73.0.3629.1', - '73.0.3629.0', - '72.0.3626.3', - '71.0.3578.84', - '73.0.3628.1', - '73.0.3628.0', - '71.0.3578.83', - '73.0.3627.1', - '73.0.3627.0', - '72.0.3626.2', - '71.0.3578.82', - '71.0.3578.81', - '71.0.3578.80', - '72.0.3626.1', - '72.0.3626.0', - '71.0.3578.79', - '70.0.3538.124', - '71.0.3578.78', - '72.0.3623.4', - '72.0.3625.2', - '72.0.3625.1', - '72.0.3625.0', - '71.0.3578.77', - '70.0.3538.123', - '72.0.3624.4', - '72.0.3624.3', - '72.0.3624.2', - '71.0.3578.76', - '72.0.3624.1', - '72.0.3624.0', - '72.0.3623.3', - '71.0.3578.75', - '70.0.3538.122', - '71.0.3578.74', - '72.0.3623.2', - '72.0.3610.3', - '72.0.3623.1', - '72.0.3623.0', - '72.0.3622.3', - '72.0.3622.2', - '71.0.3578.73', - '70.0.3538.121', - '72.0.3622.1', - '72.0.3622.0', - '71.0.3578.72', - '70.0.3538.120', - '72.0.3621.1', - '72.0.3621.0', - '71.0.3578.71', - '70.0.3538.119', - '72.0.3620.1', - '72.0.3620.0', - '71.0.3578.70', - '70.0.3538.118', - '71.0.3578.69', - '72.0.3619.1', - '72.0.3619.0', - '71.0.3578.68', - '70.0.3538.117', - '71.0.3578.67', - '72.0.3618.1', - '72.0.3618.0', - '71.0.3578.66', - '70.0.3538.116', - '72.0.3617.1', - '72.0.3617.0', - '71.0.3578.65', - '70.0.3538.115', - '72.0.3602.3', - '71.0.3578.64', - '72.0.3616.1', - '72.0.3616.0', - '71.0.3578.63', - '70.0.3538.114', - '71.0.3578.62', - '72.0.3615.1', - '72.0.3615.0', - '71.0.3578.61', - '70.0.3538.113', - '72.0.3614.1', - '72.0.3614.0', - '71.0.3578.60', - '70.0.3538.112', - '72.0.3613.1', - '72.0.3613.0', - '71.0.3578.59', - '70.0.3538.111', - '72.0.3612.2', - '72.0.3612.1', - '72.0.3612.0', - '70.0.3538.110', - '71.0.3578.58', - '70.0.3538.109', - '72.0.3611.2', - '72.0.3611.1', - '72.0.3611.0', - '71.0.3578.57', - '70.0.3538.108', - '72.0.3610.2', - '71.0.3578.56', - '71.0.3578.55', - '72.0.3610.1', - '72.0.3610.0', - '71.0.3578.54', - '70.0.3538.107', - '71.0.3578.53', - '72.0.3609.3', - '71.0.3578.52', - '72.0.3609.2', - '71.0.3578.51', - '72.0.3608.5', - '72.0.3609.1', - '72.0.3609.0', - '71.0.3578.50', - '70.0.3538.106', - '72.0.3608.4', - '72.0.3608.3', - '72.0.3608.2', - '71.0.3578.49', - '72.0.3608.1', - '72.0.3608.0', - '70.0.3538.105', - '71.0.3578.48', - '72.0.3607.1', - '72.0.3607.0', - '71.0.3578.47', - '70.0.3538.104', - '72.0.3606.2', - '72.0.3606.1', - '72.0.3606.0', - '71.0.3578.46', - '70.0.3538.103', - '70.0.3538.102', - '72.0.3605.3', - '72.0.3605.2', - '72.0.3605.1', - '72.0.3605.0', - '71.0.3578.45', - '70.0.3538.101', - '71.0.3578.44', - '71.0.3578.43', - '70.0.3538.100', - '70.0.3538.99', - '71.0.3578.42', - '72.0.3604.1', - '72.0.3604.0', - '71.0.3578.41', - '70.0.3538.98', - '71.0.3578.40', - '72.0.3603.2', - '72.0.3603.1', - '72.0.3603.0', - '71.0.3578.39', - '70.0.3538.97', - '72.0.3602.2', - '71.0.3578.38', - '71.0.3578.37', - '72.0.3602.1', - '72.0.3602.0', - '71.0.3578.36', - '70.0.3538.96', - '72.0.3601.1', - '72.0.3601.0', - '71.0.3578.35', - '70.0.3538.95', - '72.0.3600.1', - '72.0.3600.0', - '71.0.3578.34', - '70.0.3538.94', - '72.0.3599.3', - '72.0.3599.2', - '72.0.3599.1', - '72.0.3599.0', - '71.0.3578.33', - '70.0.3538.93', - '72.0.3598.1', - '72.0.3598.0', - '71.0.3578.32', - '70.0.3538.87', - '72.0.3597.1', - '72.0.3597.0', - '72.0.3596.2', - '71.0.3578.31', - '70.0.3538.86', - '71.0.3578.30', - '71.0.3578.29', - '72.0.3596.1', - '72.0.3596.0', - '71.0.3578.28', - '70.0.3538.85', - '72.0.3595.2', - '72.0.3591.3', - '72.0.3595.1', - '72.0.3595.0', - '71.0.3578.27', - '70.0.3538.84', - '72.0.3594.1', - '72.0.3594.0', - '71.0.3578.26', - '70.0.3538.83', - '72.0.3593.2', - '72.0.3593.1', - '72.0.3593.0', - '71.0.3578.25', - '70.0.3538.82', - '72.0.3589.3', - '72.0.3592.2', - '72.0.3592.1', - '72.0.3592.0', - '71.0.3578.24', - '72.0.3589.2', - '70.0.3538.81', - '70.0.3538.80', - '72.0.3591.2', - '72.0.3591.1', - '72.0.3591.0', - '71.0.3578.23', - '70.0.3538.79', - '71.0.3578.22', - '72.0.3590.1', - '72.0.3590.0', - '71.0.3578.21', - '70.0.3538.78', - '70.0.3538.77', - '72.0.3589.1', - '72.0.3589.0', - '71.0.3578.20', - '70.0.3538.76', - '71.0.3578.19', - '70.0.3538.75', - '72.0.3588.1', - '72.0.3588.0', - '71.0.3578.18', - '70.0.3538.74', - '72.0.3586.2', - '72.0.3587.0', - '71.0.3578.17', - '70.0.3538.73', - '72.0.3586.1', - '72.0.3586.0', - '71.0.3578.16', - '70.0.3538.72', - '72.0.3585.1', - '72.0.3585.0', - '71.0.3578.15', - '70.0.3538.71', - '71.0.3578.14', - '72.0.3584.1', - '72.0.3584.0', - '71.0.3578.13', - '70.0.3538.70', - '72.0.3583.2', - '71.0.3578.12', - '72.0.3583.1', - '72.0.3583.0', - '71.0.3578.11', - '70.0.3538.69', - '71.0.3578.10', - '72.0.3582.0', - '72.0.3581.4', - '71.0.3578.9', - '70.0.3538.67', - '72.0.3581.3', - '72.0.3581.2', - '72.0.3581.1', - '72.0.3581.0', - '71.0.3578.8', - '70.0.3538.66', - '72.0.3580.1', - '72.0.3580.0', - '71.0.3578.7', - '70.0.3538.65', - '71.0.3578.6', - '72.0.3579.1', - '72.0.3579.0', - '71.0.3578.5', - '70.0.3538.64', - '71.0.3578.4', - '71.0.3578.3', - '71.0.3578.2', - '71.0.3578.1', - '71.0.3578.0', - '70.0.3538.63', - '69.0.3497.128', - '70.0.3538.62', - '70.0.3538.61', - '70.0.3538.60', - '70.0.3538.59', - '71.0.3577.1', - '71.0.3577.0', - '70.0.3538.58', - '69.0.3497.127', - '71.0.3576.2', - '71.0.3576.1', - '71.0.3576.0', - '70.0.3538.57', - '70.0.3538.56', - '71.0.3575.2', - '70.0.3538.55', - '69.0.3497.126', - '70.0.3538.54', - '71.0.3575.1', - '71.0.3575.0', - '71.0.3574.1', - '71.0.3574.0', - '70.0.3538.53', - '69.0.3497.125', - '70.0.3538.52', - '71.0.3573.1', - '71.0.3573.0', - '70.0.3538.51', - '69.0.3497.124', - '71.0.3572.1', - '71.0.3572.0', - '70.0.3538.50', - '69.0.3497.123', - '71.0.3571.2', - '70.0.3538.49', - '69.0.3497.122', - '71.0.3571.1', - '71.0.3571.0', - '70.0.3538.48', - '69.0.3497.121', - '71.0.3570.1', - '71.0.3570.0', - '70.0.3538.47', - '69.0.3497.120', - '71.0.3568.2', - '71.0.3569.1', - '71.0.3569.0', - '70.0.3538.46', - '69.0.3497.119', - '70.0.3538.45', - '71.0.3568.1', - '71.0.3568.0', - '70.0.3538.44', - '69.0.3497.118', - '70.0.3538.43', - '70.0.3538.42', - '71.0.3567.1', - '71.0.3567.0', - '70.0.3538.41', - '69.0.3497.117', - '71.0.3566.1', - '71.0.3566.0', - '70.0.3538.40', - '69.0.3497.116', - '71.0.3565.1', - '71.0.3565.0', - '70.0.3538.39', - '69.0.3497.115', - '71.0.3564.1', - '71.0.3564.0', - '70.0.3538.38', - '69.0.3497.114', - '71.0.3563.0', - '71.0.3562.2', - '70.0.3538.37', - '69.0.3497.113', - '70.0.3538.36', - '70.0.3538.35', - '71.0.3562.1', - '71.0.3562.0', - '70.0.3538.34', - '69.0.3497.112', - '70.0.3538.33', - '71.0.3561.1', - '71.0.3561.0', - '70.0.3538.32', - '69.0.3497.111', - '71.0.3559.6', - '71.0.3560.1', - '71.0.3560.0', - '71.0.3559.5', - '71.0.3559.4', - '70.0.3538.31', - '69.0.3497.110', - '71.0.3559.3', - '70.0.3538.30', - '69.0.3497.109', - '71.0.3559.2', - '71.0.3559.1', - '71.0.3559.0', - '70.0.3538.29', - '69.0.3497.108', - '71.0.3558.2', - '71.0.3558.1', - '71.0.3558.0', - '70.0.3538.28', - '69.0.3497.107', - '71.0.3557.2', - '71.0.3557.1', - '71.0.3557.0', - '70.0.3538.27', - '69.0.3497.106', - '71.0.3554.4', - '70.0.3538.26', - '71.0.3556.1', - '71.0.3556.0', - '70.0.3538.25', - '71.0.3554.3', - '69.0.3497.105', - '71.0.3554.2', - '70.0.3538.24', - '69.0.3497.104', - '71.0.3555.2', - '70.0.3538.23', - '71.0.3555.1', - '71.0.3555.0', - '70.0.3538.22', - '69.0.3497.103', - '71.0.3554.1', - '71.0.3554.0', - '70.0.3538.21', - '69.0.3497.102', - '71.0.3553.3', - '70.0.3538.20', - '69.0.3497.101', - '71.0.3553.2', - '69.0.3497.100', - '71.0.3553.1', - '71.0.3553.0', - '70.0.3538.19', - '69.0.3497.99', - '69.0.3497.98', - '69.0.3497.97', - '71.0.3552.6', - '71.0.3552.5', - '71.0.3552.4', - '71.0.3552.3', - '71.0.3552.2', - '71.0.3552.1', - '71.0.3552.0', - '70.0.3538.18', - '69.0.3497.96', - '71.0.3551.3', - '71.0.3551.2', - '71.0.3551.1', - '71.0.3551.0', - '70.0.3538.17', - '69.0.3497.95', - '71.0.3550.3', - '71.0.3550.2', - '71.0.3550.1', - '71.0.3550.0', - '70.0.3538.16', - '69.0.3497.94', - '71.0.3549.1', - '71.0.3549.0', - '70.0.3538.15', - '69.0.3497.93', - '69.0.3497.92', - '71.0.3548.1', - '71.0.3548.0', - '70.0.3538.14', - '69.0.3497.91', - '71.0.3547.1', - '71.0.3547.0', - '70.0.3538.13', - '69.0.3497.90', - '71.0.3546.2', - '69.0.3497.89', - '71.0.3546.1', - '71.0.3546.0', - '70.0.3538.12', - '69.0.3497.88', - '71.0.3545.4', - '71.0.3545.3', - '71.0.3545.2', - '71.0.3545.1', - '71.0.3545.0', - '70.0.3538.11', - '69.0.3497.87', - '71.0.3544.5', - '71.0.3544.4', - '71.0.3544.3', - '71.0.3544.2', - '71.0.3544.1', - '71.0.3544.0', - '69.0.3497.86', - '70.0.3538.10', - '69.0.3497.85', - '70.0.3538.9', - '69.0.3497.84', - '71.0.3543.4', - '70.0.3538.8', - '71.0.3543.3', - '71.0.3543.2', - '71.0.3543.1', - '71.0.3543.0', - '70.0.3538.7', - '69.0.3497.83', - '71.0.3542.2', - '71.0.3542.1', - '71.0.3542.0', - '70.0.3538.6', - '69.0.3497.82', - '69.0.3497.81', - '71.0.3541.1', - '71.0.3541.0', - '70.0.3538.5', - '69.0.3497.80', - '71.0.3540.1', - '71.0.3540.0', - '70.0.3538.4', - '69.0.3497.79', - '70.0.3538.3', - '71.0.3539.1', - '71.0.3539.0', - '69.0.3497.78', - '68.0.3440.134', - '69.0.3497.77', - '70.0.3538.2', - '70.0.3538.1', - '70.0.3538.0', - '69.0.3497.76', - '68.0.3440.133', - '69.0.3497.75', - '70.0.3537.2', - '70.0.3537.1', - '70.0.3537.0', - '69.0.3497.74', - '68.0.3440.132', - '70.0.3536.0', - '70.0.3535.5', - '70.0.3535.4', - '70.0.3535.3', - '69.0.3497.73', - '68.0.3440.131', - '70.0.3532.8', - '70.0.3532.7', - '69.0.3497.72', - '69.0.3497.71', - '70.0.3535.2', - '70.0.3535.1', - '70.0.3535.0', - '69.0.3497.70', - '68.0.3440.130', - '69.0.3497.69', - '68.0.3440.129', - '70.0.3534.4', - '70.0.3534.3', - '70.0.3534.2', - '70.0.3534.1', - '70.0.3534.0', - '69.0.3497.68', - '68.0.3440.128', - '70.0.3533.2', - '70.0.3533.1', - '70.0.3533.0', - '69.0.3497.67', - '68.0.3440.127', - '70.0.3532.6', - '70.0.3532.5', - '70.0.3532.4', - '69.0.3497.66', - '68.0.3440.126', - '70.0.3532.3', - '70.0.3532.2', - '70.0.3532.1', - '69.0.3497.60', - '69.0.3497.65', - '69.0.3497.64', - '70.0.3532.0', - '70.0.3531.0', - '70.0.3530.4', - '70.0.3530.3', - '70.0.3530.2', - '69.0.3497.58', - '68.0.3440.125', - '69.0.3497.57', - '69.0.3497.56', - '69.0.3497.55', - '69.0.3497.54', - '70.0.3530.1', - '70.0.3530.0', - '69.0.3497.53', - '68.0.3440.124', - '69.0.3497.52', - '70.0.3529.3', - '70.0.3529.2', - '70.0.3529.1', - '70.0.3529.0', - '69.0.3497.51', - '70.0.3528.4', - '68.0.3440.123', - '70.0.3528.3', - '70.0.3528.2', - '70.0.3528.1', - '70.0.3528.0', - '69.0.3497.50', - '68.0.3440.122', - '70.0.3527.1', - '70.0.3527.0', - '69.0.3497.49', - '68.0.3440.121', - '70.0.3526.1', - '70.0.3526.0', - '68.0.3440.120', - '69.0.3497.48', - '69.0.3497.47', - '68.0.3440.119', - '68.0.3440.118', - '70.0.3525.5', - '70.0.3525.4', - '70.0.3525.3', - '68.0.3440.117', - '69.0.3497.46', - '70.0.3525.2', - '70.0.3525.1', - '70.0.3525.0', - '69.0.3497.45', - '68.0.3440.116', - '70.0.3524.4', - '70.0.3524.3', - '69.0.3497.44', - '70.0.3524.2', - '70.0.3524.1', - '70.0.3524.0', - '70.0.3523.2', - '69.0.3497.43', - '68.0.3440.115', - '70.0.3505.9', - '69.0.3497.42', - '70.0.3505.8', - '70.0.3523.1', - '70.0.3523.0', - '69.0.3497.41', - '68.0.3440.114', - '70.0.3505.7', - '69.0.3497.40', - '70.0.3522.1', - '70.0.3522.0', - '70.0.3521.2', - '69.0.3497.39', - '68.0.3440.113', - '70.0.3505.6', - '70.0.3521.1', - '70.0.3521.0', - '69.0.3497.38', - '68.0.3440.112', - '70.0.3520.1', - '70.0.3520.0', - '69.0.3497.37', - '68.0.3440.111', - '70.0.3519.3', - '70.0.3519.2', - '70.0.3519.1', - '70.0.3519.0', - '69.0.3497.36', - '68.0.3440.110', - '70.0.3518.1', - '70.0.3518.0', - '69.0.3497.35', - '69.0.3497.34', - '68.0.3440.109', - '70.0.3517.1', - '70.0.3517.0', - '69.0.3497.33', - '68.0.3440.108', - '69.0.3497.32', - '70.0.3516.3', - '70.0.3516.2', - '70.0.3516.1', - '70.0.3516.0', - '69.0.3497.31', - '68.0.3440.107', - '70.0.3515.4', - '68.0.3440.106', - '70.0.3515.3', - '70.0.3515.2', - '70.0.3515.1', - '70.0.3515.0', - '69.0.3497.30', - '68.0.3440.105', + '68.0.3440.103', '68.0.3440.104', - '70.0.3514.2', - '70.0.3514.1', - '70.0.3514.0', + '68.0.3440.105', + '68.0.3440.106', + '68.0.3440.107', + '68.0.3440.108', + '68.0.3440.109', + '68.0.3440.110', + '68.0.3440.111', + '68.0.3440.112', + '68.0.3440.113', + '68.0.3440.114', + '68.0.3440.115', + '68.0.3440.116', + '68.0.3440.117', + '68.0.3440.118', + '68.0.3440.119', + '68.0.3440.120', + '68.0.3440.121', + '68.0.3440.122', + '68.0.3440.123', + '68.0.3440.124', + '68.0.3440.125', + '68.0.3440.126', + '68.0.3440.127', + '68.0.3440.128', + '68.0.3440.129', + '68.0.3440.130', + '68.0.3440.131', + '68.0.3440.132', + '68.0.3440.133', + '68.0.3440.134', + '69.0.3497.100', + '69.0.3497.101', + '69.0.3497.102', + '69.0.3497.103', + '69.0.3497.104', + '69.0.3497.105', + '69.0.3497.106', + '69.0.3497.107', + '69.0.3497.108', + '69.0.3497.109', + '69.0.3497.110', + '69.0.3497.111', + '69.0.3497.112', + '69.0.3497.113', + '69.0.3497.114', + '69.0.3497.115', + '69.0.3497.116', + '69.0.3497.117', + '69.0.3497.118', + '69.0.3497.119', + '69.0.3497.120', + '69.0.3497.121', + '69.0.3497.122', + '69.0.3497.123', + '69.0.3497.124', + '69.0.3497.125', + '69.0.3497.126', + '69.0.3497.127', + '69.0.3497.128', + '69.0.3497.28', '69.0.3497.29', - '68.0.3440.103', - '70.0.3513.1', + '69.0.3497.30', + '69.0.3497.31', + '69.0.3497.32', + '69.0.3497.33', + '69.0.3497.34', + '69.0.3497.35', + '69.0.3497.36', + '69.0.3497.37', + '69.0.3497.38', + '69.0.3497.39', + '69.0.3497.40', + '69.0.3497.41', + '69.0.3497.42', + '69.0.3497.43', + '69.0.3497.44', + '69.0.3497.45', + '69.0.3497.46', + '69.0.3497.47', + '69.0.3497.48', + '69.0.3497.49', + '69.0.3497.50', + '69.0.3497.51', + '69.0.3497.52', + '69.0.3497.53', + '69.0.3497.54', + '69.0.3497.55', + '69.0.3497.56', + '69.0.3497.57', + '69.0.3497.58', + '69.0.3497.60', + '69.0.3497.64', + '69.0.3497.65', + '69.0.3497.66', + '69.0.3497.67', + '69.0.3497.68', + '69.0.3497.69', + '69.0.3497.70', + '69.0.3497.71', + '69.0.3497.72', + '69.0.3497.73', + '69.0.3497.74', + '69.0.3497.75', + '69.0.3497.76', + '69.0.3497.77', + '69.0.3497.78', + '69.0.3497.79', + '69.0.3497.80', + '69.0.3497.81', + '69.0.3497.82', + '69.0.3497.83', + '69.0.3497.84', + '69.0.3497.85', + '69.0.3497.86', + '69.0.3497.87', + '69.0.3497.88', + '69.0.3497.89', + '69.0.3497.90', + '69.0.3497.91', + '69.0.3497.92', + '69.0.3497.93', + '69.0.3497.94', + '69.0.3497.95', + '69.0.3497.96', + '69.0.3497.97', + '69.0.3497.98', + '69.0.3497.99', + '70.0.3505.6', + '70.0.3505.7', + '70.0.3505.8', + '70.0.3505.9', '70.0.3513.0', - '69.0.3497.28', + '70.0.3513.1', + '70.0.3514.0', + '70.0.3514.1', + '70.0.3514.2', + '70.0.3515.0', + '70.0.3515.1', + '70.0.3515.2', + '70.0.3515.3', + '70.0.3515.4', + '70.0.3516.0', + '70.0.3516.1', + '70.0.3516.2', + '70.0.3516.3', + '70.0.3517.0', + '70.0.3517.1', + '70.0.3518.0', + '70.0.3518.1', + '70.0.3519.0', + '70.0.3519.1', + '70.0.3519.2', + '70.0.3519.3', + '70.0.3520.0', + '70.0.3520.1', + '70.0.3521.0', + '70.0.3521.1', + '70.0.3521.2', + '70.0.3522.0', + '70.0.3522.1', + '70.0.3523.0', + '70.0.3523.1', + '70.0.3523.2', + '70.0.3524.0', + '70.0.3524.1', + '70.0.3524.2', + '70.0.3524.3', + '70.0.3524.4', + '70.0.3525.0', + '70.0.3525.1', + '70.0.3525.2', + '70.0.3525.3', + '70.0.3525.4', + '70.0.3525.5', + '70.0.3526.0', + '70.0.3526.1', + '70.0.3527.0', + '70.0.3527.1', + '70.0.3528.0', + '70.0.3528.1', + '70.0.3528.2', + '70.0.3528.3', + '70.0.3528.4', + '70.0.3529.0', + '70.0.3529.1', + '70.0.3529.2', + '70.0.3529.3', + '70.0.3530.0', + '70.0.3530.1', + '70.0.3530.2', + '70.0.3530.3', + '70.0.3530.4', + '70.0.3531.0', + '70.0.3532.0', + '70.0.3532.1', + '70.0.3532.2', + '70.0.3532.3', + '70.0.3532.4', + '70.0.3532.5', + '70.0.3532.6', + '70.0.3532.7', + '70.0.3532.8', + '70.0.3533.0', + '70.0.3533.1', + '70.0.3533.2', + '70.0.3534.0', + '70.0.3534.1', + '70.0.3534.2', + '70.0.3534.3', + '70.0.3534.4', + '70.0.3535.0', + '70.0.3535.1', + '70.0.3535.2', + '70.0.3535.3', + '70.0.3535.4', + '70.0.3535.5', + '70.0.3536.0', + '70.0.3537.0', + '70.0.3537.1', + '70.0.3537.2', + '70.0.3538.0', + '70.0.3538.1', + '70.0.3538.10', + '70.0.3538.100', + '70.0.3538.101', + '70.0.3538.102', + '70.0.3538.103', + '70.0.3538.104', + '70.0.3538.105', + '70.0.3538.106', + '70.0.3538.107', + '70.0.3538.108', + '70.0.3538.109', + '70.0.3538.11', + '70.0.3538.110', + '70.0.3538.111', + '70.0.3538.112', + '70.0.3538.113', + '70.0.3538.114', + '70.0.3538.115', + '70.0.3538.116', + '70.0.3538.117', + '70.0.3538.118', + '70.0.3538.119', + '70.0.3538.12', + '70.0.3538.120', + '70.0.3538.121', + '70.0.3538.122', + '70.0.3538.123', + '70.0.3538.124', + '70.0.3538.13', + '70.0.3538.14', + '70.0.3538.15', + '70.0.3538.16', + '70.0.3538.17', + '70.0.3538.18', + '70.0.3538.19', + '70.0.3538.2', + '70.0.3538.20', + '70.0.3538.21', + '70.0.3538.22', + '70.0.3538.23', + '70.0.3538.24', + '70.0.3538.25', + '70.0.3538.26', + '70.0.3538.27', + '70.0.3538.28', + '70.0.3538.29', + '70.0.3538.3', + '70.0.3538.30', + '70.0.3538.31', + '70.0.3538.32', + '70.0.3538.33', + '70.0.3538.34', + '70.0.3538.35', + '70.0.3538.36', + '70.0.3538.37', + '70.0.3538.38', + '70.0.3538.39', + '70.0.3538.4', + '70.0.3538.40', + '70.0.3538.41', + '70.0.3538.42', + '70.0.3538.43', + '70.0.3538.44', + '70.0.3538.45', + '70.0.3538.46', + '70.0.3538.47', + '70.0.3538.48', + '70.0.3538.49', + '70.0.3538.5', + '70.0.3538.50', + '70.0.3538.51', + '70.0.3538.52', + '70.0.3538.53', + '70.0.3538.54', + '70.0.3538.55', + '70.0.3538.56', + '70.0.3538.57', + '70.0.3538.58', + '70.0.3538.59', + '70.0.3538.6', + '70.0.3538.60', + '70.0.3538.61', + '70.0.3538.62', + '70.0.3538.63', + '70.0.3538.64', + '70.0.3538.65', + '70.0.3538.66', + '70.0.3538.67', + '70.0.3538.69', + '70.0.3538.7', + '70.0.3538.70', + '70.0.3538.71', + '70.0.3538.72', + '70.0.3538.73', + '70.0.3538.74', + '70.0.3538.75', + '70.0.3538.76', + '70.0.3538.77', + '70.0.3538.78', + '70.0.3538.79', + '70.0.3538.8', + '70.0.3538.80', + '70.0.3538.81', + '70.0.3538.82', + '70.0.3538.83', + '70.0.3538.84', + '70.0.3538.85', + '70.0.3538.86', + '70.0.3538.87', + '70.0.3538.9', + '70.0.3538.93', + '70.0.3538.94', + '70.0.3538.95', + '70.0.3538.96', + '70.0.3538.97', + '70.0.3538.98', + '70.0.3538.99', + '71.0.3539.0', + '71.0.3539.1', + '71.0.3540.0', + '71.0.3540.1', + '71.0.3541.0', + '71.0.3541.1', + '71.0.3542.0', + '71.0.3542.1', + '71.0.3542.2', + '71.0.3543.0', + '71.0.3543.1', + '71.0.3543.2', + '71.0.3543.3', + '71.0.3543.4', + '71.0.3544.0', + '71.0.3544.1', + '71.0.3544.2', + '71.0.3544.3', + '71.0.3544.4', + '71.0.3544.5', + '71.0.3545.0', + '71.0.3545.1', + '71.0.3545.2', + '71.0.3545.3', + '71.0.3545.4', + '71.0.3546.0', + '71.0.3546.1', + '71.0.3546.2', + '71.0.3547.0', + '71.0.3547.1', + '71.0.3548.0', + '71.0.3548.1', + '71.0.3549.0', + '71.0.3549.1', + '71.0.3550.0', + '71.0.3550.1', + '71.0.3550.2', + '71.0.3550.3', + '71.0.3551.0', + '71.0.3551.1', + '71.0.3551.2', + '71.0.3551.3', + '71.0.3552.0', + '71.0.3552.1', + '71.0.3552.2', + '71.0.3552.3', + '71.0.3552.4', + '71.0.3552.5', + '71.0.3552.6', + '71.0.3553.0', + '71.0.3553.1', + '71.0.3553.2', + '71.0.3553.3', + '71.0.3554.0', + '71.0.3554.1', + '71.0.3554.2', + '71.0.3554.3', + '71.0.3554.4', + '71.0.3555.0', + '71.0.3555.1', + '71.0.3555.2', + '71.0.3556.0', + '71.0.3556.1', + '71.0.3557.0', + '71.0.3557.1', + '71.0.3557.2', + '71.0.3558.0', + '71.0.3558.1', + '71.0.3558.2', + '71.0.3559.0', + '71.0.3559.1', + '71.0.3559.2', + '71.0.3559.3', + '71.0.3559.4', + '71.0.3559.5', + '71.0.3559.6', + '71.0.3560.0', + '71.0.3560.1', + '71.0.3561.0', + '71.0.3561.1', + '71.0.3562.0', + '71.0.3562.1', + '71.0.3562.2', + '71.0.3563.0', + '71.0.3564.0', + '71.0.3564.1', + '71.0.3565.0', + '71.0.3565.1', + '71.0.3566.0', + '71.0.3566.1', + '71.0.3567.0', + '71.0.3567.1', + '71.0.3568.0', + '71.0.3568.1', + '71.0.3568.2', + '71.0.3569.0', + '71.0.3569.1', + '71.0.3570.0', + '71.0.3570.1', + '71.0.3571.0', + '71.0.3571.1', + '71.0.3571.2', + '71.0.3572.0', + '71.0.3572.1', + '71.0.3573.0', + '71.0.3573.1', + '71.0.3574.0', + '71.0.3574.1', + '71.0.3575.0', + '71.0.3575.1', + '71.0.3575.2', + '71.0.3576.0', + '71.0.3576.1', + '71.0.3576.2', + '71.0.3577.0', + '71.0.3577.1', + '71.0.3578.0', + '71.0.3578.1', + '71.0.3578.10', + '71.0.3578.100', + '71.0.3578.101', + '71.0.3578.102', + '71.0.3578.103', + '71.0.3578.104', + '71.0.3578.105', + '71.0.3578.106', + '71.0.3578.107', + '71.0.3578.108', + '71.0.3578.109', + '71.0.3578.11', + '71.0.3578.110', + '71.0.3578.111', + '71.0.3578.112', + '71.0.3578.113', + '71.0.3578.114', + '71.0.3578.115', + '71.0.3578.116', + '71.0.3578.117', + '71.0.3578.118', + '71.0.3578.119', + '71.0.3578.12', + '71.0.3578.120', + '71.0.3578.121', + '71.0.3578.122', + '71.0.3578.123', + '71.0.3578.124', + '71.0.3578.125', + '71.0.3578.126', + '71.0.3578.127', + '71.0.3578.128', + '71.0.3578.129', + '71.0.3578.13', + '71.0.3578.130', + '71.0.3578.131', + '71.0.3578.132', + '71.0.3578.133', + '71.0.3578.134', + '71.0.3578.135', + '71.0.3578.136', + '71.0.3578.137', + '71.0.3578.138', + '71.0.3578.139', + '71.0.3578.14', + '71.0.3578.140', + '71.0.3578.141', + '71.0.3578.15', + '71.0.3578.16', + '71.0.3578.17', + '71.0.3578.18', + '71.0.3578.19', + '71.0.3578.2', + '71.0.3578.20', + '71.0.3578.21', + '71.0.3578.22', + '71.0.3578.23', + '71.0.3578.24', + '71.0.3578.25', + '71.0.3578.26', + '71.0.3578.27', + '71.0.3578.28', + '71.0.3578.29', + '71.0.3578.3', + '71.0.3578.30', + '71.0.3578.31', + '71.0.3578.32', + '71.0.3578.33', + '71.0.3578.34', + '71.0.3578.35', + '71.0.3578.36', + '71.0.3578.37', + '71.0.3578.38', + '71.0.3578.39', + '71.0.3578.4', + '71.0.3578.40', + '71.0.3578.41', + '71.0.3578.42', + '71.0.3578.43', + '71.0.3578.44', + '71.0.3578.45', + '71.0.3578.46', + '71.0.3578.47', + '71.0.3578.48', + '71.0.3578.49', + '71.0.3578.5', + '71.0.3578.50', + '71.0.3578.51', + '71.0.3578.52', + '71.0.3578.53', + '71.0.3578.54', + '71.0.3578.55', + '71.0.3578.56', + '71.0.3578.57', + '71.0.3578.58', + '71.0.3578.59', + '71.0.3578.6', + '71.0.3578.60', + '71.0.3578.61', + '71.0.3578.62', + '71.0.3578.63', + '71.0.3578.64', + '71.0.3578.65', + '71.0.3578.66', + '71.0.3578.67', + '71.0.3578.68', + '71.0.3578.69', + '71.0.3578.7', + '71.0.3578.70', + '71.0.3578.71', + '71.0.3578.72', + '71.0.3578.73', + '71.0.3578.74', + '71.0.3578.75', + '71.0.3578.76', + '71.0.3578.77', + '71.0.3578.78', + '71.0.3578.79', + '71.0.3578.8', + '71.0.3578.80', + '71.0.3578.81', + '71.0.3578.82', + '71.0.3578.83', + '71.0.3578.84', + '71.0.3578.85', + '71.0.3578.86', + '71.0.3578.87', + '71.0.3578.88', + '71.0.3578.89', + '71.0.3578.9', + '71.0.3578.90', + '71.0.3578.91', + '71.0.3578.92', + '71.0.3578.93', + '71.0.3578.94', + '71.0.3578.95', + '71.0.3578.96', + '71.0.3578.97', + '71.0.3578.98', + '71.0.3578.99', + '72.0.3579.0', + '72.0.3579.1', + '72.0.3580.0', + '72.0.3580.1', + '72.0.3581.0', + '72.0.3581.1', + '72.0.3581.2', + '72.0.3581.3', + '72.0.3581.4', + '72.0.3582.0', + '72.0.3583.0', + '72.0.3583.1', + '72.0.3583.2', + '72.0.3584.0', + '72.0.3584.1', + '72.0.3585.0', + '72.0.3585.1', + '72.0.3586.0', + '72.0.3586.1', + '72.0.3586.2', + '72.0.3587.0', + '72.0.3588.0', + '72.0.3588.1', + '72.0.3589.0', + '72.0.3589.1', + '72.0.3589.2', + '72.0.3589.3', + '72.0.3590.0', + '72.0.3590.1', + '72.0.3591.0', + '72.0.3591.1', + '72.0.3591.2', + '72.0.3591.3', + '72.0.3592.0', + '72.0.3592.1', + '72.0.3592.2', + '72.0.3593.0', + '72.0.3593.1', + '72.0.3593.2', + '72.0.3594.0', + '72.0.3594.1', + '72.0.3595.0', + '72.0.3595.1', + '72.0.3595.2', + '72.0.3596.0', + '72.0.3596.1', + '72.0.3596.2', + '72.0.3597.0', + '72.0.3597.1', + '72.0.3598.0', + '72.0.3598.1', + '72.0.3599.0', + '72.0.3599.1', + '72.0.3599.2', + '72.0.3599.3', + '72.0.3600.0', + '72.0.3600.1', + '72.0.3601.0', + '72.0.3601.1', + '72.0.3602.0', + '72.0.3602.1', + '72.0.3602.2', + '72.0.3602.3', + '72.0.3603.0', + '72.0.3603.1', + '72.0.3603.2', + '72.0.3604.0', + '72.0.3604.1', + '72.0.3605.0', + '72.0.3605.1', + '72.0.3605.2', + '72.0.3605.3', + '72.0.3606.0', + '72.0.3606.1', + '72.0.3606.2', + '72.0.3607.0', + '72.0.3607.1', + '72.0.3608.0', + '72.0.3608.1', + '72.0.3608.2', + '72.0.3608.3', + '72.0.3608.4', + '72.0.3608.5', + '72.0.3609.0', + '72.0.3609.1', + '72.0.3609.2', + '72.0.3609.3', + '72.0.3610.0', + '72.0.3610.1', + '72.0.3610.2', + '72.0.3610.3', + '72.0.3610.4', + '72.0.3611.0', + '72.0.3611.1', + '72.0.3611.2', + '72.0.3612.0', + '72.0.3612.1', + '72.0.3612.2', + '72.0.3613.0', + '72.0.3613.1', + '72.0.3614.0', + '72.0.3614.1', + '72.0.3615.0', + '72.0.3615.1', + '72.0.3616.0', + '72.0.3616.1', + '72.0.3617.0', + '72.0.3617.1', + '72.0.3618.0', + '72.0.3618.1', + '72.0.3619.0', + '72.0.3619.1', + '72.0.3620.0', + '72.0.3620.1', + '72.0.3621.0', + '72.0.3621.1', + '72.0.3622.0', + '72.0.3622.1', + '72.0.3622.2', + '72.0.3622.3', + '72.0.3623.0', + '72.0.3623.1', + '72.0.3623.2', + '72.0.3623.3', + '72.0.3623.4', + '72.0.3624.0', + '72.0.3624.1', + '72.0.3624.2', + '72.0.3624.3', + '72.0.3624.4', + '72.0.3625.0', + '72.0.3625.1', + '72.0.3625.2', + '72.0.3626.0', + '72.0.3626.1', + '72.0.3626.10', + '72.0.3626.100', + '72.0.3626.101', + '72.0.3626.102', + '72.0.3626.103', + '72.0.3626.105', + '72.0.3626.107', + '72.0.3626.108', + '72.0.3626.109', + '72.0.3626.11', + '72.0.3626.110', + '72.0.3626.111', + '72.0.3626.112', + '72.0.3626.113', + '72.0.3626.114', + '72.0.3626.115', + '72.0.3626.116', + '72.0.3626.117', + '72.0.3626.118', + '72.0.3626.119', + '72.0.3626.12', + '72.0.3626.120', + '72.0.3626.121', + '72.0.3626.122', + '72.0.3626.13', + '72.0.3626.14', + '72.0.3626.15', + '72.0.3626.16', + '72.0.3626.17', + '72.0.3626.18', + '72.0.3626.19', + '72.0.3626.2', + '72.0.3626.20', + '72.0.3626.21', + '72.0.3626.22', + '72.0.3626.23', + '72.0.3626.24', + '72.0.3626.25', + '72.0.3626.26', + '72.0.3626.27', + '72.0.3626.28', + '72.0.3626.29', + '72.0.3626.3', + '72.0.3626.30', + '72.0.3626.31', + '72.0.3626.32', + '72.0.3626.33', + '72.0.3626.34', + '72.0.3626.35', + '72.0.3626.36', + '72.0.3626.37', + '72.0.3626.38', + '72.0.3626.39', + '72.0.3626.4', + '72.0.3626.40', + '72.0.3626.41', + '72.0.3626.42', + '72.0.3626.43', + '72.0.3626.44', + '72.0.3626.45', + '72.0.3626.46', + '72.0.3626.47', + '72.0.3626.48', + '72.0.3626.49', + '72.0.3626.5', + '72.0.3626.50', + '72.0.3626.51', + '72.0.3626.52', + '72.0.3626.53', + '72.0.3626.54', + '72.0.3626.55', + '72.0.3626.56', + '72.0.3626.57', + '72.0.3626.58', + '72.0.3626.59', + '72.0.3626.6', + '72.0.3626.60', + '72.0.3626.61', + '72.0.3626.62', + '72.0.3626.63', + '72.0.3626.64', + '72.0.3626.65', + '72.0.3626.66', + '72.0.3626.67', + '72.0.3626.68', + '72.0.3626.69', + '72.0.3626.7', + '72.0.3626.70', + '72.0.3626.71', + '72.0.3626.72', + '72.0.3626.73', + '72.0.3626.74', + '72.0.3626.75', + '72.0.3626.76', + '72.0.3626.77', + '72.0.3626.78', + '72.0.3626.79', + '72.0.3626.8', + '72.0.3626.80', + '72.0.3626.81', + '72.0.3626.82', + '72.0.3626.83', + '72.0.3626.84', + '72.0.3626.85', + '72.0.3626.86', + '72.0.3626.87', + '72.0.3626.88', + '72.0.3626.89', + '72.0.3626.9', + '72.0.3626.90', + '72.0.3626.91', + '72.0.3626.92', + '72.0.3626.93', + '72.0.3626.94', + '72.0.3626.95', + '72.0.3626.96', + '72.0.3626.97', + '72.0.3626.98', + '72.0.3626.99', + '73.0.3627.0', + '73.0.3627.1', + '73.0.3628.0', + '73.0.3628.1', + '73.0.3628.2', + '73.0.3628.3', + '73.0.3629.0', + '73.0.3629.1', + '73.0.3630.0', + '73.0.3630.1', + '73.0.3631.0', + '73.0.3631.1', + '73.0.3631.2', + '73.0.3632.0', + '73.0.3632.1', + '73.0.3632.2', + '73.0.3632.3', + '73.0.3632.4', + '73.0.3632.5', + '73.0.3633.0', + '73.0.3633.1', + '73.0.3633.2', + '73.0.3634.0', + '73.0.3634.1', + '73.0.3634.2', + '73.0.3635.0', + '73.0.3635.1', + '73.0.3635.2', + '73.0.3635.3', + '73.0.3636.0', + '73.0.3636.1', + '73.0.3636.2', + '73.0.3637.0', + '73.0.3637.1', + '73.0.3638.0', + '73.0.3638.1', + '73.0.3638.2', + '73.0.3639.0', + '73.0.3639.1', + '73.0.3640.0', + '73.0.3640.1', + '73.0.3641.0', + '73.0.3641.1', + '73.0.3642.0', + '73.0.3642.1', + '73.0.3643.0', + '73.0.3643.1', + '73.0.3643.2', + '73.0.3644.0', + '73.0.3645.0', + '73.0.3645.1', + '73.0.3645.2', + '73.0.3646.0', + '73.0.3646.1', + '73.0.3646.2', + '73.0.3647.0', + '73.0.3647.1', + '73.0.3647.2', + '73.0.3648.0', + '73.0.3648.1', + '73.0.3648.2', + '73.0.3649.0', + '73.0.3649.1', + '73.0.3650.0', + '73.0.3650.1', + '73.0.3651.0', + '73.0.3651.1', + '73.0.3652.0', + '73.0.3652.1', + '73.0.3653.0', + '73.0.3653.1', + '73.0.3654.0', + '73.0.3654.1', + '73.0.3655.0', + '73.0.3655.1', + '73.0.3656.0', + '73.0.3656.1', + '73.0.3657.0', + '73.0.3657.1', + '73.0.3658.0', + '73.0.3658.1', + '73.0.3659.0', + '73.0.3659.1', + '73.0.3660.0', + '73.0.3660.1', + '73.0.3660.2', + '73.0.3661.0', + '73.0.3661.1', + '73.0.3662.0', + '73.0.3662.1', + '73.0.3663.0', + '73.0.3663.1', + '73.0.3663.2', + '73.0.3664.0', + '73.0.3664.1', + '73.0.3664.2', + '73.0.3664.3', + '73.0.3664.4', + '73.0.3665.0', + '73.0.3665.1', + '73.0.3665.2', + '73.0.3665.3', + '73.0.3665.4', + '73.0.3666.0', + '73.0.3666.1', + '73.0.3667.0', + '73.0.3667.1', + '73.0.3667.2', + '73.0.3668.0', + '73.0.3668.1', + '73.0.3668.2', + '73.0.3669.0', + '73.0.3669.1', + '73.0.3670.0', + '73.0.3670.1', + '73.0.3671.0', + '73.0.3671.1', + '73.0.3671.2', + '73.0.3671.3', + '73.0.3672.0', + '73.0.3672.1', + '73.0.3673.0', + '73.0.3673.1', + '73.0.3673.2', + '73.0.3674.0', + '73.0.3674.1', + '73.0.3674.2', + '73.0.3676.0', + '73.0.3676.1', + '73.0.3677.0', + '73.0.3677.1', + '73.0.3678.0', + '73.0.3678.1', + '73.0.3678.2', + '73.0.3679.0', + '73.0.3679.1', + '73.0.3680.0', + '73.0.3680.1', + '73.0.3681.0', + '73.0.3681.1', + '73.0.3681.2', + '73.0.3681.3', + '73.0.3681.4', + '73.0.3682.0', + '73.0.3682.1', + '73.0.3683.0', + '73.0.3683.1', + '73.0.3683.10', + '73.0.3683.100', + '73.0.3683.101', + '73.0.3683.102', + '73.0.3683.103', + '73.0.3683.104', + '73.0.3683.105', + '73.0.3683.106', + '73.0.3683.107', + '73.0.3683.108', + '73.0.3683.109', + '73.0.3683.11', + '73.0.3683.110', + '73.0.3683.111', + '73.0.3683.112', + '73.0.3683.113', + '73.0.3683.114', + '73.0.3683.115', + '73.0.3683.116', + '73.0.3683.117', + '73.0.3683.118', + '73.0.3683.119', + '73.0.3683.12', + '73.0.3683.120', + '73.0.3683.121', + '73.0.3683.13', + '73.0.3683.14', + '73.0.3683.15', + '73.0.3683.16', + '73.0.3683.17', + '73.0.3683.18', + '73.0.3683.19', + '73.0.3683.2', + '73.0.3683.20', + '73.0.3683.21', + '73.0.3683.22', + '73.0.3683.23', + '73.0.3683.24', + '73.0.3683.25', + '73.0.3683.26', + '73.0.3683.27', + '73.0.3683.28', + '73.0.3683.29', + '73.0.3683.3', + '73.0.3683.31', + '73.0.3683.32', + '73.0.3683.33', + '73.0.3683.34', + '73.0.3683.35', + '73.0.3683.36', + '73.0.3683.37', + '73.0.3683.38', + '73.0.3683.39', + '73.0.3683.4', + '73.0.3683.40', + '73.0.3683.41', + '73.0.3683.42', + '73.0.3683.43', + '73.0.3683.44', + '73.0.3683.45', + '73.0.3683.46', + '73.0.3683.47', + '73.0.3683.48', + '73.0.3683.49', + '73.0.3683.5', + '73.0.3683.50', + '73.0.3683.51', + '73.0.3683.52', + '73.0.3683.53', + '73.0.3683.54', + '73.0.3683.55', + '73.0.3683.56', + '73.0.3683.57', + '73.0.3683.58', + '73.0.3683.59', + '73.0.3683.6', + '73.0.3683.60', + '73.0.3683.61', + '73.0.3683.62', + '73.0.3683.63', + '73.0.3683.64', + '73.0.3683.65', + '73.0.3683.66', + '73.0.3683.67', + '73.0.3683.68', + '73.0.3683.69', + '73.0.3683.7', + '73.0.3683.70', + '73.0.3683.71', + '73.0.3683.72', + '73.0.3683.73', + '73.0.3683.74', + '73.0.3683.75', + '73.0.3683.76', + '73.0.3683.77', + '73.0.3683.78', + '73.0.3683.79', + '73.0.3683.8', + '73.0.3683.80', + '73.0.3683.81', + '73.0.3683.82', + '73.0.3683.83', + '73.0.3683.84', + '73.0.3683.85', + '73.0.3683.86', + '73.0.3683.87', + '73.0.3683.88', + '73.0.3683.89', + '73.0.3683.9', + '73.0.3683.90', + '73.0.3683.91', + '73.0.3683.92', + '73.0.3683.93', + '73.0.3683.94', + '73.0.3683.95', + '73.0.3683.96', + '73.0.3683.97', + '73.0.3683.98', + '73.0.3683.99', + '74.0.3684.0', + '74.0.3684.1', + '74.0.3685.0', + '74.0.3685.1', + '74.0.3686.0', + '74.0.3686.1', + '74.0.3686.2', + '74.0.3686.3', + '74.0.3686.4', + '74.0.3687.0', + '74.0.3687.1', + '74.0.3687.2', + '74.0.3687.3', + '74.0.3688.0', + '74.0.3688.1', + '74.0.3689.0', + '74.0.3689.1', + '74.0.3690.0', + '74.0.3690.1', + '74.0.3691.0', + '74.0.3691.1', + '74.0.3692.0', + '74.0.3692.1', + '74.0.3693.0', + '74.0.3693.1', + '74.0.3693.2', + '74.0.3693.3', + '74.0.3693.4', + '74.0.3693.5', + '74.0.3693.6', + '74.0.3694.0', + '74.0.3694.1', + '74.0.3694.2', + '74.0.3694.3', + '74.0.3694.4', + '74.0.3694.5', + '74.0.3694.6', + '74.0.3694.7', + '74.0.3694.8', + '74.0.3696.0', + '74.0.3696.1', + '74.0.3696.2', + '74.0.3698.0', + '74.0.3699.0', + '74.0.3699.1', + '74.0.3699.2', + '74.0.3699.3', + '74.0.3700.0', + '74.0.3700.1', + '74.0.3701.0', + '74.0.3701.1', + '74.0.3702.0', + '74.0.3702.1', + '74.0.3702.2', + '74.0.3702.3', + '74.0.3703.0', + '74.0.3703.1', + '74.0.3703.2', + '74.0.3703.3', + '74.0.3704.0', + '74.0.3704.1', + '74.0.3704.2', + '74.0.3704.3', + '74.0.3704.4', + '74.0.3704.5', + '74.0.3704.6', + '74.0.3704.7', + '74.0.3704.8', + '74.0.3704.9', + '74.0.3705.0', + '74.0.3705.1', + '74.0.3706.0', + '74.0.3706.1', + '74.0.3706.2', + '74.0.3706.3', + '74.0.3706.4', + '74.0.3706.5', + '74.0.3706.6', + '74.0.3706.7', + '74.0.3708.0', + '74.0.3709.0', + '74.0.3709.1', + '74.0.3710.0', + '74.0.3710.1', + '74.0.3710.2', + '74.0.3711.0', + '74.0.3711.1', + '74.0.3711.2', + '74.0.3712.0', + '74.0.3712.1', + '74.0.3712.2', + '74.0.3713.0', + '74.0.3713.1', + '74.0.3713.3', + '74.0.3714.0', + '74.0.3714.1', + '74.0.3714.2', + '74.0.3715.0', + '74.0.3715.1', + '74.0.3716.0', + '74.0.3716.1', + '74.0.3717.0', + '74.0.3717.1', + '74.0.3717.2', + '74.0.3718.0', + '74.0.3718.1', + '74.0.3718.2', + '74.0.3718.3', + '74.0.3718.4', + '74.0.3718.5', + '74.0.3718.6', + '74.0.3718.7', + '74.0.3718.8', + '74.0.3718.9', + '74.0.3719.0', + '74.0.3719.1', + '74.0.3719.2', + '74.0.3719.3', + '74.0.3719.4', + '74.0.3719.5', + '74.0.3720.0', + '74.0.3720.1', + '74.0.3720.2', + '74.0.3720.3', + '74.0.3720.4', + '74.0.3720.5', + '74.0.3720.6', + '74.0.3721.0', + '74.0.3721.1', + '74.0.3721.2', + '74.0.3721.3', + '74.0.3722.0', + '74.0.3722.1', + '74.0.3723.0', + '74.0.3723.1', + '74.0.3724.0', + '74.0.3724.1', + '74.0.3724.2', + '74.0.3724.3', + '74.0.3724.4', + '74.0.3724.5', + '74.0.3724.6', + '74.0.3724.7', + '74.0.3724.8', + '74.0.3725.0', + '74.0.3725.1', + '74.0.3725.2', + '74.0.3725.3', + '74.0.3725.4', + '74.0.3726.0', + '74.0.3726.1', + '74.0.3726.2', + '74.0.3726.3', + '74.0.3726.4', + '74.0.3728.0', + '74.0.3729.0', + '74.0.3729.1', + '74.0.3729.10', + '74.0.3729.100', + '74.0.3729.101', + '74.0.3729.102', + '74.0.3729.103', + '74.0.3729.104', + '74.0.3729.105', + '74.0.3729.106', + '74.0.3729.107', + '74.0.3729.108', + '74.0.3729.109', + '74.0.3729.11', + '74.0.3729.110', + '74.0.3729.111', + '74.0.3729.112', + '74.0.3729.113', + '74.0.3729.114', + '74.0.3729.115', + '74.0.3729.116', + '74.0.3729.117', + '74.0.3729.118', + '74.0.3729.119', + '74.0.3729.12', + '74.0.3729.120', + '74.0.3729.121', + '74.0.3729.122', + '74.0.3729.123', + '74.0.3729.124', + '74.0.3729.125', + '74.0.3729.126', + '74.0.3729.127', + '74.0.3729.128', + '74.0.3729.129', + '74.0.3729.13', + '74.0.3729.14', + '74.0.3729.15', + '74.0.3729.16', + '74.0.3729.17', + '74.0.3729.18', + '74.0.3729.19', + '74.0.3729.2', + '74.0.3729.20', + '74.0.3729.21', + '74.0.3729.22', + '74.0.3729.23', + '74.0.3729.24', + '74.0.3729.25', + '74.0.3729.26', + '74.0.3729.27', + '74.0.3729.28', + '74.0.3729.29', + '74.0.3729.3', + '74.0.3729.30', + '74.0.3729.31', + '74.0.3729.32', + '74.0.3729.33', + '74.0.3729.34', + '74.0.3729.35', + '74.0.3729.36', + '74.0.3729.37', + '74.0.3729.38', + '74.0.3729.39', + '74.0.3729.4', + '74.0.3729.40', + '74.0.3729.41', + '74.0.3729.42', + '74.0.3729.43', + '74.0.3729.44', + '74.0.3729.45', + '74.0.3729.46', + '74.0.3729.47', + '74.0.3729.48', + '74.0.3729.49', + '74.0.3729.5', + '74.0.3729.50', + '74.0.3729.51', + '74.0.3729.52', + '74.0.3729.53', + '74.0.3729.54', + '74.0.3729.55', + '74.0.3729.56', + '74.0.3729.57', + '74.0.3729.58', + '74.0.3729.59', + '74.0.3729.6', + '74.0.3729.60', + '74.0.3729.61', + '74.0.3729.62', + '74.0.3729.63', + '74.0.3729.64', + '74.0.3729.65', + '74.0.3729.66', + '74.0.3729.67', + '74.0.3729.68', + '74.0.3729.69', + '74.0.3729.7', + '74.0.3729.70', + '74.0.3729.71', + '74.0.3729.72', + '74.0.3729.73', + '74.0.3729.74', + '74.0.3729.75', + '74.0.3729.76', + '74.0.3729.77', + '74.0.3729.78', + '74.0.3729.79', + '74.0.3729.8', + '74.0.3729.80', + '74.0.3729.81', + '74.0.3729.82', + '74.0.3729.83', + '74.0.3729.84', + '74.0.3729.85', + '74.0.3729.86', + '74.0.3729.87', + '74.0.3729.88', + '74.0.3729.89', + '74.0.3729.9', + '74.0.3729.90', + '74.0.3729.91', + '74.0.3729.92', + '74.0.3729.93', + '74.0.3729.94', + '74.0.3729.95', + '74.0.3729.96', + '74.0.3729.97', + '74.0.3729.98', + '74.0.3729.99', + '75.0.3730.0', + '75.0.3730.1', + '75.0.3730.2', + '75.0.3730.3', + '75.0.3730.4', + '75.0.3730.5', + '75.0.3731.0', + '75.0.3731.2', + '75.0.3731.3', + '75.0.3732.0', + '75.0.3732.1', + '75.0.3733.0', + '75.0.3733.1', + '75.0.3734.0', + '75.0.3734.1', + '75.0.3735.0', + '75.0.3735.1', + '75.0.3736.0', + '75.0.3736.1', + '75.0.3737.0', + '75.0.3737.1', + '75.0.3738.0', + '75.0.3738.1', + '75.0.3738.2', + '75.0.3738.3', + '75.0.3738.4', + '75.0.3739.0', + '75.0.3739.1', + '75.0.3740.0', + '75.0.3740.1', + '75.0.3740.2', + '75.0.3740.3', + '75.0.3740.4', + '75.0.3740.5', + '75.0.3741.0', + '75.0.3741.1', + '75.0.3741.2', + '75.0.3744.0', + '75.0.3744.1', + '75.0.3744.2', + '75.0.3745.0', + '75.0.3745.1', + '75.0.3745.2', + '75.0.3745.3', + '75.0.3745.4', + '75.0.3745.5', + '75.0.3746.0', + '75.0.3746.1', + '75.0.3746.2', + '75.0.3746.3', + '75.0.3746.4', + '75.0.3747.0', + '75.0.3747.1', + '75.0.3748.0', + '75.0.3748.1', + '75.0.3749.0', + '75.0.3749.1', + '75.0.3749.2', + '75.0.3749.3', + '75.0.3750.0', + '75.0.3751.0', + '75.0.3751.1', + '75.0.3752.0', + '75.0.3752.1', + '75.0.3752.2', + '75.0.3753.0', + '75.0.3753.1', + '75.0.3753.2', + '75.0.3753.3', + '75.0.3753.4', + '75.0.3754.0', + '75.0.3754.1', + '75.0.3754.2', + '75.0.3755.0', + '75.0.3755.1', + '75.0.3755.2', + '75.0.3755.3', + '75.0.3756.0', + '75.0.3756.1', + '75.0.3757.0', + '75.0.3757.1', + '75.0.3758.0', + '75.0.3758.1', + '75.0.3759.0', + '75.0.3759.1', + '75.0.3759.2', + '75.0.3759.3', + '75.0.3759.4', + '75.0.3759.5', + '75.0.3759.6', + '75.0.3759.7', + '75.0.3759.8', + '75.0.3760.0', + '75.0.3761.0', + '75.0.3761.1', + '75.0.3761.2', + '75.0.3761.3', + '75.0.3761.4', + '75.0.3762.0', + '75.0.3762.1', + '75.0.3763.0', + '75.0.3763.1', + '75.0.3763.2', + '75.0.3764.0', + '75.0.3764.1', + '75.0.3765.0', + '75.0.3765.1', + '75.0.3766.0', + '75.0.3766.1', + '75.0.3766.2', + '75.0.3766.3', + '75.0.3767.0', + '75.0.3767.1', + '75.0.3767.2', + '75.0.3768.0', + '75.0.3768.1', + '75.0.3768.2', + '75.0.3768.3', + '75.0.3768.4', + '75.0.3768.5', + '75.0.3768.6', + '75.0.3769.0', + '75.0.3769.1', + '75.0.3769.2', + '75.0.3769.3', + '75.0.3769.4', + '75.0.3769.5', + '75.0.3770.0', + '75.0.3770.1', + '75.0.3770.10', + '75.0.3770.11', + '75.0.3770.12', + '75.0.3770.13', + '75.0.3770.14', + '75.0.3770.15', + '75.0.3770.2', + '75.0.3770.3', + '75.0.3770.4', + '75.0.3770.5', + '75.0.3770.6', + '75.0.3770.7', + '75.0.3770.8', + '75.0.3770.9', + '76.0.3771.0', + '76.0.3771.1', + '76.0.3772.0', + '76.0.3772.1', + '76.0.3773.0', + '76.0.3773.1', + '76.0.3774.0', + '76.0.3774.1', + '76.0.3775.0', + '76.0.3775.1', + '76.0.3775.2', + '76.0.3775.3', + '76.0.3775.4', + '76.0.3775.5', + '76.0.3776.0', + '76.0.3776.1', + '76.0.3776.2', + '76.0.3776.3', + '76.0.3776.4', + '76.0.3777.0', + '76.0.3777.1', + '76.0.3778.0', + '76.0.3778.1', + '76.0.3779.0', + '76.0.3779.1', + '76.0.3780.0', + '76.0.3780.1', + '76.0.3780.2', + '76.0.3780.3', ) return _USER_AGENT_TPL % random.choice(_CHROME_VERSIONS) @@ -1682,7 +1682,7 @@ std_headers = { 'Accept-Language': 'en-us,en;q=0.5', } - +# TODO: only used by CeskaTeleviseIE, replace by _USER_AGENT_TPL % _CHROME_VERSIONS[0] on UA freeze USER_AGENTS = { 'Safari': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27', } From 1d9df28c7d678d1845630c04c5d79ec6f4acd965 Mon Sep 17 00:00:00 2001 From: dirkf Date: Wed, 26 Jan 2022 20:42:42 +0000 Subject: [PATCH 12/18] [utils] Recognise FLAC audio in parse_codecs() --- youtube_dl/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 3fc78cf42..90d380f25 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -4766,7 +4766,7 @@ def parse_codecs(codecs_str): if codec in ('avc1', 'avc2', 'avc3', 'avc4', 'vp9', 'vp8', 'hev1', 'hev2', 'h263', 'h264', 'mp4v', 'hvc1', 'av01', 'theora'): if not vcodec: vcodec = full_codec - elif codec in ('mp4a', 'opus', 'vorbis', 'mp3', 'aac', 'ac-3', 'ec-3', 'eac3', 'dtsc', 'dtse', 'dtsh', 'dtsl'): + elif codec in ('flac', 'mp4a', 'opus', 'vorbis', 'mp3', 'aac', 'ac-3', 'ec-3', 'eac3', 'dtsc', 'dtse', 'dtsh', 'dtsl'): if not acodec: acodec = full_codec else: From f5f19082758cf2a9aa391beee1326d567ca3d287 Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 27 Jan 2022 00:04:09 +0000 Subject: [PATCH 13/18] [utils] Add parsing YYYYMMDD dates, also in Nov/Dec (yt-dlp PR #2094) --- test/test_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_utils.py b/test/test_utils.py index 1186dd46b..9319e8695 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -377,6 +377,7 @@ class TestUtil(unittest.TestCase): self.assertEqual(unified_strdate('Sep 2nd, 2013'), '20130902') self.assertEqual(unified_strdate('November 3rd, 2019'), '20191103') self.assertEqual(unified_strdate('October 23rd, 2005'), '20051023') + self.assertEqual(unified_strdate('20211221'), '20211221') def test_unified_timestamps(self): self.assertEqual(unified_timestamp('December 21, 2010'), 1292889600) From 0205fea8333392bbfa9978d9bd7dbf5ded369d9a Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 27 Jan 2022 00:59:08 +0000 Subject: [PATCH 14/18] [utils] Improve parse_count() with single regex, based on yt-dlp 352d5da81219e2675ef8cac9383ab0dfbd161a19 --- test/test_utils.py | 7 +++++++ youtube_dl/utils.py | 19 ++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 9319e8695..e6e202b23 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1272,9 +1272,16 @@ class TestUtil(unittest.TestCase): self.assertEqual(parse_count('1000'), 1000) self.assertEqual(parse_count('1.000'), 1000) self.assertEqual(parse_count('1.1k'), 1100) + self.assertEqual(parse_count('1.1 k'), 1100) + self.assertEqual(parse_count('1,1 k'), 1100) + self.assertEqual(parse_count('1,1kk'), 1100000) + self.assertEqual(parse_count('100 views'), 100) + self.assertEqual(parse_count('1,100 views'), 1100) self.assertEqual(parse_count('1.1kk'), 1100000) self.assertEqual(parse_count('1.1kk '), 1100000) self.assertEqual(parse_count('1.1kk views'), 1100000) + self.assertEqual(parse_count('10M views'), 10000000) + self.assertEqual(parse_count('has 10M views'), 10000000) def test_parse_resolution(self): self.assertEqual(parse_resolution(None), {}) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 90d380f25..952c636a8 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -3746,10 +3746,11 @@ def parse_count(s): if s is None: return None - s = s.strip() - - if re.match(r'^[\d,.]+$', s): - return str_to_int(s) + m = re.match(r'^(?:[^\d]+\s+)?(?P(?P[\d,.]+)(?P[\w\s]+?)?)(?:\s|\s*$)', s) + if m: + if not m.group('rest'): + return str_to_int(m.group('num')) + s = m.group('val') _UNIT_TABLE = { 'k': 1000, @@ -3758,9 +3759,17 @@ def parse_count(s): 'M': 1000 ** 2, 'kk': 1000 ** 2, 'KK': 1000 ** 2, + 'b': 1000 ** 3, + 'B': 1000 ** 3, } - return lookup_unit_table(_UNIT_TABLE, s) + ret = lookup_unit_table(_UNIT_TABLE, s) + if ret is not None: + return ret + + s = m and m.group('num') + if s is not None: + return str_to_int(s) def parse_resolution(s): From 645d7a399c20df75d3af7fd91fa51330241d3a6c Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 27 Jan 2022 02:29:33 +0000 Subject: [PATCH 15/18] [utils] Fix/improve InAdvancePagedList, from yt-dlp d37707bda466282b66ce381cbfd734f899f9e06e --- youtube_dl/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 952c636a8..7ddb7695c 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -4243,7 +4243,8 @@ class InAdvancePagedList(PagedList): res = [] start_page = start // self._pagesize end_page = ( - self._pagecount if end is None else (end // self._pagesize + 1)) + self._pagecount if end is None + else min(self._pagecount, end // self._pagesize + 1)) skip_elems = start - start_page * self._pagesize only_more = None if end is None else end - start for pagenum in range(start_page, end_page): From 059ef5b55e6b8270fdea0918d458ef4abed1e307 Mon Sep 17 00:00:00 2001 From: dirkf Date: Thu, 27 Jan 2022 02:51:25 +0000 Subject: [PATCH 16/18] [utils] Handle ss:xxx in parse_duration(), based on yt-dlp 8bd1c00bf399ba7002fc21cd399c931e9d301bd8 --- test/test_utils.py | 2 ++ youtube_dl/utils.py | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index e6e202b23..06a7a5d2b 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -654,6 +654,8 @@ class TestUtil(unittest.TestCase): self.assertEqual(parse_duration('PT1H0.040S'), 3600.04) self.assertEqual(parse_duration('PT00H03M30SZ'), 210) self.assertEqual(parse_duration('P0Y0M0DT0H4M20.880S'), 260.88) + self.assertEqual(parse_duration('01:02:03:050'), 3723.05) + self.assertEqual(parse_duration('103:050'), 103.05) def test_fix_xml_ampersands(self): self.assertEqual( diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 7ddb7695c..60fa29103 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -3967,12 +3967,14 @@ def parse_duration(s): if not isinstance(s, compat_basestring): return None - s = s.strip() - - days, hours, mins, secs, ms = [None] * 5 - m = re.match(r'(?:(?:(?:(?P[0-9]+):)?(?P[0-9]+):)?(?P[0-9]+):)?(?P[0-9]+)(?P\.[0-9]+)?Z?$', s) + m = re.match(r'''(?x)\s* + (?P + (?:(?:(?P[0-9]+):)?(?P[0-9]+):)?(?P[0-9]+):)? + (?P(?(before_secs)[0-9]{1,2}|[0-9]+)) + (?P[.:][0-9]+)?Z?\s*$ + ''', s) if m: - days, hours, mins, secs, ms = m.groups() + days, hours, mins, secs, ms = m.group('days', 'hours', 'mins', 'secs', 'ms') else: m = re.match( r'''(?ix)(?:P? @@ -4004,6 +4006,7 @@ def parse_duration(s): m = re.match(r'(?i)(?:(?P[0-9.]+)\s*(?:hours?)|(?P[0-9.]+)\s*(?:mins?\.?|minutes?)\s*)Z?$', s) if m: hours, mins = m.groups() + days = secs = ms = None else: return None @@ -4017,7 +4020,7 @@ def parse_duration(s): if days: duration += float(days) * 24 * 60 * 60 if ms: - duration += float(ms) + duration += float(ms.replace(':', '.')) return duration From 80cb917ef60335055810df1772bdfe61b15af9aa Mon Sep 17 00:00:00 2001 From: dirkf Date: Mon, 11 Mar 2024 15:49:59 +0000 Subject: [PATCH 17/18] [utils] Unescape HTML5 named character references (with no ;) --- test/test_utils.py | 5 ++++- youtube_dl/utils.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 06a7a5d2b..ea81ef01f 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -337,6 +337,9 @@ class TestUtil(unittest.TestCase): self.assertEqual(unescapeHTML('&a"'), '&a"') # HTML5 entities self.assertEqual(unescapeHTML('.''), '.\'') + # non-semicolon HTML5 (bah!) entities + self.assertEqual(unescapeHTML('&&etc'), '&&etc') + self.assertEqual(unescapeHTML('£&POUNDetc'), '£&POUNDetc') def test_date_from_str(self): self.assertEqual(date_from_str('yesterday'), date_from_str('now-1day')) @@ -1251,7 +1254,7 @@ class TestUtil(unittest.TestCase): def test_args_to_str(self): self.assertEqual( args_to_str(['foo', 'ba/r', '-baz', '2 be', '']), - 'foo ba/r -baz \'2 be\' \'\'' if not(compat_os_name in ('nt', 'ce')) else 'foo ba/r -baz "2 be" ""' + 'foo ba/r -baz \'2 be\' \'\'' if not (compat_os_name in ('nt', 'ce')) else 'foo ba/r -baz "2 be" ""' ) def test_parse_filesize(self): diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 60fa29103..459502554 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -2232,25 +2232,25 @@ def orderedSet(iterable): return res -def _htmlentity_transform(entity_with_semicolon): +def _htmlentity_transform(entity): """Transforms an HTML entity to a character.""" + entity_with_semicolon = entity if entity[-1] == ';' else (entity + ';') entity = entity_with_semicolon[:-1] # Known non-numeric HTML entity if entity in compat_html_entities.name2codepoint: return compat_chr(compat_html_entities.name2codepoint[entity]) - # TODO: HTML5 allows entities without a semicolon. For example, - # 'Éric' should be decoded as 'Éric'. if entity_with_semicolon in compat_html_entities_html5: return compat_html_entities_html5[entity_with_semicolon] - mobj = re.match(r'#(x[0-9a-fA-F]+|[0-9]+)', entity) + # numeric entity + mobj = re.match(r'(?i)#(x[0-9a-f]+|[0-9]+)', entity) if mobj is not None: numstr = mobj.group(1) - if numstr.startswith('x'): + if numstr[0] in 'xX': base = 16 - numstr = '0%s' % numstr + numstr = '0%s' % numstr.lower() else: base = 10 # See https://github.com/ytdl-org/youtube-dl/issues/7518 @@ -2263,13 +2263,34 @@ def _htmlentity_transform(entity_with_semicolon): return '&%s;' % entity +# Based on https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#cite_note-semicolon-2 +# (someone else read WHATWG so we didn't have to) +_html5_CI_non_semicolon_entities = ( + # canonically use lower-case REs + 'quot', 'amp', '[lg]t', 'copy', 'reg', 'eth', 'thorn', +) +_html5_non_semicolon_entities = itertools.chain( + _html5_CI_non_semicolon_entities, + (e.upper() for e in _html5_CI_non_semicolon_entities), + ('nbsp', 'i(?:excl|quest)', 'cent', 'pound', 'curren', 'yen', 'brvbar', + 'sect', 'ord[fm]', '[lr]aquo', 'not', 'shy' 'macr', 'dseg', + 'plusmn', 'sup[231]', 'micro', 'para', 'middot', '[cC]?cedil', + 'frac(?:12|[13]4)', '[aAeEiIoOuUyY]?(?:acute|uml)', + '[aAeEiIoOuU](?:grave|circ)', '[aA]ring', '[aAnNoO]tilde', + '(?:ae|AE|sz|SZ)lig', '[oO]slash', 'divide', 'times', ) +) +_html5_entities_re = '&([^&;]+;|%s)' % '|'.join(_html5_non_semicolon_entities) + + def unescapeHTML(s): if s is None: return None assert isinstance(s, compat_str) return re.sub( - r'&([^&;]+;)', lambda m: _htmlentity_transform(m.group(1)), s) + # match generic &xxx;, &nnn; entities, and also + # HTML5 "named character references" with *omitted* final ; + _html5_entities_re, lambda m: _htmlentity_transform(m.group(1)), s) def process_communicate_or_kill(p, *args, **kwargs): From 05aa2ad2f849d6742e8c178c6ff59b439e3c6c89 Mon Sep 17 00:00:00 2001 From: dirkf Date: Mon, 11 Mar 2024 15:52:02 +0000 Subject: [PATCH 18/18] [utils] `mode` might be `None` in `write_string()` * see https://github.com/yt-dlp/yt-dlp/issues/8816 --- youtube_dl/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 459502554..57f6ccb2f 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -3495,7 +3495,8 @@ def write_string(s, out=None, encoding=None): if _windows_write_string(s, out): return - if ('b' in getattr(out, 'mode', '') + # `mode` might be `None` (see https://github.com/yt-dlp/yt-dlp/issues/8816) + if ('b' in (getattr(out, 'mode', None) or '') or sys.version_info[0] < 3): # Python 2 lies about mode of sys.stderr byt = s.encode(encoding or preferredencoding(), 'ignore') out.write(byt)