Skip to content

Commit

Permalink
yt_dlp: db7b054a6111ca387220d0eb87bf342f9c130eb8
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Aug 4, 2023
1 parent cd22a5e commit b2f755f
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
7 changes: 4 additions & 3 deletions lib/yt_dlp/YoutubeDL.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from .extractor.openload import PhantomJSwrapper
from .minicurses import format_text
from .networking import HEADRequest, Request, RequestDirector
from .networking.common import _REQUEST_HANDLERS
from .networking.common import _REQUEST_HANDLERS, _RH_PREFERENCES
from .networking.exceptions import (
HTTPError,
NoSupportingHandlers,
Expand Down Expand Up @@ -683,7 +683,7 @@ def process_color_policy(stream):
self.params['http_headers'] = HTTPHeaderDict(std_headers, self.params.get('http_headers'))
self._load_cookies(self.params['http_headers'].get('Cookie')) # compat
self.params['http_headers'].pop('Cookie', None)
self._request_director = self.build_request_director(_REQUEST_HANDLERS.values())
self._request_director = self.build_request_director(_REQUEST_HANDLERS.values(), _RH_PREFERENCES)

if auto_init and auto_init != 'no_verbose_header':
self.print_debug_header()
Expand Down Expand Up @@ -4077,7 +4077,7 @@ def urlopen(self, req):
except HTTPError as e: # TODO: Remove in a future release
raise _CompatHTTPError(e) from e

def build_request_director(self, handlers):
def build_request_director(self, handlers, preferences=None):
logger = _YDLLogger(self)
headers = self.params['http_headers'].copy()
proxies = self.proxies.copy()
Expand Down Expand Up @@ -4106,6 +4106,7 @@ def build_request_director(self, handlers):
},
}),
))
director.preferences.update(preferences or [])
return director

def encode(self, s):
Expand Down
40 changes: 36 additions & 4 deletions lib/yt_dlp/networking/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,37 @@
)
from ..utils.networking import HTTPHeaderDict, normalize_url

if typing.TYPE_CHECKING:
RequestData = bytes | Iterable[bytes] | typing.IO | None

def register_preference(*handlers: type[RequestHandler]):
assert all(issubclass(handler, RequestHandler) for handler in handlers)

def outer(preference: Preference):
@functools.wraps(preference)
def inner(handler, *args, **kwargs):
if not handlers or isinstance(handler, handlers):
return preference(handler, *args, **kwargs)
return 0
_RH_PREFERENCES.add(inner)
return inner
return outer


class RequestDirector:
"""RequestDirector class
Helper class that, when given a request, forward it to a RequestHandler that supports it.
Preference functions in the form of func(handler, request) -> int
can be registered into the `preferences` set. These are used to sort handlers
in order of preference.
@param logger: Logger instance.
@param verbose: Print debug request information to stdout.
"""

def __init__(self, logger, verbose=False):
self.handlers: dict[str, RequestHandler] = {}
self.preferences: set[Preference] = set()
self.logger = logger # TODO(Grub4k): default logger
self.verbose = verbose

Expand All @@ -58,6 +74,16 @@ def add_handler(self, handler: RequestHandler):
assert isinstance(handler, RequestHandler), 'handler must be a RequestHandler'
self.handlers[handler.RH_KEY] = handler

def _get_handlers(self, request: Request) -> list[RequestHandler]:
"""Sorts handlers by preference, given a request"""
preferences = {
rh: sum(pref(rh, request) for pref in self.preferences)
for rh in self.handlers.values()
}
self._print_verbose('Handler preferences for this request: %s' % ', '.join(
f'{rh.RH_NAME}={pref}' for rh, pref in preferences.items()))
return sorted(self.handlers.values(), key=preferences.get, reverse=True)

def _print_verbose(self, msg):
if self.verbose:
self.logger.stdout(f'director: {msg}')
Expand All @@ -73,8 +99,7 @@ def send(self, request: Request) -> Response:

unexpected_errors = []
unsupported_errors = []
# TODO (future): add a per-request preference system
for handler in reversed(list(self.handlers.values())):
for handler in self._get_handlers(request):
self._print_verbose(f'Checking if "{handler.RH_NAME}" supports this request.')
try:
handler.validate(request)
Expand Down Expand Up @@ -530,3 +555,10 @@ def info(self):
def getheader(self, name, default=None):
deprecation_warning('Response.getheader() is deprecated, use Response.get_header', stacklevel=2)
return self.get_header(name, default)


if typing.TYPE_CHECKING:
RequestData = bytes | Iterable[bytes] | typing.IO | None
Preference = typing.Callable[[RequestHandler, Request], int]

_RH_PREFERENCES: set[Preference] = set()

0 comments on commit b2f755f

Please sign in to comment.