diff --git a/youtube_dl/FileDownloader.py b/youtube_dl/FileDownloader.py
index 96130152d..5087b4cc8 100644
--- a/youtube_dl/FileDownloader.py
+++ b/youtube_dl/FileDownloader.py
@@ -250,6 +250,18 @@ class FileDownloader(object):
warning_message=u'%s %s' % (_msg_header,message)
self.to_stderr(warning_message)
+ def report_error(self, message, tb=None):
+ '''
+ Do the same as trouble, but prefixes the message with 'ERROR:', colored
+ in red if stderr is a tty file.
+ '''
+ if sys.stderr.isatty():
+ _msg_header = u'\033[0;31mERROR:\033[0m'
+ else:
+ _msg_header = u'ERROR:'
+ error_message = u'%s %s' % (_msg_header, message)
+ self.trouble(error_message, tb)
+
def slow_down(self, start_time, byte_counter):
"""Sleep if the download speed is over the rate limit."""
rate_limit = self.params.get('ratelimit', None)
@@ -281,7 +293,7 @@ class FileDownloader(object):
return
os.rename(encodeFilename(old_filename), encodeFilename(new_filename))
except (IOError, OSError) as err:
- self.trouble(u'ERROR: unable to rename file')
+ self.report_error(u'unable to rename file')
def try_utime(self, filename, last_modified_hdr):
"""Try to set the last-modified time of the given file."""
@@ -444,7 +456,7 @@ class FileDownloader(object):
if dn != '' and not os.path.exists(dn): # dn is already encoded
os.makedirs(dn)
except (OSError, IOError) as err:
- self.trouble(u'ERROR: unable to create directory ' + compat_str(err))
+ self.report_error(u'unable to create directory ' + compat_str(err))
return
if self.params.get('writedescription', False):
@@ -454,7 +466,7 @@ class FileDownloader(object):
with io.open(encodeFilename(descfn), 'w', encoding='utf-8') as descfile:
descfile.write(info_dict['description'])
except (OSError, IOError):
- self.trouble(u'ERROR: Cannot write description file ' + descfn)
+ self.report_error(u'Cannot write description file ' + descfn)
return
if self.params.get('writesubtitles', False) and 'subtitles' in info_dict and info_dict['subtitles']:
@@ -469,7 +481,7 @@ class FileDownloader(object):
with io.open(encodeFilename(sub_filename), 'w', encoding='utf-8') as subfile:
subfile.write(sub)
except (OSError, IOError):
- self.trouble(u'ERROR: Cannot write subtitles file ' + descfn)
+ self.report_error(u'Cannot write subtitles file ' + descfn)
return
if self.params.get('onlysubtitles', False):
return
@@ -497,7 +509,7 @@ class FileDownloader(object):
json_info_dict = dict((k, v) for k,v in info_dict.items() if not k in ['urlhandle'])
write_json_file(json_info_dict, encodeFilename(infofn))
except (OSError, IOError):
- self.trouble(u'ERROR: Cannot write metadata to JSON file ' + infofn)
+ self.report_error(u'Cannot write metadata to JSON file ' + infofn)
return
if not self.params.get('skip_download', False):
@@ -509,17 +521,17 @@ class FileDownloader(object):
except (OSError, IOError) as err:
raise UnavailableVideoError()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self.trouble(u'ERROR: unable to download video data: %s' % str(err))
+ self.report_error(u'unable to download video data: %s' % str(err))
return
except (ContentTooShortError, ) as err:
- self.trouble(u'ERROR: content too short (expected %s bytes and served %s)' % (err.expected, err.downloaded))
+ self.report_error(u'content too short (expected %s bytes and served %s)' % (err.expected, err.downloaded))
return
if success:
try:
self.post_process(filename, info_dict)
except (PostProcessingError) as err:
- self.trouble(u'ERROR: postprocessing: %s' % str(err))
+ self.report_error(u'postprocessing: %s' % str(err))
return
def download(self, url_list):
@@ -553,7 +565,7 @@ class FileDownloader(object):
raise
except Exception as e:
if self.params.get('ignoreerrors', False):
- self.trouble(u'ERROR: ' + compat_str(e), tb=compat_str(traceback.format_exc()))
+ self.report_error(u'' + compat_str(e), tb=compat_str(traceback.format_exc()))
break
else:
raise
@@ -567,13 +579,14 @@ class FileDownloader(object):
self.increment_downloads()
self.process_info(video)
except UnavailableVideoError:
- self.trouble(u'\nERROR: unable to download video')
+ self.to_stderr(u"\n")
+ self.report_error(u'unable to download video')
# Suitable InfoExtractor had been found; go to next URL
break
if not suitable_found:
- self.trouble(u'ERROR: no suitable InfoExtractor: %s' % url)
+ self.report_error(u'no suitable InfoExtractor: %s' % url)
return self._download_retcode
@@ -608,7 +621,7 @@ class FileDownloader(object):
try:
subprocess.call(['rtmpdump', '-h'], stdout=(open(os.path.devnull, 'w')), stderr=subprocess.STDOUT)
except (OSError, IOError):
- self.trouble(u'ERROR: RTMP download detected but "rtmpdump" could not be run')
+ self.report_error(u'RTMP download detected but "rtmpdump" could not be run')
return False
# Download using rtmpdump. rtmpdump returns exit code 2 when
@@ -653,7 +666,8 @@ class FileDownloader(object):
})
return True
else:
- self.trouble(u'\nERROR: rtmpdump exited with code %d' % retval)
+ self.to_stderr(u"\n")
+ self.report_error(u'rtmpdump exited with code %d' % retval)
return False
def _do_download(self, filename, info_dict):
@@ -753,7 +767,7 @@ class FileDownloader(object):
self.report_retry(count, retries)
if count > retries:
- self.trouble(u'ERROR: giving up after %s retries' % retries)
+ self.report_error(u'giving up after %s retries' % retries)
return False
data_len = data.info().get('Content-length', None)
@@ -789,12 +803,13 @@ class FileDownloader(object):
filename = self.undo_temp_name(tmpfilename)
self.report_destination(filename)
except (OSError, IOError) as err:
- self.trouble(u'ERROR: unable to open for writing: %s' % str(err))
+ self.report_error(u'unable to open for writing: %s' % str(err))
return False
try:
stream.write(data_block)
except (IOError, OSError) as err:
- self.trouble(u'\nERROR: unable to write data: %s' % str(err))
+ self.to_stderr(u"\n")
+ self.report_error(u'unable to write data: %s' % str(err))
return False
if not self.params.get('noresizebuffer', False):
block_size = self.best_block_size(after - before, len(data_block))
@@ -820,7 +835,8 @@ class FileDownloader(object):
self.slow_down(start, byte_counter - resume_len)
if stream is None:
- self.trouble(u'\nERROR: Did not get any data blocks')
+ self.to_stderr(u"\n")
+ self.report_error(u'Did not get any data blocks')
return False
stream.close()
self.report_finish()
diff --git a/youtube_dl/InfoExtractors.py b/youtube_dl/InfoExtractors.py
index 3f7950cb8..8e164760b 100755
--- a/youtube_dl/InfoExtractors.py
+++ b/youtube_dl/InfoExtractors.py
@@ -411,13 +411,13 @@ class YoutubeIE(InfoExtractor):
self.report_age_confirmation()
age_results = compat_urllib_request.urlopen(request).read().decode('utf-8')
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: unable to confirm age: %s' % compat_str(err))
+ self._downloader.report_error(u'unable to confirm age: %s' % compat_str(err))
return
def _extract_id(self, url):
mobj = re.match(self._VALID_URL, url, re.VERBOSE)
if mobj is None:
- self._downloader.trouble(u'ERROR: invalid URL: %s' % url)
+ self._downloader.report_error(u'invalid URL: %s' % url)
return
video_id = mobj.group(2)
return video_id
@@ -436,7 +436,7 @@ class YoutubeIE(InfoExtractor):
try:
video_webpage_bytes = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % compat_str(err))
+ self._downloader.report_error(u'unable to download video webpage: %s' % compat_str(err))
return
video_webpage = video_webpage_bytes.decode('utf-8', 'ignore')
@@ -461,18 +461,18 @@ class YoutubeIE(InfoExtractor):
if 'token' in video_info:
break
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: unable to download video info webpage: %s' % compat_str(err))
+ self._downloader.report_error(u'unable to download video info webpage: %s' % compat_str(err))
return
if 'token' not in video_info:
if 'reason' in video_info:
- self._downloader.trouble(u'ERROR: YouTube said: %s' % video_info['reason'][0])
+ self._downloader.report_error(u'YouTube said: %s' % video_info['reason'][0])
else:
- self._downloader.trouble(u'ERROR: "token" parameter not in video info for unknown reason')
+ self._downloader.report_error(u'"token" parameter not in video info for unknown reason')
return
# Check for "rental" videos
if 'ypc_video_rental_bar_text' in video_info and 'author' not in video_info:
- self._downloader.trouble(u'ERROR: "rental" videos not supported')
+ self._downloader.report_error(u'"rental" videos not supported')
return
# Start extracting information
@@ -480,7 +480,7 @@ class YoutubeIE(InfoExtractor):
# uploader
if 'author' not in video_info:
- self._downloader.trouble(u'ERROR: unable to extract uploader name')
+ self._downloader.report_error(u'unable to extract uploader name')
return
video_uploader = compat_urllib_parse.unquote_plus(video_info['author'][0])
@@ -490,17 +490,17 @@ class YoutubeIE(InfoExtractor):
if mobj is not None:
video_uploader_id = mobj.group(1)
else:
- self._downloader.trouble(u'WARNING: unable to extract uploader nickname')
+ self._downloader.report_warning(u'unable to extract uploader nickname')
# title
if 'title' not in video_info:
- self._downloader.trouble(u'ERROR: unable to extract video title')
+ self._downloader.report_error(u'unable to extract video title')
return
video_title = compat_urllib_parse.unquote_plus(video_info['title'][0])
# thumbnail image
if 'thumbnail_url' not in video_info:
- self._downloader.trouble(u'WARNING: unable to extract video thumbnail')
+ self._downloader.report_warning(u'unable to extract video thumbnail')
video_thumbnail = ''
else: # don't panic if we can't find it
video_thumbnail = compat_urllib_parse.unquote_plus(video_info['thumbnail_url'][0])
@@ -546,7 +546,7 @@ class YoutubeIE(InfoExtractor):
return
if 'length_seconds' not in video_info:
- self._downloader.trouble(u'WARNING: unable to extract video duration')
+ self._downloader.report_warning(u'unable to extract video duration')
video_duration = ''
else:
video_duration = compat_urllib_parse.unquote_plus(video_info['length_seconds'][0])
@@ -574,7 +574,7 @@ class YoutubeIE(InfoExtractor):
format_list = available_formats
existing_formats = [x for x in format_list if x in url_map]
if len(existing_formats) == 0:
- self._downloader.trouble(u'ERROR: no known formats available for video')
+ self._downloader.report_error(u'no known formats available for video')
return
if self._downloader.params.get('listformats', None):
self._print_formats(existing_formats)
@@ -595,10 +595,10 @@ class YoutubeIE(InfoExtractor):
video_url_list = [(rf, url_map[rf])]
break
if video_url_list is None:
- self._downloader.trouble(u'ERROR: requested format not available')
+ self._downloader.report_error(u'requested format not available')
return
else:
- self._downloader.trouble(u'ERROR: no conn or url_encoded_fmt_stream_map information found in video info')
+ self._downloader.report_error(u'no conn or url_encoded_fmt_stream_map information found in video info')
return
results = []
@@ -661,7 +661,7 @@ class MetacafeIE(InfoExtractor):
self.report_disclaimer()
disclaimer = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: unable to retrieve disclaimer: %s' % compat_str(err))
+ self._downloader.report_error(u'unable to retrieve disclaimer: %s' % compat_str(err))
return
# Confirm age
@@ -674,14 +674,14 @@ class MetacafeIE(InfoExtractor):
self.report_age_confirmation()
disclaimer = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: unable to confirm age: %s' % compat_str(err))
+ self._downloader.report_error(u'unable to confirm age: %s' % compat_str(err))
return
def _real_extract(self, url):
# Extract id and simplified title from URL
mobj = re.match(self._VALID_URL, url)
if mobj is None:
- self._downloader.trouble(u'ERROR: invalid URL: %s' % url)
+ self._downloader.report_error(u'invalid URL: %s' % url)
return
video_id = mobj.group(1)
@@ -698,7 +698,7 @@ class MetacafeIE(InfoExtractor):
self.report_download_webpage(video_id)
webpage = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: unable retrieve video webpage: %s' % compat_str(err))
+ self._downloader.report_error(u'unable retrieve video webpage: %s' % compat_str(err))
return
# Extract URL, uploader and title from webpage
@@ -718,15 +718,15 @@ class MetacafeIE(InfoExtractor):
else:
mobj = re.search(r' name="flashvars" value="(.*?)"', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract media URL')
+ self._downloader.report_error(u'unable to extract media URL')
return
vardict = compat_parse_qs(mobj.group(1))
if 'mediaData' not in vardict:
- self._downloader.trouble(u'ERROR: unable to extract media URL')
+ self._downloader.report_error(u'unable to extract media URL')
return
mobj = re.search(r'"mediaURL":"(http.*?)","key":"(.*?)"', vardict['mediaData'][0])
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract media URL')
+ self._downloader.report_error(u'unable to extract media URL')
return
mediaURL = mobj.group(1).replace('\\/', '/')
video_extension = mediaURL[-3:]
@@ -734,13 +734,13 @@ class MetacafeIE(InfoExtractor):
mobj = re.search(r'(?im)
(.*) - Video', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract title')
+ self._downloader.report_error(u'unable to extract title')
return
video_title = mobj.group(1).decode('utf-8')
mobj = re.search(r'submitter=(.*?);', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract uploader nickname')
+ self._downloader.report_error(u'unable to extract uploader nickname')
return
video_uploader = mobj.group(1)
@@ -772,7 +772,7 @@ class DailymotionIE(InfoExtractor):
# Extract id and simplified title from URL
mobj = re.match(self._VALID_URL, url)
if mobj is None:
- self._downloader.trouble(u'ERROR: invalid URL: %s' % url)
+ self._downloader.report_error(u'invalid URL: %s' % url)
return
video_id = mobj.group(1).split('_')[0].split('?')[0]
@@ -788,7 +788,7 @@ class DailymotionIE(InfoExtractor):
self.report_extraction(video_id)
mobj = re.search(r'\s*var flashvars = (.*)', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract media URL')
+ self._downloader.report_error(u'unable to extract media URL')
return
flashvars = compat_urllib_parse.unquote(mobj.group(1))
@@ -798,12 +798,12 @@ class DailymotionIE(InfoExtractor):
self._downloader.to_screen(u'[dailymotion] Using %s' % key)
break
else:
- self._downloader.trouble(u'ERROR: unable to extract video URL')
+ self._downloader.report_error(u'unable to extract video URL')
return
mobj = re.search(r'"' + max_quality + r'":"(.+?)"', flashvars)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract video URL')
+ self._downloader.report_error(u'unable to extract video URL')
return
video_url = compat_urllib_parse.unquote(mobj.group(1)).replace('\\/', '/')
@@ -812,7 +812,7 @@ class DailymotionIE(InfoExtractor):
mobj = re.search(r'', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract title')
+ self._downloader.report_error(u'unable to extract title')
return
video_title = unescapeHTML(mobj.group('title'))
@@ -822,7 +822,7 @@ class DailymotionIE(InfoExtractor):
# lookin for official user
mobj_official = re.search(r']+?>([^<]+?)', webpage)
if mobj_official is None:
- self._downloader.trouble(u'WARNING: unable to extract uploader nickname')
+ self._downloader.report_warning(u'unable to extract uploader nickname')
else:
video_uploader = mobj_official.group(1)
else:
@@ -864,7 +864,7 @@ class PhotobucketIE(InfoExtractor):
# Extract id from URL
mobj = re.match(self._VALID_URL, url)
if mobj is None:
- self._downloader.trouble(u'ERROR: Invalid URL: %s' % url)
+ self._downloader.report_error(u'Invalid URL: %s' % url)
return
video_id = mobj.group(1)
@@ -877,14 +877,14 @@ class PhotobucketIE(InfoExtractor):
self.report_download_webpage(video_id)
webpage = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: Unable to retrieve video webpage: %s' % compat_str(err))
+ self._downloader.report_error(u'Unable to retrieve video webpage: %s' % compat_str(err))
return
# Extract URL, uploader, and title from webpage
self.report_extraction(video_id)
mobj = re.search(r'', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract media URL')
+ self._downloader.report_error(u'unable to extract media URL')
return
mediaURL = compat_urllib_parse.unquote(mobj.group(1))
@@ -892,7 +892,7 @@ class PhotobucketIE(InfoExtractor):
mobj = re.search(r'(.*) video by (.*) - Photobucket', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract title')
+ self._downloader.report_error(u'unable to extract title')
return
video_title = mobj.group(1).decode('utf-8')
@@ -933,7 +933,7 @@ class YahooIE(InfoExtractor):
# Extract ID from URL
mobj = re.match(self._VALID_URL, url)
if mobj is None:
- self._downloader.trouble(u'ERROR: Invalid URL: %s' % url)
+ self._downloader.report_error(u'Invalid URL: %s' % url)
return
video_id = mobj.group(2)
@@ -946,18 +946,18 @@ class YahooIE(InfoExtractor):
try:
webpage = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: Unable to retrieve video webpage: %s' % compat_str(err))
+ self._downloader.report_error(u'Unable to retrieve video webpage: %s' % compat_str(err))
return
mobj = re.search(r'\("id", "([0-9]+)"\);', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: Unable to extract id field')
+ self._downloader.report_error(u'Unable to extract id field')
return
yahoo_id = mobj.group(1)
mobj = re.search(r'\("vid", "([0-9]+)"\);', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: Unable to extract vid field')
+ self._downloader.report_error(u'Unable to extract vid field')
return
yahoo_vid = mobj.group(1)
@@ -970,34 +970,34 @@ class YahooIE(InfoExtractor):
self.report_download_webpage(video_id)
webpage = compat_urllib_request.urlopen(request).read()
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
- self._downloader.trouble(u'ERROR: Unable to retrieve video webpage: %s' % compat_str(err))
+ self._downloader.report_error(u'Unable to retrieve video webpage: %s' % compat_str(err))
return
# Extract uploader and title from webpage
self.report_extraction(video_id)
mobj = re.search(r'', webpage)
if mobj is None:
- self._downloader.trouble(u'ERROR: unable to extract video title')
+ self._downloader.report_error(u'unable to extract video title')
return
video_title = mobj.group(1).decode('utf-8')
mobj = re.search(r'