1 """No longer used and new code should not use. Exists only for API compat."""
12 from ._utils
import Popen
, decode_base_n
, preferredencoding
13 from .traversal
import traverse_obj
14 from ..dependencies
import certifi
, websockets
15 from ..networking
._helper
import make_ssl_context
16 from ..networking
._urllib
import HTTPHandler
19 from .networking
import escape_rfc3986
# noqa: F401
20 from .networking
import normalize_url
as escape_url
21 from .networking
import random_user_agent
, std_headers
# noqa: F401
22 from ..cookies
import YoutubeDLCookieJar
# noqa: F401
23 from ..networking
._urllib
import PUTRequest
# noqa: F401
24 from ..networking
._urllib
import SUPPORTED_ENCODINGS
, HEADRequest
# noqa: F401
25 from ..networking
._urllib
import ProxyHandler
as PerRequestProxyHandler
# noqa: F401
26 from ..networking
._urllib
import RedirectHandler
as YoutubeDLRedirectHandler
# noqa: F401
27 from ..networking
._urllib
import ( # noqa: F401
28 make_socks_conn_class
,
31 from ..networking
.exceptions
import HTTPError
, network_exceptions
# noqa: F401
33 has_certifi
= bool(certifi
)
34 has_websockets
= bool(websockets
)
37 class WebSocketsWrapper
:
38 """Wraps websockets module to use in non-async scopes"""
41 def __init__(self
, url
, headers
=None, connect
=True, **ws_kwargs
):
42 self
.loop
= asyncio
.new_event_loop()
43 # XXX: "loop" is deprecated
44 self
.conn
= websockets
.connect(
45 url
, extra_headers
=headers
, ping_interval
=None,
46 close_timeout
=float('inf'), loop
=self
.loop
, ping_timeout
=float('inf'), **ws_kwargs
)
49 atexit
.register(self
.__exit
__, None, None, None)
53 self
.pool
= self
.run_with_loop(self
.conn
.__aenter
__(), self
.loop
)
56 def send(self
, *args
):
57 self
.run_with_loop(self
.pool
.send(*args
), self
.loop
)
59 def recv(self
, *args
):
60 return self
.run_with_loop(self
.pool
.recv(*args
), self
.loop
)
62 def __exit__(self
, type, value
, traceback
):
64 return self
.run_with_loop(self
.conn
.__aexit
__(type, value
, traceback
), self
.loop
)
67 self
._cancel
_all
_tasks
(self
.loop
)
69 # taken from https://github.com/python/cpython/blob/3.9/Lib/asyncio/runners.py with modifications
70 # for contributors: If there's any new library using asyncio needs to be run in non-async, move these function out of this class
72 def run_with_loop(main
, loop
):
73 if not asyncio
.iscoroutine(main
):
74 raise ValueError(f
'a coroutine was expected, got {main!r}')
77 return loop
.run_until_complete(main
)
79 loop
.run_until_complete(loop
.shutdown_asyncgens())
80 if hasattr(loop
, 'shutdown_default_executor'):
81 loop
.run_until_complete(loop
.shutdown_default_executor())
84 def _cancel_all_tasks(loop
):
85 to_cancel
= asyncio
.all_tasks(loop
)
90 for task
in to_cancel
:
93 # XXX: "loop" is removed in Python 3.10+
94 loop
.run_until_complete(
95 asyncio
.gather(*to_cancel
, loop
=loop
, return_exceptions
=True))
97 for task
in to_cancel
:
100 if task
.exception() is not None:
101 loop
.call_exception_handler({
102 'message': 'unhandled exception during asyncio.run() shutdown',
103 'exception': task
.exception(),
108 def load_plugins(name
, suffix
, namespace
):
109 from ..plugins
import load_plugins
110 ret
= load_plugins(name
, suffix
)
111 namespace
.update(ret
)
115 def traverse_dict(dictn
, keys
, casesense
=True):
116 return traverse_obj(dictn
, keys
, casesense
=casesense
, is_user_input
=True, traverse_string
=True)
119 def decode_base(value
, digits
):
120 return decode_base_n(value
, table
=digits
)
124 """ Returns the platform name as a str """
125 return platform
.platform()
128 def get_subprocess_encoding():
129 if sys
.platform
== 'win32' and sys
.getwindowsversion()[0] >= 5:
130 # For subprocess calls, encode with locale encoding
131 # Refer to http://stackoverflow.com/a/9951851/35070
132 encoding
= preferredencoding()
134 encoding
= sys
.getfilesystemencoding()
141 # Based on png2str() written by @gdkchan and improved by @yokrysty
142 # Originally posted at https://github.com/ytdl-org/youtube-dl/issues/9706
143 def decode_png(png_data
):
144 # Reference: https://www.w3.org/TR/PNG/
145 header
= png_data
[8:]
147 if png_data
[:8] != b
'\x89PNG\x0d\x0a\x1a\x0a' or header
[4:8] != b
'IHDR':
148 raise OSError('Not a valid PNG file.')
150 int_map
= {1: '>B', 2: '>H', 4: '>I'}
151 unpack_integer
= lambda x
: struct
.unpack(int_map
[len(x
)], x
)[0]
156 length
= unpack_integer(header
[:4])
159 chunk_type
= header
[:4]
162 chunk_data
= header
[:length
]
163 header
= header
[length
:]
165 header
= header
[4:] # Skip CRC
173 ihdr
= chunks
[0]['data']
175 width
= unpack_integer(ihdr
[:4])
176 height
= unpack_integer(ihdr
[4:8])
181 if chunk
['type'] == b
'IDAT':
182 idat
+= chunk
['data']
185 raise OSError('Unable to read PNG data.')
187 decompressed_data
= bytearray(zlib
.decompress(idat
))
197 for y
in range(height
):
198 base_pos
= y
* (1 + stride
)
199 filter_type
= decompressed_data
[base_pos
]
203 pixels
.append(current_row
)
205 for x
in range(stride
):
206 color
= decompressed_data
[1 + base_pos
+ x
]
207 basex
= y
* stride
+ x
212 left
= _get_pixel(basex
- 3)
214 up
= _get_pixel(basex
- stride
)
216 if filter_type
== 1: # Sub
217 color
= (color
+ left
) & 0xff
218 elif filter_type
== 2: # Up
219 color
= (color
+ up
) & 0xff
220 elif filter_type
== 3: # Average
221 color
= (color
+ ((left
+ up
) >> 1)) & 0xff
222 elif filter_type
== 4: # Paeth
228 c
= _get_pixel(basex
- stride
- 3)
236 if pa
<= pb
and pa
<= pc
:
237 color
= (color
+ a
) & 0xff
239 color
= (color
+ b
) & 0xff
241 color
= (color
+ c
) & 0xff
243 current_row
.append(color
)
245 return width
, height
, pixels
248 def register_socks_protocols():
249 # "Register" SOCKS protocols
250 # In Python < 2.6.5, urlsplit() suffers from bug https://bugs.python.org/issue7904
251 # URLs with protocols not in urlparse.uses_netloc are not handled correctly
252 for scheme
in ('socks', 'socks4', 'socks4a', 'socks5'):
253 if scheme
not in urllib
.parse
.uses_netloc
:
254 urllib
.parse
.uses_netloc
.append(scheme
)
257 def handle_youtubedl_headers(headers
):
258 filtered_headers
= headers
260 if 'Youtubedl-no-compression' in filtered_headers
:
261 filtered_headers
= {k
: v
for k
, v
in filtered_headers
.items() if k
.lower() != 'accept-encoding'}
262 del filtered_headers
['Youtubedl-no-compression']
264 return filtered_headers
267 def request_to_url(req
):
268 if isinstance(req
, urllib
.request
.Request
):
269 return req
.get_full_url()
274 def sanitized_Request(url
, *args
, **kwargs
):
275 from ..utils
import extract_basic_auth
, sanitize_url
276 url
, auth_header
= extract_basic_auth(escape_url(sanitize_url(url
)))
277 if auth_header
is not None:
278 headers
= args
[1] if len(args
) >= 2 else kwargs
.setdefault('headers', {})
279 headers
['Authorization'] = auth_header
280 return urllib
.request
.Request(url
, *args
, **kwargs
)
283 class YoutubeDLHandler(HTTPHandler
):
284 def __init__(self
, params
, *args
, **kwargs
):
285 self
._params
= params
286 super().__init
__(*args
, **kwargs
)
289 YoutubeDLHTTPSHandler
= YoutubeDLHandler
292 class YoutubeDLCookieProcessor(urllib
.request
.HTTPCookieProcessor
):
293 def __init__(self
, cookiejar
=None):
294 urllib
.request
.HTTPCookieProcessor
.__init
__(self
, cookiejar
)
296 def http_response(self
, request
, response
):
297 return urllib
.request
.HTTPCookieProcessor
.http_response(self
, request
, response
)
299 https_request
= urllib
.request
.HTTPCookieProcessor
.http_request
300 https_response
= http_response
303 def make_HTTPS_handler(params
, **kwargs
):
304 return YoutubeDLHTTPSHandler(params
, context
=make_ssl_context(
305 verify
=not params
.get('nocheckcertificate'),
306 client_certificate
=params
.get('client_certificate'),
307 client_certificate_key
=params
.get('client_certificate_key'),
308 client_certificate_password
=params
.get('client_certificate_password'),
309 legacy_support
=params
.get('legacyserverconnect'),
310 use_certifi
='no-certifi' not in params
.get('compat_opts', []),
314 def process_communicate_or_kill(p
, *args
, **kwargs
):
315 return Popen
.communicate_or_kill(p
, *args
, **kwargs
)
318 def encodeFilename(s
, for_subprocess
=False):
319 assert isinstance(s
, str)
323 def decodeFilename(b
, for_subprocess
=False):
327 def decodeArgument(b
):
331 def decodeOption(optval
):
334 if isinstance(optval
, bytes
):
335 optval
= optval
.decode(preferredencoding())
337 assert isinstance(optval
, str)
341 def error_to_compat_str(err
):