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