1# coding: utf-8 2 3import asyncio 4import base64 5import ctypes 6import getpass 7import html 8import html.parser 9import http 10import http.client 11import http.cookiejar 12import http.cookies 13import http.server 14import itertools 15import optparse 16import os 17import re 18import shlex 19import shutil 20import socket 21import struct 22import subprocess 23import sys 24import tokenize 25import urllib 26import xml.etree.ElementTree as etree 27from subprocess import DEVNULL 28 29 30# HTMLParseError has been deprecated in Python 3.3 and removed in 31# Python 3.5. Introducing dummy exception for Python >3.5 for compatible 32# and uniform cross-version exception handling 33class compat_HTMLParseError(Exception): 34 pass 35 36 37# compat_ctypes_WINFUNCTYPE = ctypes.WINFUNCTYPE 38# will not work since ctypes.WINFUNCTYPE does not exist in UNIX machines 39def compat_ctypes_WINFUNCTYPE(*args, **kwargs): 40 return ctypes.WINFUNCTYPE(*args, **kwargs) 41 42 43class _TreeBuilder(etree.TreeBuilder): 44 def doctype(self, name, pubid, system): 45 pass 46 47 48def compat_etree_fromstring(text): 49 return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder())) 50 51 52compat_os_name = os._name if os.name == 'java' else os.name 53 54 55if compat_os_name == 'nt': 56 def compat_shlex_quote(s): 57 return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"') 58else: 59 from shlex import quote as compat_shlex_quote 60 61 62def compat_ord(c): 63 if type(c) is int: 64 return c 65 else: 66 return ord(c) 67 68 69def compat_setenv(key, value, env=os.environ): 70 env[key] = value 71 72 73if compat_os_name == 'nt' and sys.version_info < (3, 8): 74 # os.path.realpath on Windows does not follow symbolic links 75 # prior to Python 3.8 (see https://bugs.python.org/issue9949) 76 def compat_realpath(path): 77 while os.path.islink(path): 78 path = os.path.abspath(os.readlink(path)) 79 return path 80else: 81 compat_realpath = os.path.realpath 82 83 84def compat_print(s): 85 assert isinstance(s, compat_str) 86 print(s) 87 88 89# Fix https://github.com/ytdl-org/youtube-dl/issues/4223 90# See http://bugs.python.org/issue9161 for what is broken 91def workaround_optparse_bug9161(): 92 op = optparse.OptionParser() 93 og = optparse.OptionGroup(op, 'foo') 94 try: 95 og.add_option('-t') 96 except TypeError: 97 real_add_option = optparse.OptionGroup.add_option 98 99 def _compat_add_option(self, *args, **kwargs): 100 enc = lambda v: ( 101 v.encode('ascii', 'replace') if isinstance(v, compat_str) 102 else v) 103 bargs = [enc(a) for a in args] 104 bkwargs = dict( 105 (k, enc(v)) for k, v in kwargs.items()) 106 return real_add_option(self, *bargs, **bkwargs) 107 optparse.OptionGroup.add_option = _compat_add_option 108 109 110try: 111 compat_Pattern = re.Pattern 112except AttributeError: 113 compat_Pattern = type(re.compile('')) 114 115 116try: 117 compat_Match = re.Match 118except AttributeError: 119 compat_Match = type(re.compile('').match('')) 120 121 122try: 123 compat_asyncio_run = asyncio.run # >= 3.7 124except AttributeError: 125 def compat_asyncio_run(coro): 126 try: 127 loop = asyncio.get_event_loop() 128 except RuntimeError: 129 loop = asyncio.new_event_loop() 130 asyncio.set_event_loop(loop) 131 loop.run_until_complete(coro) 132 133 asyncio.run = compat_asyncio_run 134 135 136# Python 3.8+ does not honor %HOME% on windows, but this breaks compatibility with youtube-dl 137# See https://github.com/yt-dlp/yt-dlp/issues/792 138# https://docs.python.org/3/library/os.path.html#os.path.expanduser 139if compat_os_name in ('nt', 'ce') and 'HOME' in os.environ: 140 _userhome = os.environ['HOME'] 141 142 def compat_expanduser(path): 143 if not path.startswith('~'): 144 return path 145 i = path.replace('\\', '/', 1).find('/') # ~user 146 if i < 0: 147 i = len(path) 148 userhome = os.path.join(os.path.dirname(_userhome), path[1:i]) if i > 1 else _userhome 149 return userhome + path[i:] 150else: 151 compat_expanduser = os.path.expanduser 152 153 154try: 155 from Cryptodome.Cipher import AES as compat_pycrypto_AES 156except ImportError: 157 try: 158 from Crypto.Cipher import AES as compat_pycrypto_AES 159 except ImportError: 160 compat_pycrypto_AES = None 161 162 163WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None 164 165 166def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075 167 if compat_os_name != 'nt': 168 return 169 global WINDOWS_VT_MODE 170 startupinfo = subprocess.STARTUPINFO() 171 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 172 try: 173 subprocess.Popen('', shell=True, startupinfo=startupinfo) 174 WINDOWS_VT_MODE = True 175 except Exception: 176 pass 177 178 179# Deprecated 180 181compat_basestring = str 182compat_chr = chr 183compat_input = input 184compat_integer_types = (int, ) 185compat_kwargs = lambda kwargs: kwargs 186compat_numeric_types = (int, float, complex) 187compat_str = str 188compat_xpath = lambda xpath: xpath 189compat_zip = zip 190 191compat_HTMLParser = html.parser.HTMLParser 192compat_HTTPError = urllib.error.HTTPError 193compat_Struct = struct.Struct 194compat_b64decode = base64.b64decode 195compat_cookiejar = http.cookiejar 196compat_cookiejar_Cookie = compat_cookiejar.Cookie 197compat_cookies = http.cookies 198compat_cookies_SimpleCookie = compat_cookies.SimpleCookie 199compat_etree_Element = etree.Element 200compat_etree_register_namespace = etree.register_namespace 201compat_get_terminal_size = shutil.get_terminal_size 202compat_getenv = os.getenv 203compat_getpass = getpass.getpass 204compat_html_entities = html.entities 205compat_html_entities_html5 = compat_html_entities.html5 206compat_http_client = http.client 207compat_http_server = http.server 208compat_itertools_count = itertools.count 209compat_parse_qs = urllib.parse.parse_qs 210compat_shlex_split = shlex.split 211compat_socket_create_connection = socket.create_connection 212compat_struct_pack = struct.pack 213compat_struct_unpack = struct.unpack 214compat_subprocess_get_DEVNULL = lambda: DEVNULL 215compat_tokenize_tokenize = tokenize.tokenize 216compat_urllib_error = urllib.error 217compat_urllib_parse = urllib.parse 218compat_urllib_parse_quote = urllib.parse.quote 219compat_urllib_parse_quote_plus = urllib.parse.quote_plus 220compat_urllib_parse_unquote = urllib.parse.unquote 221compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus 222compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes 223compat_urllib_parse_urlencode = urllib.parse.urlencode 224compat_urllib_parse_urlparse = urllib.parse.urlparse 225compat_urllib_parse_urlunparse = urllib.parse.urlunparse 226compat_urllib_request = urllib.request 227compat_urllib_request_DataHandler = urllib.request.DataHandler 228compat_urllib_response = urllib.response 229compat_urlparse = urllib.parse 230compat_urlretrieve = urllib.request.urlretrieve 231compat_xml_parse_error = etree.ParseError 232 233 234# Set public objects 235 236__all__ = [ 237 'WINDOWS_VT_MODE', 238 'compat_HTMLParseError', 239 'compat_HTMLParser', 240 'compat_HTTPError', 241 'compat_Match', 242 'compat_Pattern', 243 'compat_Struct', 244 'compat_asyncio_run', 245 'compat_b64decode', 246 'compat_basestring', 247 'compat_chr', 248 'compat_cookiejar', 249 'compat_cookiejar_Cookie', 250 'compat_cookies', 251 'compat_cookies_SimpleCookie', 252 'compat_ctypes_WINFUNCTYPE', 253 'compat_etree_Element', 254 'compat_etree_fromstring', 255 'compat_etree_register_namespace', 256 'compat_expanduser', 257 'compat_get_terminal_size', 258 'compat_getenv', 259 'compat_getpass', 260 'compat_html_entities', 261 'compat_html_entities_html5', 262 'compat_http_client', 263 'compat_http_server', 264 'compat_input', 265 'compat_integer_types', 266 'compat_itertools_count', 267 'compat_kwargs', 268 'compat_numeric_types', 269 'compat_ord', 270 'compat_os_name', 271 'compat_parse_qs', 272 'compat_print', 273 'compat_pycrypto_AES', 274 'compat_realpath', 275 'compat_setenv', 276 'compat_shlex_quote', 277 'compat_shlex_split', 278 'compat_socket_create_connection', 279 'compat_str', 280 'compat_struct_pack', 281 'compat_struct_unpack', 282 'compat_subprocess_get_DEVNULL', 283 'compat_tokenize_tokenize', 284 'compat_urllib_error', 285 'compat_urllib_parse', 286 'compat_urllib_parse_quote', 287 'compat_urllib_parse_quote_plus', 288 'compat_urllib_parse_unquote', 289 'compat_urllib_parse_unquote_plus', 290 'compat_urllib_parse_unquote_to_bytes', 291 'compat_urllib_parse_urlencode', 292 'compat_urllib_parse_urlparse', 293 'compat_urllib_parse_urlunparse', 294 'compat_urllib_request', 295 'compat_urllib_request_DataHandler', 296 'compat_urllib_response', 297 'compat_urlparse', 298 'compat_urlretrieve', 299 'compat_xml_parse_error', 300 'compat_xpath', 301 'compat_zip', 302 'windows_enable_vt_mode', 303 'workaround_optparse_bug9161', 304] 305