mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-12-18 05:58:55 +00:00
Merge branch 'master' into yt-live-from-start-range
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import asyncio
|
||||
import atexit
|
||||
import base64
|
||||
import binascii
|
||||
import calendar
|
||||
@@ -54,7 +52,7 @@ from ..compat import (
|
||||
compat_os_name,
|
||||
compat_shlex_quote,
|
||||
)
|
||||
from ..dependencies import websockets, xattr
|
||||
from ..dependencies import xattr
|
||||
|
||||
__name__ = __name__.rsplit('.', 1)[0] # Pretend to be the parent module
|
||||
|
||||
@@ -560,7 +558,7 @@ class LenientJSONDecoder(json.JSONDecoder):
|
||||
s = self._close_object(e)
|
||||
if s is not None:
|
||||
continue
|
||||
raise type(e)(f'{e.msg} in {s[e.pos-10:e.pos+10]!r}', s, e.pos)
|
||||
raise type(e)(f'{e.msg} in {s[e.pos - 10:e.pos + 10]!r}', s, e.pos)
|
||||
assert False, 'Too many attempts to decode JSON'
|
||||
|
||||
|
||||
@@ -638,7 +636,7 @@ def sanitize_filename(s, restricted=False, is_id=NO_DEFAULT):
|
||||
elif char in '\\/|*<>':
|
||||
return '\0_'
|
||||
if restricted and (char in '!&\'()[]{}$;`^,#' or char.isspace() or ord(char) > 127):
|
||||
return '\0_'
|
||||
return '' if unicodedata.category(char)[0] in 'CM' else '\0_'
|
||||
return char
|
||||
|
||||
# Replace look-alike Unicode glyphs
|
||||
@@ -1887,6 +1885,7 @@ def setproctitle(title):
|
||||
buf = ctypes.create_string_buffer(len(title_bytes))
|
||||
buf.value = title_bytes
|
||||
try:
|
||||
# PR_SET_NAME = 15 Ref: /usr/include/linux/prctl.h
|
||||
libc.prctl(15, buf, 0, 0, 0)
|
||||
except AttributeError:
|
||||
return # Strange libc, just skip this
|
||||
@@ -2267,6 +2266,9 @@ class PagedList:
|
||||
raise self.IndexError()
|
||||
return entries[0]
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self.getslice(0, 1))
|
||||
|
||||
|
||||
class OnDemandPagedList(PagedList):
|
||||
"""Download pages until a page with less than maximum results"""
|
||||
@@ -4446,10 +4448,12 @@ def write_xattr(path, key, value):
|
||||
raise XAttrMetadataError(e.errno, e.strerror)
|
||||
return
|
||||
|
||||
# UNIX Method 1. Use xattrs/pyxattrs modules
|
||||
# UNIX Method 1. Use os.setxattr/xattrs/pyxattrs modules
|
||||
|
||||
setxattr = None
|
||||
if getattr(xattr, '_yt_dlp__identifier', None) == 'pyxattr':
|
||||
if callable(getattr(os, 'setxattr', None)):
|
||||
setxattr = os.setxattr
|
||||
elif getattr(xattr, '_yt_dlp__identifier', None) == 'pyxattr':
|
||||
# Unicode arguments are not supported in pyxattr until version 0.5.0
|
||||
# See https://github.com/ytdl-org/youtube-dl/issues/5498
|
||||
if version_tuple(xattr.__version__) >= (0, 5, 0):
|
||||
@@ -4794,8 +4798,9 @@ def parse_http_range(range):
|
||||
|
||||
|
||||
def read_stdin(what):
|
||||
eof = 'Ctrl+Z' if compat_os_name == 'nt' else 'Ctrl+D'
|
||||
write_string(f'Reading {what} from STDIN - EOF ({eof}) to end:\n')
|
||||
if what:
|
||||
eof = 'Ctrl+Z' if compat_os_name == 'nt' else 'Ctrl+D'
|
||||
write_string(f'Reading {what} from STDIN - EOF ({eof}) to end:\n')
|
||||
return sys.stdin
|
||||
|
||||
|
||||
@@ -4926,77 +4931,6 @@ class Config:
|
||||
return self.parser.parse_args(self.all_args)
|
||||
|
||||
|
||||
class WebSocketsWrapper:
|
||||
"""Wraps websockets module to use in non-async scopes"""
|
||||
pool = None
|
||||
|
||||
def __init__(self, url, headers=None, connect=True):
|
||||
self.loop = asyncio.new_event_loop()
|
||||
# XXX: "loop" is deprecated
|
||||
self.conn = websockets.connect(
|
||||
url, extra_headers=headers, ping_interval=None,
|
||||
close_timeout=float('inf'), loop=self.loop, ping_timeout=float('inf'))
|
||||
if connect:
|
||||
self.__enter__()
|
||||
atexit.register(self.__exit__, None, None, None)
|
||||
|
||||
def __enter__(self):
|
||||
if not self.pool:
|
||||
self.pool = self.run_with_loop(self.conn.__aenter__(), self.loop)
|
||||
return self
|
||||
|
||||
def send(self, *args):
|
||||
self.run_with_loop(self.pool.send(*args), self.loop)
|
||||
|
||||
def recv(self, *args):
|
||||
return self.run_with_loop(self.pool.recv(*args), self.loop)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
try:
|
||||
return self.run_with_loop(self.conn.__aexit__(type, value, traceback), self.loop)
|
||||
finally:
|
||||
self.loop.close()
|
||||
self._cancel_all_tasks(self.loop)
|
||||
|
||||
# taken from https://github.com/python/cpython/blob/3.9/Lib/asyncio/runners.py with modifications
|
||||
# for contributors: If there's any new library using asyncio needs to be run in non-async, move these function out of this class
|
||||
@staticmethod
|
||||
def run_with_loop(main, loop):
|
||||
if not asyncio.iscoroutine(main):
|
||||
raise ValueError(f'a coroutine was expected, got {main!r}')
|
||||
|
||||
try:
|
||||
return loop.run_until_complete(main)
|
||||
finally:
|
||||
loop.run_until_complete(loop.shutdown_asyncgens())
|
||||
if hasattr(loop, 'shutdown_default_executor'):
|
||||
loop.run_until_complete(loop.shutdown_default_executor())
|
||||
|
||||
@staticmethod
|
||||
def _cancel_all_tasks(loop):
|
||||
to_cancel = asyncio.all_tasks(loop)
|
||||
|
||||
if not to_cancel:
|
||||
return
|
||||
|
||||
for task in to_cancel:
|
||||
task.cancel()
|
||||
|
||||
# XXX: "loop" is removed in python 3.10+
|
||||
loop.run_until_complete(
|
||||
asyncio.gather(*to_cancel, loop=loop, return_exceptions=True))
|
||||
|
||||
for task in to_cancel:
|
||||
if task.cancelled():
|
||||
continue
|
||||
if task.exception() is not None:
|
||||
loop.call_exception_handler({
|
||||
'message': 'unhandled exception during asyncio.run() shutdown',
|
||||
'exception': task.exception(),
|
||||
'task': task,
|
||||
})
|
||||
|
||||
|
||||
def merge_headers(*dicts):
|
||||
"""Merge dicts of http headers case insensitively, prioritizing the latter ones"""
|
||||
return {k.title(): v for k, v in itertools.chain.from_iterable(map(dict.items, dicts))}
|
||||
@@ -5145,7 +5079,7 @@ def truncate_string(s, left, right=0):
|
||||
assert left > 3 and right >= 0
|
||||
if s is None or len(s) <= left + right:
|
||||
return s
|
||||
return f'{s[:left-3]}...{s[-right:] if right else ""}'
|
||||
return f'{s[:left - 3]}...{s[-right:] if right else ""}'
|
||||
|
||||
|
||||
def orderedSet_from_options(options, alias_dict, *, use_regex=False, start=None):
|
||||
|
||||
Reference in New Issue
Block a user