diff --git a/README.md b/README.md index abd8a5ef1..f222eb463 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ which means you can modify it, redistribute it or use it however you like. -U, --update update this program to latest version -i, --ignore-errors continue on download errors -r, --rate-limit LIMIT download rate limit (e.g. 50k or 44.6m) - -R, --retries RETRIES number of retries (default is 10) + -R, --retries RETRIES number of retries (default is 10). Specify 0 or inf + for infinite retries --dump-user-agent display the current browser identification --user-agent UA specify a custom user agent --list-extractors List all supported extractors and the URLs they diff --git a/youtube_dl/FileDownloader.py b/youtube_dl/FileDownloader.py index 08bd83354..392f580a4 100644 --- a/youtube_dl/FileDownloader.py +++ b/youtube_dl/FileDownloader.py @@ -292,7 +292,7 @@ class FileDownloader(object): def report_retry(self, count, retries): """Report retry in case of HTTP error 5xx""" - self.to_screen(u'[download] Got server HTTP error. Retrying (attempt %d of %d)...' % (count, retries)) + self.to_screen(u'[download] Got server HTTP error. Retrying (attempt %s of %s)...' % (count, retries)) def report_file_already_downloaded(self, file_name): """Report file has already been fully downloaded.""" @@ -584,8 +584,8 @@ class FileDownloader(object): resume_len = 0 count = 0 - retries = self.params.get('retries', 0) - while count <= retries: + retries = self.params['retries'] + while retries == 0 or count < retries: # Establish connection try: if count == 0 and 'urlhandle' in info_dict: @@ -626,10 +626,9 @@ class FileDownloader(object): break # Retry count += 1 - if count <= retries: - self.report_retry(count, retries) + self.report_retry(count, retries if retries else "infinite") - if count > retries: + if retries != 0 and count > retries: self.trouble(u'ERROR: giving up after %s retries' % retries) return False diff --git a/youtube_dl/InfoExtractors.py b/youtube_dl/InfoExtractors.py index d2d8d7b77..7bd03ab95 100644 --- a/youtube_dl/InfoExtractors.py +++ b/youtube_dl/InfoExtractors.py @@ -93,6 +93,66 @@ class InfoExtractor(object): """Real extraction process. Redefine in subclasses.""" pass + def _login(self): + if self._downloader is None: + return False + + username = None + password = None + downloader_params = self._downloader.params + + # Attempt to use provided username and password or .netrc data + if downloader_params.get('username', None) and \ + downloader_params.get('password', None): + username = downloader_params['username'] + password = downloader_params['password'] + elif downloader_params.get('usenetrc', False): + try: + info = netrc.netrc().authenticators(self._NETRC_MACHINE) + if info is not None: + username = info[0] + password = info[2] + else: + raise netrc.NetrcParseError('No authenticators for %s' % self._NETRC_MACHINE) + except (IOError, netrc.NetrcParseError), err: + self._downloader.to_stderr(u'WARNING: parsing .netrc: %s' % str(err)) + return False + + # Set language + if hasattr(self, "_LANG_URL"): + request = urllib2.Request(self._LANG_URL) + try: + self.report_lang() + urllib2.urlopen(request).read() + except (urllib2.URLError, httplib.HTTPException, socket.error), err: + self._downloader.to_stderr(u'WARNING: unable to set language: %s' % str(err)) + return False + + # No authentication to be performed + if username is None: + return False + + login_form = self._LOGIN_FORM + # Set login credentials + for k in login_form: + if login_form[k] == "username": + login_form[k] = username + elif login_form[k] == "password": + login_form[k] = password + + request = urllib2.Request(self._LOGIN_URL, urllib.urlencode(login_form)) + try: + self.report_login() + login_results = urllib2.urlopen(request).read() + if re.search(self._FAILED_LOGIN, login_results) is not None: + self._downloader.to_stderr(u'WARNING: unable to log in: bad username or password') + return + except (urllib2.URLError, httplib.HTTPException, socket.error), err: + self._downloader.to_stderr(u'WARNING: unable to log in: %s' % str(err)) + return False + + return request + class YoutubeIE(InfoExtractor): """Information extractor for youtube.com.""" @@ -119,9 +179,17 @@ class YoutubeIE(InfoExtractor): $""" _LANG_URL = r'http://www.youtube.com/?hl=en&persist_hl=1&gl=US&persist_gl=1&opt_out_ackd=1' _LOGIN_URL = 'https://www.youtube.com/signup?next=/&gl=US&hl=en' + _FAILED_LOGIN = r'(?i)