transplant 0f6e296a8ec97bce781b722bbaf4cff95642d253
[youtube-dl.git] / youtube_dl / __init__.py
index 0f9eecc..7772315 100755 (executable)
@@ -18,12 +18,14 @@ __authors__  = (
        )
 
 __license__ = 'Public Domain'
-__version__ = '2012.01.05'
+__version__ = '2012.02.27'
 
 UPDATE_URL = 'https://raw.github.com/rg3/youtube-dl/master/youtube-dl'
 
+
 import cookielib
 import datetime
+import getpass
 import gzip
 import htmlentitydefs
 import HTMLParser
@@ -31,9 +33,11 @@ import httplib
 import locale
 import math
 import netrc
+import optparse
 import os
 import os.path
 import re
+import shlex
 import socket
 import string
 import subprocess
@@ -305,7 +309,14 @@ def _encodeFilename(s):
        """
 
        assert type(s) == type(u'')
-       return s.encode(sys.getfilesystemencoding(), 'ignore')
+
+       if sys.platform == 'win32' and sys.getwindowsversion().major >= 5:
+               # Pass u'' directly to use Unicode APIs on Windows 2000 and up
+               # (Detecting Windows NT 4 is tricky because 'major >= 4' would
+               # match Windows 9x series as well. Besides, NT 4 is obsolete.)
+               return s
+       else:
+               return s.encode(sys.getfilesystemencoding(), 'ignore')
 
 class DownloadError(Exception):
        """Download Error exception.
@@ -889,7 +900,15 @@ class FileDownloader(object):
                # the connection was interrumpted and resuming appears to be
                # possible. This is part of rtmpdump's normal usage, AFAIK.
                basic_args = ['rtmpdump', '-q'] + [[], ['-W', player_url]][player_url is not None] + ['-r', url, '-o', tmpfilename]
-               retval = subprocess.call(basic_args + [[], ['-e', '-k', '1']][self.params.get('continuedl', False)])
+               args = basic_args + [[], ['-e', '-k', '1']][self.params.get('continuedl', False)]
+               if self.params.get('verbose', False):
+                       try:
+                               import pipes
+                               shell_quote = lambda args: ' '.join(map(pipes.quote, args))
+                       except ImportError:
+                               shell_quote = repr
+                       self.to_screen(u'[debug] rtmpdump command line: ' + shell_quote(args))
+               retval = subprocess.call(args)
                while retval == 2 or retval == 1:
                        prevsize = os.path.getsize(_encodeFilename(tmpfilename))
                        self.to_screen(u'\r[rtmpdump] %s bytes' % prevsize, skip_eol=True)
@@ -1362,10 +1381,9 @@ class YoutubeIE(InfoExtractor):
                        lxml.etree
                except NameError:
                        video_description = u'No description available.'
-                       if self._downloader.params.get('forcedescription', False) or self._downloader.params.get('writedescription', False):
-                               mobj = re.search(r'<meta name="description" content="(.*)"(?:\s*/)?>', video_webpage)
-                               if mobj is not None:
-                                       video_description = mobj.group(1).decode('utf-8')
+                       mobj = re.search(r'<meta name="description" content="(.*?)">', video_webpage)
+                       if mobj is not None:
+                               video_description = mobj.group(1).decode('utf-8')
                else:
                        html_parser = lxml.etree.HTMLParser(encoding='utf-8')
                        vwebpage_doc = lxml.etree.parse(StringIO.StringIO(video_webpage), html_parser)
@@ -2322,8 +2340,8 @@ class GoogleSearchIE(InfoExtractor):
        """Information Extractor for Google Video search queries."""
        _VALID_URL = r'gvsearch(\d+|all)?:[\s\S]+'
        _TEMPLATE_URL = 'http://video.google.com/videosearch?q=%s+site:video.google.com&start=%s&hl=en'
-       _VIDEO_INDICATOR = r'videoplay\?docid=([^\&>]+)\&'
-       _MORE_PAGES_INDICATOR = r'<span>Next</span>'
+       _VIDEO_INDICATOR = r'<a href="http://video\.google\.com/videoplay\?docid=([^"\&]+)'
+       _MORE_PAGES_INDICATOR = r'class="pn" id="pnnext"'
        _google_ie = None
        _max_google_results = 1000
        IE_NAME = u'video.google:search'
@@ -2374,12 +2392,11 @@ class GoogleSearchIE(InfoExtractor):
                """Downloads a specified number of results for a query"""
 
                video_ids = []
-               already_seen = set()
-               pagenum = 1
+               pagenum = 0
 
                while True:
                        self.report_download_page(query, pagenum)
-                       result_url = self._TEMPLATE_URL % (urllib.quote_plus(query), pagenum)
+                       result_url = self._TEMPLATE_URL % (urllib.quote_plus(query), pagenum*10)
                        request = urllib2.Request(result_url)
                        try:
                                page = urllib2.urlopen(request).read()
@@ -2390,9 +2407,8 @@ class GoogleSearchIE(InfoExtractor):
                        # Extract video identifiers
                        for mobj in re.finditer(self._VIDEO_INDICATOR, page):
                                video_id = mobj.group(1)
-                               if video_id not in already_seen:
+                               if video_id not in video_ids:
                                        video_ids.append(video_id)
-                                       already_seen.add(video_id)
                                        if len(video_ids) == n:
                                                # Specified n videos reached
                                                for id in video_ids:
@@ -2652,7 +2668,7 @@ class YoutubeUserIE(InfoExtractor):
                else:
                        video_ids = video_ids[playliststart:playlistend]
 
-               self._downloader.to_screen("[youtube] user %s: Collected %d video ids (downloading %d of them)" %
+               self._downloader.to_screen(u"[youtube] user %s: Collected %d video ids (downloading %d of them)" %
                                (username, all_ids_count, len(video_ids)))
 
                for video_id in video_ids:
@@ -4170,7 +4186,7 @@ def updateSelf(downloader, filename):
        if not os.access(filename, os.W_OK):
                sys.exit('ERROR: no write permissions on %s' % filename)
 
-       downloader.to_screen('Updating to latest version...')
+       downloader.to_screen(u'Updating to latest version...')
 
        try:
                try:
@@ -4179,7 +4195,7 @@ def updateSelf(downloader, filename):
                        
                        vmatch = re.search("__version__ = '([^']+)'", newcontent)
                        if vmatch is not None and vmatch.group(1) == __version__:
-                               downloader.to_screen('youtube-dl is up-to-date (' + __version__ + ')')
+                               downloader.to_screen(u'youtube-dl is up-to-date (' + __version__ + ')')
                                return
                finally:
                        urlh.close()
@@ -4195,14 +4211,9 @@ def updateSelf(downloader, filename):
        except (IOError, OSError), err:
                sys.exit('ERROR: unable to overwrite current version')
 
-       downloader.to_screen('Updated youtube-dl. Restart youtube-dl to use the new version.')
+       downloader.to_screen(u'Updated youtube-dl. Restart youtube-dl to use the new version.')
 
 def parseOpts():
-       # Deferred imports
-       import getpass
-       import optparse
-       import shlex
-
        def _readOptions(filename_bytes):
                try:
                        optionf = open(filename_bytes)
@@ -4344,6 +4355,8 @@ def parseOpts():
        verbosity.add_option('--console-title',
                        action='store_true', dest='consoletitle',
                        help='display progress in console titlebar', default=False)
+       verbosity.add_option('-v', '--verbose',
+                       action='store_true', dest='verbose', help='print various debugging information', default=False)
 
 
        filesystem.add_option('-t', '--title',
@@ -4360,7 +4373,7 @@ def parseOpts():
        filesystem.add_option('-w', '--no-overwrites',
                        action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
        filesystem.add_option('-c', '--continue',
-                       action='store_true', dest='continue_dl', help='resume partially downloaded files', default=False)
+                       action='store_true', dest='continue_dl', help='resume partially downloaded files', default=True)
        filesystem.add_option('--no-continue',
                        action='store_false', dest='continue_dl',
                        help='do not resume partially downloaded files (restart from beginning)')
@@ -4480,10 +4493,14 @@ def _real_main():
 
        # General configuration
        cookie_processor = urllib2.HTTPCookieProcessor(jar)
-       opener = urllib2.build_opener(urllib2.ProxyHandler(), cookie_processor, YoutubeDLHandler())
+       proxy_handler = urllib2.ProxyHandler()
+       opener = urllib2.build_opener(proxy_handler, cookie_processor, YoutubeDLHandler())
        urllib2.install_opener(opener)
        socket.setdefaulttimeout(300) # 5 minutes should be enough (famous last words)
 
+       if opts.verbose:
+               print(u'[debug] Proxy map: ' + str(proxy_handler.proxies))
+
        extractors = gen_extractors()
 
        if opts.list_extractors:
@@ -4577,6 +4594,7 @@ def _real_main():
                'rejecttitle': opts.rejecttitle,
                'max_downloads': opts.max_downloads,
                'prefer_free_formats': opts.prefer_free_formats,
+               'verbose': opts.verbose,
                })
        for extractor in extractors:
                fd.add_info_extractor(extractor)