Improve some metavar names
[youtube-dl] / youtube-dl
index 83a4e22c05bbf06fdcbc03de4b67e489e68135ea..7bd4b2aaca5f002524ed3dec1a085b8fe76e1f4f 100755 (executable)
@@ -99,7 +99,7 @@ def sanitize_open(filename, open_mode):
                return (stream, filename)
        except (IOError, OSError), err:
                # In case of error, try to remove win32 forbidden chars
-               filename = re.sub(ur'[<>:"\|\?\*]', u'#', filename)
+               filename = re.sub(ur'[/<>:"\|\?\*]', u'#', filename)
 
                # An exception here should be caught in the caller
                stream = open(filename, open_mode)
@@ -193,6 +193,7 @@ class FileDownloader(object):
        ignoreerrors:   Do not stop on download errors.
        ratelimit:      Download speed limit, in bytes/sec.
        nooverwrites:   Prevent overwriting files.
+       retries:        Number of times to retry for HTTP error 503
        continuedl:     Try to continue downloads if possible.
        noprogress:     Do not print the progress bar.
        """
@@ -364,6 +365,10 @@ class FileDownloader(object):
                """Report attemtp to resume at given byte."""
                self.to_stdout(u'[download] Resuming download at byte %s' % resume_len)
        
+       def report_retry(self, count, retries):
+               """Report retry in case of HTTP error 503"""
+               self.to_stdout(u'[download] Got HTTP error 503. Retrying (attempt %d of %d)...' % (count, retries))
+       
        def report_file_already_downloaded(self, file_name):
                """Report file has already been fully downloaded."""
                try:
@@ -527,25 +532,34 @@ class FileDownloader(object):
                        request.add_header('Range','bytes=%d-' % resume_len)
                        open_mode = 'ab'
 
-               # Establish connection
-               try:
-                       data = urllib2.urlopen(request)
-               except (urllib2.HTTPError, ), err:
-                       if err.code != 416: #  416 is 'Requested range not satisfiable'
-                               raise
-                       # Unable to resume
-                       data = urllib2.urlopen(basic_request)
-                       content_length = data.info()['Content-Length']
-
-                       if content_length is not None and long(content_length) == resume_len:
-                               # Because the file had already been fully downloaded
-                               self.report_file_already_downloaded(filename)
-                               self._num_downloads += 1
-                               return True
-                       else:
-                               # Because the server didn't let us
-                               self.report_unable_to_resume()
-                               open_mode = 'wb'
+               count = 0
+               retries = self.params.get('retries', 0)
+               while True:
+                       # Establish connection
+                       try:
+                               data = urllib2.urlopen(request)
+                               break
+                       except (urllib2.HTTPError, ), err:
+                               if err.code == 503:
+                                       # Retry in case of HTTP error 503
+                                       count += 1
+                                       if count <= retries:
+                                               self.report_retry(count, retries)
+                                               continue
+                               if err.code != 416: #  416 is 'Requested range not satisfiable'
+                                       raise
+                               # Unable to resume
+                               data = urllib2.urlopen(basic_request)
+                               content_length = data.info()['Content-Length']
+
+                               if content_length is not None and long(content_length) == resume_len:
+                                       # Because the file had already been fully downloaded
+                                       self.report_file_already_downloaded(filename)
+                                       return True
+                               else:
+                                       # Because the server didn't let us
+                                       self.report_unable_to_resume()
+                                       open_mode = 'wb'
 
                data_len = data.info().get('Content-length', None)
                data_len_str = self.format_bytes(data_len)
@@ -677,6 +691,8 @@ class YoutubeIE(InfoExtractor):
                '18': 'mp4',
                '22': 'mp4',
                '37': 'mp4',
+               '43': 'webm',
+               '45': 'webm',
        }
 
        @staticmethod
@@ -913,17 +929,18 @@ class YoutubeIE(InfoExtractor):
                                })
 
                                if all_formats:
+                                       quality_index += 1
                                        if quality_index == len(self._available_formats):
                                                # None left to get
                                                return
                                        else:
-                                               quality_index += 1
                                                format_param = self._available_formats[quality_index]
                                                continue
                                return
 
                        except UnavailableFormatError, err:
                                if best_quality or all_formats:
+                                       quality_index += 1
                                        if quality_index == len(self._available_formats):
                                                # I don't ever expect this to happen
                                                if not all_formats:
@@ -931,7 +948,6 @@ class YoutubeIE(InfoExtractor):
                                                return
                                        else:
                                                self.report_unavailable_format(video_id, format_param)
-                                               quality_index += 1
                                                format_param = self._available_formats[quality_index]
                                                continue
                                else: 
@@ -1971,7 +1987,7 @@ if __name__ == '__main__':
                # Parse command line
                parser = optparse.OptionParser(
                        usage='Usage: %prog [options] url...',
-                       version='2010.04.04',
+                       version='2010.06.06',
                        conflict_handler='resolve',
                )
 
@@ -1984,20 +2000,22 @@ if __name__ == '__main__':
                parser.add_option('-i', '--ignore-errors',
                                action='store_true', dest='ignoreerrors', help='continue on download errors', default=False)
                parser.add_option('-r', '--rate-limit',
-                               dest='ratelimit', metavar='L', help='download rate limit (e.g. 50k or 44.6m)')
+                               dest='ratelimit', metavar='LIMIT', help='download rate limit (e.g. 50k or 44.6m)')
+               parser.add_option('-R', '--retries',
+                               dest='retries', metavar='RETRIES', help='number of retries (default is 10)', default=10)
 
                authentication = optparse.OptionGroup(parser, 'Authentication Options')
                authentication.add_option('-u', '--username',
-                               dest='username', metavar='UN', help='account username')
+                               dest='username', metavar='USERNAME', help='account username')
                authentication.add_option('-p', '--password',
-                               dest='password', metavar='PW', help='account password')
+                               dest='password', metavar='PASSWORD', help='account password')
                authentication.add_option('-n', '--netrc',
                                action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
                parser.add_option_group(authentication)
 
                video_format = optparse.OptionGroup(parser, 'Video Format Options')
                video_format.add_option('-f', '--format',
-                               action='store', dest='format', metavar='FMT', help='video format code')
+                               action='store', dest='format', metavar='FORMAT', help='video format code')
                video_format.add_option('-b', '--best-quality',
                                action='store_const', dest='format', help='download the best quality video possible', const='0')
                video_format.add_option('-m', '--mobile-version',
@@ -2031,9 +2049,9 @@ if __name__ == '__main__':
                filesystem.add_option('-l', '--literal',
                                action='store_true', dest='useliteral', help='use literal title in file name', default=False)
                filesystem.add_option('-o', '--output',
-                               dest='outtmpl', metavar='TPL', help='output filename template')
+                               dest='outtmpl', metavar='TEMPLATE', help='output filename template')
                filesystem.add_option('-a', '--batch-file',
-                               dest='batchfile', metavar='F', help='file containing URLs to download (\'-\' for stdin)')
+                               dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
                filesystem.add_option('-w', '--no-overwrites',
                                action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
                filesystem.add_option('-c', '--continue',
@@ -2073,6 +2091,11 @@ if __name__ == '__main__':
                        if numeric_limit is None:
                                parser.error(u'invalid rate limit specified')
                        opts.ratelimit = numeric_limit
+               if opts.retries is not None:
+                       try:
+                               opts.retries = long(opts.retries)
+                       except (TypeError, ValueError), err:
+                               parser.error(u'invalid retry count specified')
 
                # Information extractors
                youtube_ie = YoutubeIE()
@@ -2109,6 +2132,7 @@ if __name__ == '__main__':
                        'ignoreerrors': opts.ignoreerrors,
                        'ratelimit': opts.ratelimit,
                        'nooverwrites': opts.nooverwrites,
+                       'retries': opts.retries,
                        'continuedl': opts.continue_dl,
                        'noprogress': opts.noprogress,
                        })