]> jfr.im git - yt-dlp.git/blob - yt_dlp/compat.py
[utils] Parse `vp09` as vp9
[yt-dlp.git] / yt_dlp / compat.py
1 # coding: utf-8
2
3 import asyncio
4 import base64
5 import ctypes
6 import getpass
7 import html
8 import html.parser
9 import http
10 import http.client
11 import http.cookiejar
12 import http.cookies
13 import http.server
14 import itertools
15 import optparse
16 import os
17 import re
18 import shlex
19 import shutil
20 import socket
21 import struct
22 import subprocess
23 import sys
24 import tokenize
25 import urllib
26 import xml.etree.ElementTree as etree
27 from 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
33 class 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
39 def compat_ctypes_WINFUNCTYPE(*args, **kwargs):
40 return ctypes.WINFUNCTYPE(*args, **kwargs)
41
42
43 class _TreeBuilder(etree.TreeBuilder):
44 def doctype(self, name, pubid, system):
45 pass
46
47
48 def compat_etree_fromstring(text):
49 return etree.XML(text, parser=etree.XMLParser(target=_TreeBuilder()))
50
51
52 compat_os_name = os._name if os.name == 'java' else os.name
53
54
55 if compat_os_name == 'nt':
56 def compat_shlex_quote(s):
57 return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"')
58 else:
59 from shlex import quote as compat_shlex_quote
60
61
62 def compat_ord(c):
63 if type(c) is int:
64 return c
65 else:
66 return ord(c)
67
68
69 def compat_setenv(key, value, env=os.environ):
70 env[key] = value
71
72
73 if 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
80 else:
81 compat_realpath = os.path.realpath
82
83
84 def 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
91 def 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
110 try:
111 compat_Pattern = re.Pattern
112 except AttributeError:
113 compat_Pattern = type(re.compile(''))
114
115
116 try:
117 compat_Match = re.Match
118 except AttributeError:
119 compat_Match = type(re.compile('').match(''))
120
121
122 try:
123 compat_asyncio_run = asyncio.run # >= 3.7
124 except 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
139 if 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:]
150 else:
151 compat_expanduser = os.path.expanduser
152
153
154 try:
155 from Cryptodome.Cipher import AES as compat_pycrypto_AES
156 except ImportError:
157 try:
158 from Crypto.Cipher import AES as compat_pycrypto_AES
159 except ImportError:
160 compat_pycrypto_AES = None
161
162
163 def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
164 if compat_os_name != 'nt':
165 return
166 startupinfo = subprocess.STARTUPINFO()
167 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
168 subprocess.Popen('', shell=True, startupinfo=startupinfo)
169
170
171 # Deprecated
172
173 compat_basestring = str
174 compat_chr = chr
175 compat_input = input
176 compat_integer_types = (int, )
177 compat_kwargs = lambda kwargs: kwargs
178 compat_numeric_types = (int, float, complex)
179 compat_str = str
180 compat_xpath = lambda xpath: xpath
181 compat_zip = zip
182
183 compat_HTMLParser = html.parser.HTMLParser
184 compat_HTTPError = urllib.error.HTTPError
185 compat_Struct = struct.Struct
186 compat_b64decode = base64.b64decode
187 compat_cookiejar = http.cookiejar
188 compat_cookiejar_Cookie = compat_cookiejar.Cookie
189 compat_cookies = http.cookies
190 compat_cookies_SimpleCookie = compat_cookies.SimpleCookie
191 compat_etree_Element = etree.Element
192 compat_etree_register_namespace = etree.register_namespace
193 compat_get_terminal_size = shutil.get_terminal_size
194 compat_getenv = os.getenv
195 compat_getpass = getpass.getpass
196 compat_html_entities = html.entities
197 compat_html_entities_html5 = compat_html_entities.html5
198 compat_http_client = http.client
199 compat_http_server = http.server
200 compat_itertools_count = itertools.count
201 compat_parse_qs = urllib.parse.parse_qs
202 compat_shlex_split = shlex.split
203 compat_socket_create_connection = socket.create_connection
204 compat_struct_pack = struct.pack
205 compat_struct_unpack = struct.unpack
206 compat_subprocess_get_DEVNULL = lambda: DEVNULL
207 compat_tokenize_tokenize = tokenize.tokenize
208 compat_urllib_error = urllib.error
209 compat_urllib_parse = urllib.parse
210 compat_urllib_parse_quote = urllib.parse.quote
211 compat_urllib_parse_quote_plus = urllib.parse.quote_plus
212 compat_urllib_parse_unquote = urllib.parse.unquote
213 compat_urllib_parse_unquote_plus = urllib.parse.unquote_plus
214 compat_urllib_parse_unquote_to_bytes = urllib.parse.unquote_to_bytes
215 compat_urllib_parse_urlencode = urllib.parse.urlencode
216 compat_urllib_parse_urlparse = urllib.parse.urlparse
217 compat_urllib_parse_urlunparse = urllib.parse.urlunparse
218 compat_urllib_request = urllib.request
219 compat_urllib_request_DataHandler = urllib.request.DataHandler
220 compat_urllib_response = urllib.response
221 compat_urlparse = urllib.parse
222 compat_urlretrieve = urllib.request.urlretrieve
223 compat_xml_parse_error = etree.ParseError
224
225
226 # Set public objects
227
228 __all__ = [
229 'compat_HTMLParseError',
230 'compat_HTMLParser',
231 'compat_HTTPError',
232 'compat_Match',
233 'compat_Pattern',
234 'compat_Struct',
235 'compat_asyncio_run',
236 'compat_b64decode',
237 'compat_basestring',
238 'compat_chr',
239 'compat_cookiejar',
240 'compat_cookiejar_Cookie',
241 'compat_cookies',
242 'compat_cookies_SimpleCookie',
243 'compat_ctypes_WINFUNCTYPE',
244 'compat_etree_Element',
245 'compat_etree_fromstring',
246 'compat_etree_register_namespace',
247 'compat_expanduser',
248 'compat_get_terminal_size',
249 'compat_getenv',
250 'compat_getpass',
251 'compat_html_entities',
252 'compat_html_entities_html5',
253 'compat_http_client',
254 'compat_http_server',
255 'compat_input',
256 'compat_integer_types',
257 'compat_itertools_count',
258 'compat_kwargs',
259 'compat_numeric_types',
260 'compat_ord',
261 'compat_os_name',
262 'compat_parse_qs',
263 'compat_print',
264 'compat_pycrypto_AES',
265 'compat_realpath',
266 'compat_setenv',
267 'compat_shlex_quote',
268 'compat_shlex_split',
269 'compat_socket_create_connection',
270 'compat_str',
271 'compat_struct_pack',
272 'compat_struct_unpack',
273 'compat_subprocess_get_DEVNULL',
274 'compat_tokenize_tokenize',
275 'compat_urllib_error',
276 'compat_urllib_parse',
277 'compat_urllib_parse_quote',
278 'compat_urllib_parse_quote_plus',
279 'compat_urllib_parse_unquote',
280 'compat_urllib_parse_unquote_plus',
281 'compat_urllib_parse_unquote_to_bytes',
282 'compat_urllib_parse_urlencode',
283 'compat_urllib_parse_urlparse',
284 'compat_urllib_parse_urlunparse',
285 'compat_urllib_request',
286 'compat_urllib_request_DataHandler',
287 'compat_urllib_response',
288 'compat_urlparse',
289 'compat_urlretrieve',
290 'compat_xml_parse_error',
291 'compat_xpath',
292 'compat_zip',
293 'windows_enable_vt_mode',
294 'workaround_optparse_bug9161',
295 ]