1 from __future__ 
import unicode_literals
 
  15     import urllib
.request 
as compat_urllib_request
 
  16 except ImportError:  # Python 2 
  17     import urllib2 
as compat_urllib_request
 
  20     import urllib
.error 
as compat_urllib_error
 
  21 except ImportError:  # Python 2 
  22     import urllib2 
as compat_urllib_error
 
  25     import urllib
.parse 
as compat_urllib_parse
 
  26 except ImportError:  # Python 2 
  27     import urllib 
as compat_urllib_parse
 
  30     from urllib
.parse 
import urlparse 
as compat_urllib_parse_urlparse
 
  31 except ImportError:  # Python 2 
  32     from urlparse 
import urlparse 
as compat_urllib_parse_urlparse
 
  35     import urllib
.parse 
as compat_urlparse
 
  36 except ImportError:  # Python 2 
  37     import urlparse 
as compat_urlparse
 
  40     import http
.cookiejar 
as compat_cookiejar
 
  41 except ImportError:  # Python 2 
  42     import cookielib 
as compat_cookiejar
 
  45     import html
.entities 
as compat_html_entities
 
  46 except ImportError:  # Python 2 
  47     import htmlentitydefs 
as compat_html_entities
 
  50     import http
.client 
as compat_http_client
 
  51 except ImportError:  # Python 2 
  52     import httplib 
as compat_http_client
 
  55     from urllib
.error 
import HTTPError 
as compat_HTTPError
 
  56 except ImportError:  # Python 2 
  57     from urllib2 
import HTTPError 
as compat_HTTPError
 
  60     from urllib
.request 
import urlretrieve 
as compat_urlretrieve
 
  61 except ImportError:  # Python 2 
  62     from urllib 
import urlretrieve 
as compat_urlretrieve
 
  66     from subprocess 
import DEVNULL
 
  67     compat_subprocess_get_DEVNULL 
= lambda: DEVNULL
 
  69     compat_subprocess_get_DEVNULL 
= lambda: open(os
.path
.devnull
, 'w') 
  72     import http
.server 
as compat_http_server
 
  74     import BaseHTTPServer 
as compat_http_server
 
  77     from urllib
.parse 
import unquote 
as compat_urllib_parse_unquote
 
  79     def compat_urllib_parse_unquote(string
, encoding
='utf-8', errors
='replace'): 
  82         res 
= string
.split('%') 
  89         # pct_sequence: contiguous sequence of percent-encoded bytes, decoded 
  96                 pct_sequence 
+= item
[:2].decode('hex') 
  99                     # This segment was just a single percent-encoded character. 
 100                     # May be part of a sequence of code units, so delay decoding. 
 101                     # (Stored in pct_sequence). 
 105             # Encountered non-percent-encoded characters. Flush the current 
 107             string 
+= pct_sequence
.decode(encoding
, errors
) + rest
 
 110             # Flush the final pct_sequence 
 111             string 
+= pct_sequence
.decode(encoding
, errors
) 
 115     compat_str 
= unicode  # Python 2 
 120     compat_basestring 
= basestring  
# Python 2 
 122     compat_basestring 
= str 
 125     compat_chr 
= unichr  # Python 2 
 130     from xml
.etree
.ElementTree 
import ParseError 
as compat_xml_parse_error
 
 131 except ImportError:  # Python 2.6 
 132     from xml
.parsers
.expat 
import ExpatError 
as compat_xml_parse_error
 
 136     from urllib
.parse 
import parse_qs 
as compat_parse_qs
 
 137 except ImportError:  # Python 2 
 138     # HACK: The following is the correct parse_qs implementation from cpython 3's stdlib. 
 139     # Python 2's version is apparently totally broken 
 141     def _parse_qsl(qs
, keep_blank_values
=False, strict_parsing
=False, 
 142                    encoding
='utf-8', errors
='replace'): 
 143         qs
, _coerce_result 
= qs
, compat_str
 
 144         pairs 
= [s2 
for s1 
in qs
.split('&') for s2 
in s1
.split(';')] 
 146         for name_value 
in pairs
: 
 147             if not name_value 
and not strict_parsing
: 
 149             nv 
= name_value
.split('=', 1) 
 152                     raise ValueError("bad query field: %r" % (name_value
,)) 
 153                 # Handle case of a control-name with no equal sign 
 154                 if keep_blank_values
: 
 158             if len(nv
[1]) or keep_blank_values
: 
 159                 name 
= nv
[0].replace('+', ' ') 
 160                 name 
= compat_urllib_parse_unquote( 
 161                     name
, encoding
=encoding
, errors
=errors
) 
 162                 name 
= _coerce_result(name
) 
 163                 value 
= nv
[1].replace('+', ' ') 
 164                 value 
= compat_urllib_parse_unquote( 
 165                     value
, encoding
=encoding
, errors
=errors
) 
 166                 value 
= _coerce_result(value
) 
 167                 r
.append((name
, value
)) 
 170     def compat_parse_qs(qs
, keep_blank_values
=False, strict_parsing
=False, 
 171                         encoding
='utf-8', errors
='replace'): 
 173         pairs 
= _parse_qsl(qs
, keep_blank_values
, strict_parsing
, 
 174                            encoding
=encoding
, errors
=errors
) 
 175         for name
, value 
in pairs
: 
 176             if name 
in parsed_result
: 
 177                 parsed_result
[name
].append(value
) 
 179                 parsed_result
[name
] = [value
] 
 183     from shlex 
import quote 
as shlex_quote
 
 184 except ImportError:  # Python < 3.3 
 186         if re
.match(r
'^[-_\w./]+$', s
): 
 189             return "'" + s
.replace("'", "'\"'\"'") + "'" 
 199 if sys
.version_info 
>= (3, 0): 
 200     compat_getenv 
= os
.getenv
 
 201     compat_expanduser 
= os
.path
.expanduser
 
 203     # Environment variables should be decoded with filesystem encoding. 
 204     # Otherwise it will fail if any non-ASCII characters present (see #3854 #3217 #2918) 
 206     def compat_getenv(key
, default
=None): 
 207         from .utils 
import get_filesystem_encoding
 
 208         env 
= os
.getenv(key
, default
) 
 210             env 
= env
.decode(get_filesystem_encoding()) 
 213     # HACK: The default implementations of os.path.expanduser from cpython do not decode 
 214     # environment variables with filesystem encoding. We will work around this by 
 215     # providing adjusted implementations. 
 216     # The following are os.path.expanduser implementations from cpython 2.7.8 stdlib 
 217     # for different platforms with correct environment variables decoding. 
 219     if os
.name 
== 'posix': 
 220         def compat_expanduser(path
): 
 221             """Expand ~ and ~user constructions.  If user or $HOME is unknown, 
 223             if not path
.startswith('~'): 
 225             i 
= path
.find('/', 1) 
 229                 if 'HOME' not in os
.environ
: 
 231                     userhome 
= pwd
.getpwuid(os
.getuid()).pw_dir
 
 233                     userhome 
= compat_getenv('HOME') 
 237                     pwent 
= pwd
.getpwnam(path
[1:i
]) 
 240                 userhome 
= pwent
.pw_dir
 
 241             userhome 
= userhome
.rstrip('/') 
 242             return (userhome 
+ path
[i
:]) or '/' 
 243     elif os
.name 
== 'nt' or os
.name 
== 'ce': 
 244         def compat_expanduser(path
): 
 245             """Expand ~ and ~user constructs. 
 247             If user or $HOME is unknown, do nothing.""" 
 251             while i 
< n 
and path
[i
] not in '/\\': 
 254             if 'HOME' in os
.environ
: 
 255                 userhome 
= compat_getenv('HOME') 
 256             elif 'USERPROFILE' in os
.environ
: 
 257                 userhome 
= compat_getenv('USERPROFILE') 
 258             elif 'HOMEPATH' not in os
.environ
: 
 262                     drive 
= compat_getenv('HOMEDRIVE') 
 265                 userhome 
= os
.path
.join(drive
, compat_getenv('HOMEPATH')) 
 268                 userhome 
= os
.path
.join(os
.path
.dirname(userhome
), path
[1:i
]) 
 270             return userhome 
+ path
[i
:] 
 272         compat_expanduser 
= os
.path
.expanduser
 
 275 if sys
.version_info 
< (3, 0): 
 277         from .utils 
import preferredencoding
 
 278         print(s
.encode(preferredencoding(), 'xmlcharrefreplace')) 
 281         assert isinstance(s
, compat_str
) 
 286     subprocess_check_output 
= subprocess
.check_output
 
 287 except AttributeError: 
 288     def subprocess_check_output(*args
, **kwargs
): 
 289         assert 'input' not in kwargs
 
 290         p 
= subprocess
.Popen(*args
, stdout
=subprocess
.PIPE
, **kwargs
) 
 291         output
, _ 
= p
.communicate() 
 294             raise subprocess
.CalledProcessError(ret
, p
.args
, output
=output
) 
 297 if sys
.version_info 
< (3, 0) and sys
.platform 
== 'win32': 
 298     def compat_getpass(prompt
, *args
, **kwargs
): 
 299         if isinstance(prompt
, compat_str
): 
 300             from .utils 
import preferredencoding
 
 301             prompt 
= prompt
.encode(preferredencoding()) 
 302         return getpass
.getpass(prompt
, *args
, **kwargs
) 
 304     compat_getpass 
= getpass
.getpass
 
 306 # Old 2.6 and 2.7 releases require kwargs to be bytes 
 310     _testfunc(**{'x': 0}) 
 312     def compat_kwargs(kwargs
): 
 313         return dict((bytes(k
), v
) for k
, v 
in kwargs
.items()) 
 315     compat_kwargs 
= lambda kwargs
: kwargs
 
 318 if sys
.version_info 
< (2, 7): 
 319     def compat_socket_create_connection(address
, timeout
, source_address
=None): 
 322         for res 
in socket
.getaddrinfo(host
, port
, 0, socket
.SOCK_STREAM
): 
 323             af
, socktype
, proto
, canonname
, sa 
= res
 
 326                 sock 
= socket
.socket(af
, socktype
, proto
) 
 327                 sock
.settimeout(timeout
) 
 329                     sock
.bind(source_address
) 
 332             except socket
.error 
as _
: 
 339             raise socket
.error("getaddrinfo returns an empty list") 
 341     compat_socket_create_connection 
= socket
.create_connection
 
 344 # Fix https://github.com/rg3/youtube-dl/issues/4223 
 345 # See http://bugs.python.org/issue9161 for what is broken 
 346 def workaround_optparse_bug9161(): 
 347     op 
= optparse
.OptionParser() 
 348     og 
= optparse
.OptionGroup(op
, 'foo') 
 352         real_add_option 
= optparse
.OptionGroup
.add_option
 
 354         def _compat_add_option(self
, *args
, **kwargs
): 
 356                 v
.encode('ascii', 'replace') if isinstance(v
, compat_str
) 
 358             bargs 
= [enc(a
) for a 
in args
] 
 360                 (k
, enc(v
)) for k
, v 
in kwargs
.items()) 
 361             return real_add_option(self
, *bargs
, **bkwargs
) 
 362         optparse
.OptionGroup
.add_option 
= _compat_add_option
 
 364 if hasattr(shutil
, 'get_terminal_size'):  # Python >= 3.3 
 365     compat_get_terminal_size 
= shutil
.get_terminal_size
 
 367     _terminal_size 
= collections
.namedtuple('terminal_size', ['columns', 'lines']) 
 369     def compat_get_terminal_size(): 
 370         columns 
= compat_getenv('COLUMNS', None) 
 372             columns 
= int(columns
) 
 375         lines 
= compat_getenv('LINES', None) 
 382             sp 
= subprocess
.Popen( 
 384                 stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
) 
 385             out
, err 
= sp
.communicate() 
 386             lines
, columns 
= map(int, out
.split()) 
 389         return _terminal_size(columns
, lines
) 
 398     'compat_get_terminal_size', 
 401     'compat_html_entities', 
 402     'compat_http_client', 
 403     'compat_http_server', 
 408     'compat_socket_create_connection', 
 410     'compat_subprocess_get_DEVNULL', 
 411     'compat_urllib_error', 
 412     'compat_urllib_parse', 
 413     'compat_urllib_parse_unquote', 
 414     'compat_urllib_parse_urlparse', 
 415     'compat_urllib_request', 
 417     'compat_urlretrieve', 
 418     'compat_xml_parse_error', 
 420     'subprocess_check_output', 
 421     'workaround_optparse_bug9161',