diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index a6e4c6177..17aa63487 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -833,11 +833,13 @@ class YoutubeDL(object): except UnicodeEncodeError: self.to_screen('Deleting existing file') - def raise_no_formats(self, has_drm=False, forced=False): + def raise_no_formats(self, info, forced=False): + has_drm = info.get('__has_drm') msg = 'This video is DRM protected' if has_drm else 'No video formats found!' expected = self.params.get('ignore_no_formats_error') if forced or not expected: - raise ExtractorError(msg, expected=has_drm or expected) + raise ExtractorError(msg, video_id=info['id'], ie=info['extractor'], + expected=has_drm or expected) else: self.report_warning(msg) @@ -1191,12 +1193,7 @@ class YoutubeDL(object): self.report_warning('The program functionality for this site has been marked as broken, ' 'and will probably not work.') - try: - temp_id = str_or_none( - ie.extract_id(url) if callable(getattr(ie, 'extract_id', None)) - else ie._match_id(url)) - except (AssertionError, IndexError, AttributeError): - temp_id = None + temp_id = ie.get_temp_id(url) if temp_id is not None and self.in_download_archive({'id': temp_id, 'ie_key': ie_key}): self.to_screen("[%s] %s: has already been recorded in archive" % ( ie_key, temp_id)) @@ -2064,7 +2061,8 @@ class YoutubeDL(object): if 'id' not in info_dict: raise ExtractorError('Missing "id" field in extractor result') if 'title' not in info_dict: - raise ExtractorError('Missing "title" field in extractor result') + raise ExtractorError('Missing "title" field in extractor result', + video_id=info_dict['id'], ie=info_dict['extractor']) def report_force_conversion(field, field_not, conversion): self.report_warning( @@ -2170,7 +2168,7 @@ class YoutubeDL(object): info_dict['__has_drm'] = len(info_dict.get('formats') or ['']) > len(formats) if not formats: - self.raise_no_formats(info_dict.get('__has_drm')) + self.raise_no_formats(info_dict) def is_wellformed(f): url = f.get('url') @@ -2297,7 +2295,8 @@ class YoutubeDL(object): formats_to_download = list(format_selector(ctx)) if not formats_to_download: if not self.params.get('ignore_no_formats_error'): - raise ExtractorError('Requested format is not available', expected=True) + raise ExtractorError('Requested format is not available', expected=True, + video_id=info_dict['id'], ie=info_dict['extractor']) else: self.report_warning('Requested format is not available') # Process what we can, even without any available formats. @@ -2427,7 +2426,7 @@ class YoutubeDL(object): def dl(self, name, info, subtitle=False, test=False): if not info.get('url'): - self.raise_no_formats(info.get('__has_drm'), forced=True) + self.raise_no_formats(info, True) if test: verbose = self.params.get('verbose') diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index 85ac4857e..4e6deee1c 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -467,6 +467,13 @@ class InfoExtractor(object): def _match_id(cls, url): return cls._match_valid_url(url).group('id') + @classmethod + def get_temp_id(cls, url): + try: + return cls._match_id(url) + except (IndexError, AttributeError): + return None + @classmethod def working(cls): """Getter method for _WORKING.""" @@ -588,12 +595,14 @@ class InfoExtractor(object): if self.__maybe_fake_ip_and_retry(e.countries): continue raise - except ExtractorError: - raise + except ExtractorError as e: + video_id = e.video_id or self.get_temp_id(url) + raise ExtractorError( + e.msg, video_id=video_id, ie=self.IE_NAME, tb=e.traceback, expected=e.expected, cause=e.cause) except compat_http_client.IncompleteRead as e: - raise ExtractorError('A network error has occurred.', cause=e, expected=True) + raise ExtractorError('A network error has occurred.', cause=e, expected=True, video_id=self.get_temp_id(url)) except (KeyError, StopIteration) as e: - raise ExtractorError('An extractor error has occurred.', cause=e) + raise ExtractorError('An extractor error has occurred.', cause=e, video_id=self.get_temp_id(url)) def __maybe_fake_ip_and_retry(self, countries): if (not self.get_param('geo_bypass_country', None) diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py index c07a17099..61878b8d7 100644 --- a/yt_dlp/utils.py +++ b/yt_dlp/utils.py @@ -2399,25 +2399,27 @@ network_exceptions = tuple(network_exceptions) class ExtractorError(YoutubeDLError): """Error during info extraction.""" - def __init__(self, msg, tb=None, expected=False, cause=None, video_id=None): + def __init__(self, msg, tb=None, expected=False, cause=None, video_id=None, ie=None): """ tb, if given, is the original traceback (so that it can be printed out). If expected is set, this is a normal error message and most likely not a bug in yt-dlp. """ - if sys.exc_info()[0] in network_exceptions: expected = True - if video_id is not None: - msg = video_id + ': ' + msg - if cause: - msg += ' (caused by %r)' % cause - if not expected: - msg += bug_reports_message() - super(ExtractorError, self).__init__(msg) + self.msg = msg self.traceback = tb - self.exc_info = sys.exc_info() # preserve original exception + self.expected = expected self.cause = cause self.video_id = video_id + self.ie = ie + self.exc_info = sys.exc_info() # preserve original exception + + super(ExtractorError, self).__init__(''.join(( + format_field(ie, template='[%s] '), + format_field(video_id, template='%s: '), + msg, + format_field(cause, template=' (caused by %r)'), + '' if expected else bug_reports_message()))) def format_traceback(self): if self.traceback is None: