X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=youtube-dl;h=6730898ac757dc4d267944459dcb014d080a292a;hb=ff21a710aeadd3d6192f5d94834b990f3c1b7b2a;hp=7532a142f34387b3d0a8f5620e24cc3cbee9c222;hpb=968aa884385ba78dc113a64b3dbbb1c5c6541cbd;p=youtube-dl.git diff --git a/youtube-dl b/youtube-dl index 7532a142f..6730898ac 100755 --- a/youtube-dl +++ b/youtube-dl @@ -114,6 +114,7 @@ class FileDownloader(object): ignoreerrors: Do not stop on download errors. ratelimit: Download speed limit, in bytes/sec. nooverwrites: Prevent overwriting files. + continuedl: Try to continue downloads if possible. """ params = None @@ -182,13 +183,13 @@ class FileDownloader(object): new_min = max(bytes / 2.0, 1.0) new_max = min(max(bytes * 2.0, 1.0), 4194304) # Do not surpass 4 MB if elapsed_time < 0.001: - return int(new_max) + return long(new_max) rate = bytes / elapsed_time if rate > new_max: - return int(new_max) + return long(new_max) if rate < new_min: - return int(new_min) - return int(rate) + return long(new_min) + return long(rate) @staticmethod def parse_bytes(bytestr): @@ -266,6 +267,18 @@ class FileDownloader(object): """Report download progress.""" self.to_stdout(u'\r[download] %s of %s at %s ETA %s' % (percent_str, data_len_str, speed_str, eta_str), skip_eol=True) + + def report_resuming_byte(self, resume_len): + """Report attemtp to resume at given byte.""" + self.to_stdout(u'[download] Resuming download at byte %s' % resume_len) + + def report_file_already_downloaded(self, file_name): + """Report file has already been fully downloaded.""" + self.to_stdout(u'[download] %s has already been downloaded' % file_name) + + def report_unable_to_resume(self): + """Report it was impossible to resume download.""" + self.to_stdout(u'[download] Unable to resume') def report_finish(self): """Report download finished.""" @@ -306,7 +319,7 @@ class FileDownloader(object): return try: - outstream = open(filename, 'wb') + outstream = open(filename, 'ab') except (OSError, IOError), err: self.trouble('ERROR: unable to open for writing: %s' % str(err)) return @@ -367,8 +380,32 @@ class FileDownloader(object): break def _do_download(self, stream, url): + basic_request = urllib2.Request(url, None, std_headers) request = urllib2.Request(url, None, std_headers) - data = urllib2.urlopen(request) + + # Resume transfer if filesize is non-zero + resume_len = stream.tell() + if self.params['continuedl'] and resume_len != 0: + self.report_resuming_byte(resume_len) + request.add_header('Range','bytes=%d-' % resume_len) + else: + stream.close() + stream = open(stream.name,'wb') + try: + data = urllib2.urlopen(request) + except urllib2.HTTPError, e: + if not e.code == 416: # 416 is 'Requested range not satisfiable' + raise + data = urllib2.urlopen(basic_request) + content_length = data.info()['Content-Length'] + if content_length is not None and long(content_length) == resume_len: + self.report_file_already_downloaded(stream.name) + return + else: + self.report_unable_to_resume() + stream.close() + stream = open(stream.name,'wb') + data_len = data.info().get('Content-length', None) data_len_str = self.format_bytes(data_len) byte_counter = 0 @@ -859,7 +896,7 @@ class YoutubeSearchIE(InfoExtractor): return else: try: - n = int(prefix) + n = long(prefix) if n <= 0: self._downloader.trouble(u'ERROR: invalid download number %s for query "%s"' % (n, query)) return @@ -868,7 +905,7 @@ class YoutubeSearchIE(InfoExtractor): n = self._max_youtube_results self._download_n_results(query, n) return - except ValueError: # parsing prefix as int fails + except ValueError: # parsing prefix as integer fails self._download_n_results(query, 1) return @@ -1053,7 +1090,7 @@ if __name__ == '__main__': video_format = optparse.OptionGroup(parser, 'Video Format Options') video_format.add_option('-f', '--format', - action='append', dest='format', metavar='FMT', help='video format code') + action='store', dest='format', metavar='FMT', 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', @@ -1084,6 +1121,8 @@ if __name__ == '__main__': dest='batchfile', metavar='F', help='file containing URLs to download') 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) parser.add_option_group(filesystem) (opts, args) = parser.parse_args() @@ -1117,13 +1156,6 @@ if __name__ == '__main__': if numeric_limit is None: parser.error(u'invalid rate limit specified') opts.ratelimit = numeric_limit - if opts.format is not None and len(opts.format) > 1: - parser.error(u'pass at most one of the video format option flags (-f, -b, -m, -d)') - if opts.format is None: - real_format = None - else: - real_format = opts.format[0] - # Information extractors youtube_ie = YoutubeIE() @@ -1140,7 +1172,7 @@ if __name__ == '__main__': 'forceurl': opts.geturl, 'forcetitle': opts.gettitle, 'simulate': (opts.simulate or opts.geturl or opts.gettitle), - 'format': real_format, + 'format': opts.format, 'outtmpl': ((opts.outtmpl is not None and opts.outtmpl.decode(locale.getpreferredencoding())) or (opts.usetitle and u'%(stitle)s-%(id)s.%(ext)s') or (opts.useliteral and u'%(title)s-%(id)s.%(ext)s') @@ -1148,6 +1180,7 @@ if __name__ == '__main__': 'ignoreerrors': opts.ignoreerrors, 'ratelimit': opts.ratelimit, 'nooverwrites': opts.nooverwrites, + 'continuedl': opts.continue_dl, }) fd.add_info_extractor(youtube_search_ie) fd.add_info_extractor(youtube_pl_ie)