1 from __future__ 
import unicode_literals
 
  13     import urllib
.request 
as compat_urllib_request
 
  14 except ImportError:  # Python 2 
  15     import urllib2 
as compat_urllib_request
 
  18     import urllib
.error 
as compat_urllib_error
 
  19 except ImportError:  # Python 2 
  20     import urllib2 
as compat_urllib_error
 
  23     import urllib
.parse 
as compat_urllib_parse
 
  24 except ImportError:  # Python 2 
  25     import urllib 
as compat_urllib_parse
 
  28     from urllib
.parse 
import urlparse 
as compat_urllib_parse_urlparse
 
  29 except ImportError:  # Python 2 
  30     from urlparse 
import urlparse 
as compat_urllib_parse_urlparse
 
  33     import urllib
.parse 
as compat_urlparse
 
  34 except ImportError:  # Python 2 
  35     import urlparse 
as compat_urlparse
 
  38     import http
.cookiejar 
as compat_cookiejar
 
  39 except ImportError:  # Python 2 
  40     import cookielib 
as compat_cookiejar
 
  43     import html
.entities 
as compat_html_entities
 
  44 except ImportError:  # Python 2 
  45     import htmlentitydefs 
as compat_html_entities
 
  48     import html
.parser 
as compat_html_parser
 
  49 except ImportError:  # Python 2 
  50     import HTMLParser 
as compat_html_parser
 
  53     import http
.client 
as compat_http_client
 
  54 except ImportError:  # Python 2 
  55     import httplib 
as compat_http_client
 
  58     from urllib
.error 
import HTTPError 
as compat_HTTPError
 
  59 except ImportError:  # Python 2 
  60     from urllib2 
import HTTPError 
as compat_HTTPError
 
  63     from urllib
.request 
import urlretrieve 
as compat_urlretrieve
 
  64 except ImportError:  # Python 2 
  65     from urllib 
import urlretrieve 
as compat_urlretrieve
 
  69     from subprocess 
import DEVNULL
 
  70     compat_subprocess_get_DEVNULL 
= lambda: DEVNULL
 
  72     compat_subprocess_get_DEVNULL 
= lambda: open(os
.path
.devnull
, 'w') 
  75     import http
.server 
as compat_http_server
 
  77     import BaseHTTPServer 
as compat_http_server
 
  80     from urllib
.parse 
import unquote 
as compat_urllib_parse_unquote
 
  82     def compat_urllib_parse_unquote(string
, encoding
='utf-8', errors
='replace'): 
  85         res 
= string
.split('%') 
  92         # pct_sequence: contiguous sequence of percent-encoded bytes, decoded 
  99                 pct_sequence 
+= item
[:2].decode('hex') 
 102                     # This segment was just a single percent-encoded character. 
 103                     # May be part of a sequence of code units, so delay decoding. 
 104                     # (Stored in pct_sequence). 
 108             # Encountered non-percent-encoded characters. Flush the current 
 110             string 
+= pct_sequence
.decode(encoding
, errors
) + rest
 
 113             # Flush the final pct_sequence 
 114             string 
+= pct_sequence
.decode(encoding
, errors
) 
 118     compat_str 
= unicode  # Python 2 
 123     compat_basestring 
= basestring  
# Python 2 
 125     compat_basestring 
= str 
 128     compat_chr 
= unichr  # Python 2 
 133     from xml
.etree
.ElementTree 
import ParseError 
as compat_xml_parse_error
 
 134 except ImportError:  # Python 2.6 
 135     from xml
.parsers
.expat 
import ExpatError 
as compat_xml_parse_error
 
 139     from urllib
.parse 
import parse_qs 
as compat_parse_qs
 
 140 except ImportError:  # Python 2 
 141     # HACK: The following is the correct parse_qs implementation from cpython 3's stdlib. 
 142     # Python 2's version is apparently totally broken 
 144     def _parse_qsl(qs
, keep_blank_values
=False, strict_parsing
=False, 
 145                    encoding
='utf-8', errors
='replace'): 
 146         qs
, _coerce_result 
= qs
, compat_str
 
 147         pairs 
= [s2 
for s1 
in qs
.split('&') for s2 
in s1
.split(';')] 
 149         for name_value 
in pairs
: 
 150             if not name_value 
and not strict_parsing
: 
 152             nv 
= name_value
.split('=', 1) 
 155                     raise ValueError("bad query field: %r" % (name_value
,)) 
 156                 # Handle case of a control-name with no equal sign 
 157                 if keep_blank_values
: 
 161             if len(nv
[1]) or keep_blank_values
: 
 162                 name 
= nv
[0].replace('+', ' ') 
 163                 name 
= compat_urllib_parse_unquote( 
 164                     name
, encoding
=encoding
, errors
=errors
) 
 165                 name 
= _coerce_result(name
) 
 166                 value 
= nv
[1].replace('+', ' ') 
 167                 value 
= compat_urllib_parse_unquote( 
 168                     value
, encoding
=encoding
, errors
=errors
) 
 169                 value 
= _coerce_result(value
) 
 170                 r
.append((name
, value
)) 
 173     def compat_parse_qs(qs
, keep_blank_values
=False, strict_parsing
=False, 
 174                         encoding
='utf-8', errors
='replace'): 
 176         pairs 
= _parse_qsl(qs
, keep_blank_values
, strict_parsing
, 
 177                            encoding
=encoding
, errors
=errors
) 
 178         for name
, value 
in pairs
: 
 179             if name 
in parsed_result
: 
 180                 parsed_result
[name
].append(value
) 
 182                 parsed_result
[name
] = [value
] 
 186     from shlex 
import quote 
as shlex_quote
 
 187 except ImportError:  # Python < 3.3 
 189         if re
.match(r
'^[-_\w./]+$', s
): 
 192             return "'" + s
.replace("'", "'\"'\"'") + "'" 
 202 if sys
.version_info 
>= (3, 0): 
 203     compat_getenv 
= os
.getenv
 
 204     compat_expanduser 
= os
.path
.expanduser
 
 206     # Environment variables should be decoded with filesystem encoding. 
 207     # Otherwise it will fail if any non-ASCII characters present (see #3854 #3217 #2918) 
 209     def compat_getenv(key
, default
=None): 
 210         from .utils 
import get_filesystem_encoding
 
 211         env 
= os
.getenv(key
, default
) 
 213             env 
= env
.decode(get_filesystem_encoding()) 
 216     # HACK: The default implementations of os.path.expanduser from cpython do not decode 
 217     # environment variables with filesystem encoding. We will work around this by 
 218     # providing adjusted implementations. 
 219     # The following are os.path.expanduser implementations from cpython 2.7.8 stdlib 
 220     # for different platforms with correct environment variables decoding. 
 222     if os
.name 
== 'posix': 
 223         def compat_expanduser(path
): 
 224             """Expand ~ and ~user constructions.  If user or $HOME is unknown, 
 226             if not path
.startswith('~'): 
 228             i 
= path
.find('/', 1) 
 232                 if 'HOME' not in os
.environ
: 
 234                     userhome 
= pwd
.getpwuid(os
.getuid()).pw_dir
 
 236                     userhome 
= compat_getenv('HOME') 
 240                     pwent 
= pwd
.getpwnam(path
[1:i
]) 
 243                 userhome 
= pwent
.pw_dir
 
 244             userhome 
= userhome
.rstrip('/') 
 245             return (userhome 
+ path
[i
:]) or '/' 
 246     elif os
.name 
== 'nt' or os
.name 
== 'ce': 
 247         def compat_expanduser(path
): 
 248             """Expand ~ and ~user constructs. 
 250             If user or $HOME is unknown, do nothing.""" 
 254             while i 
< n 
and path
[i
] not in '/\\': 
 257             if 'HOME' in os
.environ
: 
 258                 userhome 
= compat_getenv('HOME') 
 259             elif 'USERPROFILE' in os
.environ
: 
 260                 userhome 
= compat_getenv('USERPROFILE') 
 261             elif 'HOMEPATH' not in os
.environ
: 
 265                     drive 
= compat_getenv('HOMEDRIVE') 
 268                 userhome 
= os
.path
.join(drive
, compat_getenv('HOMEPATH')) 
 271                 userhome 
= os
.path
.join(os
.path
.dirname(userhome
), path
[1:i
]) 
 273             return userhome 
+ path
[i
:] 
 275         compat_expanduser 
= os
.path
.expanduser
 
 278 if sys
.version_info 
< (3, 0): 
 280         from .utils 
import preferredencoding
 
 281         print(s
.encode(preferredencoding(), 'xmlcharrefreplace')) 
 284         assert isinstance(s
, compat_str
) 
 289     subprocess_check_output 
= subprocess
.check_output
 
 290 except AttributeError: 
 291     def subprocess_check_output(*args
, **kwargs
): 
 292         assert 'input' not in kwargs
 
 293         p 
= subprocess
.Popen(*args
, stdout
=subprocess
.PIPE
, **kwargs
) 
 294         output
, _ 
= p
.communicate() 
 297             raise subprocess
.CalledProcessError(ret
, p
.args
, output
=output
) 
 300 if sys
.version_info 
< (3, 0) and sys
.platform 
== 'win32': 
 301     def compat_getpass(prompt
, *args
, **kwargs
): 
 302         if isinstance(prompt
, compat_str
): 
 303             from .utils 
import preferredencoding
 
 304             prompt 
= prompt
.encode(preferredencoding()) 
 305         return getpass
.getpass(prompt
, *args
, **kwargs
) 
 307     compat_getpass 
= getpass
.getpass
 
 309 # Old 2.6 and 2.7 releases require kwargs to be bytes 
 313     _testfunc(**{'x': 0}) 
 315     def compat_kwargs(kwargs
): 
 316         return dict((bytes(k
), v
) for k
, v 
in kwargs
.items()) 
 318     compat_kwargs 
= lambda kwargs
: kwargs
 
 321 if sys
.version_info 
< (2, 7): 
 322     def compat_socket_create_connection(address
, timeout
, source_address
=None): 
 325         for res 
in socket
.getaddrinfo(host
, port
, 0, socket
.SOCK_STREAM
): 
 326             af
, socktype
, proto
, canonname
, sa 
= res
 
 329                 sock 
= socket
.socket(af
, socktype
, proto
) 
 330                 sock
.settimeout(timeout
) 
 332                     sock
.bind(source_address
) 
 335             except socket
.error 
as _
: 
 342             raise socket
.error("getaddrinfo returns an empty list") 
 344     compat_socket_create_connection 
= socket
.create_connection
 
 347 # Fix https://github.com/rg3/youtube-dl/issues/4223 
 348 # See http://bugs.python.org/issue9161 for what is broken 
 349 def workaround_optparse_bug9161(): 
 350     op 
= optparse
.OptionParser() 
 351     og 
= optparse
.OptionGroup(op
, 'foo') 
 355         real_add_option 
= optparse
.OptionGroup
.add_option
 
 357         def _compat_add_option(self
, *args
, **kwargs
): 
 359                 v
.encode('ascii', 'replace') if isinstance(v
, compat_str
) 
 361             bargs 
= [enc(a
) for a 
in args
] 
 363                 (k
, enc(v
)) for k
, v 
in kwargs
.items()) 
 364             return real_add_option(self
, *bargs
, **bkwargs
) 
 365         optparse
.OptionGroup
.add_option 
= _compat_add_option
 
 376     'compat_html_entities', 
 377     'compat_html_parser', 
 378     'compat_http_client', 
 379     'compat_http_server', 
 384     'compat_socket_create_connection', 
 386     'compat_subprocess_get_DEVNULL', 
 387     'compat_urllib_error', 
 388     'compat_urllib_parse', 
 389     'compat_urllib_parse_unquote', 
 390     'compat_urllib_parse_urlparse', 
 391     'compat_urllib_request', 
 393     'compat_urlretrieve', 
 394     'compat_xml_parse_error', 
 396     'subprocess_check_output', 
 397     'workaround_optparse_bug9161',