Add --socks-proxy parameter to use SOCKS proxy

This allows the user to specify a socks proxy to
tunnel the connection through. This feature requires that
PySocks is available. If the user tries to use a SOCKS proxy
without PySocks available an error is printed and the process is
aborted.
This commit is contained in:
Marco 'don' Kaulea 2015-07-24 21:45:00 +02:00
parent 725d1c58aa
commit 8e30e9ed17
4 changed files with 57 additions and 2 deletions

View File

@ -52,6 +52,7 @@ from .utils import (
locked_file,
make_HTTPS_handler,
MaxDownloadsReached,
OptionalDependencyNotFound,
PagedList,
parse_filesize,
PerRequestProxyHandler,
@ -1953,11 +1954,39 @@ class YoutubeDL(object):
proxies['https'] = proxies['http']
proxy_handler = PerRequestProxyHandler(proxies)
socks_handler = None
opts_socks = self.params.get('socksproxy')
if opts_socks is not None and opts_socks:
# Try to import the dependencies for this feature
try:
import socks
except ImportError:
raise OptionalDependencyNotFound(module_name='socks',
feature_name='--socks-proxy')
try:
from sockshandler import SocksiPyHandler
except ImportError:
raise OptionalDependencyNotFound(module_name='sockshandler',
feature_name='--socks-proxy')
pair = opts_socks.split(':')
if len(pair) == 2:
socks_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5,
pair[0],
int(pair[1]))
else:
socks_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5,
'localhost',
int(pair[0]))
debuglevel = 1 if self.params.get('debug_printtraffic') else 0
https_handler = make_HTTPS_handler(self.params, debuglevel=debuglevel)
ydlh = YoutubeDLHandler(self.params, debuglevel=debuglevel)
opener = compat_urllib_request.build_opener(
proxy_handler, https_handler, cookie_processor, ydlh)
proxy_list = []
if socks_handler:
proxy_list.append(socks_handler)
proxy_list += [proxy_handler, https_handler, cookie_processor, ydlh]
opener = compat_urllib_request.build_opener(*proxy_list)
# Delete the default user-agent header, which would otherwise apply in
# cases where our custom HTTP handler doesn't come into play

View File

@ -29,6 +29,7 @@ from .utils import (
DownloadError,
match_filter_func,
MaxDownloadsReached,
OptionalDependencyNotFound,
preferredencoding,
read_batch_urls,
SameFileError,
@ -346,6 +347,7 @@ def _real_main(argv=None):
'nocheckcertificate': opts.no_check_certificate,
'prefer_insecure': opts.prefer_insecure,
'proxy': opts.proxy,
'socksproxy': opts.socksproxy,
'socket_timeout': opts.socket_timeout,
'bidi_workaround': opts.bidi_workaround,
'debug_printtraffic': opts.debug_printtraffic,
@ -414,5 +416,7 @@ def main(argv=None):
sys.exit('ERROR: fixed output name but more than one file to download')
except KeyboardInterrupt:
sys.exit('\nERROR: Interrupted by user')
except OptionalDependencyNotFound as e:
sys.exit(str(e))
__all__ = ['main', 'YoutubeDL', 'gen_extractors', 'list_extractors']

View File

@ -181,6 +181,11 @@ def parseOpts(overrideArguments=None):
'--proxy', dest='proxy',
default=None, metavar='URL',
help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
network.add_option(
'--socks-proxy', dest='socksproxy', default=None, metavar='URL',
help=('Use the specified socks proxy. Pass in an empty string '
'(--socks-proxy "") for direct connection. This feature requires'
'the pysocks library.'))
network.add_option(
'--socket-timeout',
dest='socket_timeout', type=float, default=None, metavar='SECONDS',

View File

@ -586,6 +586,23 @@ class ContentTooShortError(Exception):
self.expected = expected
class OptionalDependencyNotFound(Exception):
"""Optional dependency not found
This exception may be raised by YoutubeDL, when the user tries to use a
feature that requires an optional dependency which could not be found.
"""
def __init__(self, module_name, feature_name):
self.module_name = str(module_name)
self.feature_name = str(feature_name)
def __str__(self):
return ("Unable to use '{feature}', because it depends on '{module}' "
"which was not found.").format(
feature=self.feature_name, module=self.module_name)
def _create_http_connection(ydl_handler, http_class, is_https, *args, **kwargs):
# Working around python 2 bug (see http://bugs.python.org/issue17849) by limiting
# expected HTTP responses to meet HTTP/1.0 or later (see also