diff --git a/README.md b/README.md index 0f9a7d556..0f0a5e87a 100644 --- a/README.md +++ b/README.md @@ -400,6 +400,13 @@ ## Network Options: e.g. socks5://user:pass@127.0.0.1:1080/. Pass in an empty string (--proxy "") for direct connection + --url-prefix URL Prepend the specified URL prefix to every request URL. + For example, if you set the URL prefix to + `http://127.0.0.1:1080/`, a request originally aimed at + `https://url.com` will be modified to + `http://127.0.0.1:1080/https://url.com`. + pass in an empty string (i.e., `--url-prefix ""`) to use + the original request URLs directly --socket-timeout SECONDS Time to wait before giving up, in seconds --source-address IP Client-side IP address to bind to --impersonate CLIENT[:OS] Client to impersonate for requests. E.g. diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 309489672..3e55a7219 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -360,6 +360,7 @@ class YoutubeDL: enable_file_urls: Enable file:// URLs. This is disabled by default for security reasons. http_headers: A dictionary of custom headers to be used for all requests proxy: URL of the proxy server to use + url_prefix: Prepend the specified URL prefix to every request URL geo_verification_proxy: URL of the proxy to use for IP address verification on geo-restricted sites. socket_timeout: Time to wait for unresponsive hosts, in seconds @@ -4242,7 +4243,7 @@ def build_request_director(self, handlers, preferences=None): clean_headers(headers) clean_proxies(proxies, headers) - director = RequestDirector(logger=logger, verbose=self.params.get('debug_printtraffic')) + director = RequestDirector(url_prefix=self.params.get('url_prefix'), logger=logger, verbose=self.params.get('debug_printtraffic')) for handler in handlers: director.add_handler(handler( logger=logger, diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 714d9ad5c..91caa6e79 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -920,6 +920,7 @@ def parse_options(argv=None): 'enable_file_urls': opts.enable_file_urls, 'http_headers': opts.headers, 'proxy': opts.proxy, + 'url_prefix': opts.url_prefix, 'socket_timeout': opts.socket_timeout, 'bidi_workaround': opts.bidi_workaround, 'debug_printtraffic': opts.debug_printtraffic, diff --git a/yt_dlp/networking/common.py b/yt_dlp/networking/common.py index e33769422..190e910e7 100644 --- a/yt_dlp/networking/common.py +++ b/yt_dlp/networking/common.py @@ -61,10 +61,11 @@ class RequestDirector: @param verbose: Print debug request information to stdout. """ - def __init__(self, logger, verbose=False): + def __init__(self, logger, url_prefix=None, verbose=False): self.handlers: dict[str, RequestHandler] = {} self.preferences: set[Preference] = set() self.logger = logger # TODO(Grub4k): default logger + self.url_prefix = url_prefix self.verbose = verbose def close(self): @@ -100,6 +101,10 @@ def send(self, request: Request) -> Response: assert isinstance(request, Request) + # Add url_prefix to request url + if self.url_prefix: + request.url = f'{self.url_prefix}{request.url}' + unexpected_errors = [] unsupported_errors = [] for handler in self._get_handlers(request): diff --git a/yt_dlp/options.py b/yt_dlp/options.py index b4d3d4d66..b5fd7976c 100644 --- a/yt_dlp/options.py +++ b/yt_dlp/options.py @@ -571,6 +571,13 @@ def _preset_alias_callback(option, opt_str, value, parser): help=( 'Use the specified HTTP/HTTPS/SOCKS proxy. To enable SOCKS proxy, specify a proper scheme, ' 'e.g. socks5://user:pass@127.0.0.1:1080/. Pass in an empty string (--proxy "") for direct connection')) + network.add_option( + '--url-prefix', dest='url_prefix', + default=None, metavar='URL', + help=( + 'Prepend the specified URL prefix to every request URL. For example, if you set the URL prefix to `http://127.0.0.1:1080/`, ' + 'a request originally aimed at `https://request.url` will be modified to `http://127.0.0.1:1080/https://request.url`. ' + 'pass in an empty string (i.e., `--url-prefix ""`) to use the original request URLs directly')) network.add_option( '--socket-timeout', dest='socket_timeout', type=float, default=None, metavar='SECONDS',