Add option --ignore-no-formats-error

* Ignores the "no video format" and similar errors
* Experimental - Some extractors may still throw these errors
This commit is contained in:
pukkandan 2021-04-17 05:39:58 +05:30
parent 6a39ee13f7
commit b7da73eb19
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698
39 changed files with 103 additions and 76 deletions

View File

@ -191,6 +191,9 @@ class YoutubeDL(object):
simulate: Do not download the video files.
format: Video format code. see "FORMAT SELECTION" for more details.
allow_unplayable_formats: Allow unplayable formats to be extracted and downloaded.
ignore_no_formats_error: Ignore "No video formats" error. Usefull for
extracting metadata even if the video is not actually
available for download (experimental)
format_sort: How to sort the video formats. see "Sorting Formats"
for more details.
format_sort_force: Force the given format_sort. see "Sorting Formats"
@ -1884,7 +1887,10 @@ def sanitize_numeric_fields(info):
formats = info_dict['formats']
if not formats:
raise ExtractorError('No video formats found!')
if not self.params.get('ignore_no_formats_error'):
raise ExtractorError('No video formats found!')
else:
self.report_warning('No video formats found!')
def is_wellformed(f):
url = f.get('url')
@ -1948,13 +1954,15 @@ def is_wellformed(f):
# TODO Central sorting goes here
if formats[0] is not info_dict:
if formats and formats[0] is not info_dict:
# only set the 'formats' fields if the original info_dict list them
# otherwise we end up with a circular reference, the first (and unique)
# element in the 'formats' field in info_dict is info_dict itself,
# which can't be exported to json
info_dict['formats'] = formats
if self.params.get('listformats'):
if not info_dict.get('formats'):
raise ExtractorError('No video formats found', expected=True)
self.list_formats(info_dict)
return
@ -1994,19 +2002,25 @@ def is_wellformed(f):
formats_to_download = list(format_selector(ctx))
if not formats_to_download:
raise ExtractorError('requested format not available',
expected=True)
if download:
self.to_screen('[info] Downloading format(s) %s' % ", ".join([f['format_id'] for f in formats_to_download]))
if not self.params.get('ignore_no_formats_error'):
raise ExtractorError('Requested format is not available', expected=True)
else:
self.report_warning('Requested format is not available')
elif download:
self.to_screen(
'[info] %s: Downloading format(s) %s'
% (info_dict['id'], ", ".join([f['format_id'] for f in formats_to_download])))
if len(formats_to_download) > 1:
self.to_screen('[info] %s: downloading video in %s formats' % (info_dict['id'], len(formats_to_download)))
for format in formats_to_download:
self.to_screen(
'[info] %s: Downloading video in %s formats'
% (info_dict['id'], len(formats_to_download)))
for fmt in formats_to_download:
new_info = dict(info_dict)
new_info.update(format)
new_info.update(fmt)
self.process_info(new_info)
# We update the info dict with the best quality format (backwards compatibility)
info_dict.update(formats_to_download[-1])
if formats_to_download:
info_dict.update(formats_to_download[-1])
return info_dict
def process_subtitles(self, video_id, normal_subtitles, automatic_captions):

View File

@ -466,6 +466,7 @@ def report_args_compat(arg, name):
'skip_download': opts.skip_download,
'format': opts.format,
'allow_unplayable_formats': opts.allow_unplayable_formats,
'ignore_no_formats_error': opts.ignore_no_formats_error,
'format_sort': opts.format_sort,
'format_sort_force': opts.format_sort_force,
'allow_multiple_video_streams': opts.allow_multiple_video_streams,

View File

@ -323,7 +323,7 @@ def _real_extract(self, url):
'url': file_url,
'format_id': 'http',
}]
if not formats:
if not formats and not self._downloader.params.get('ignore_no_formats'):
continue
self._sort_formats(formats)
file_info = common_entry.copy()

View File

@ -36,12 +36,12 @@ def _parse_media_info(self, media_info, video_id, fsk):
if not formats:
if fsk:
raise ExtractorError(
self.raise_no_formats(
'This video is only available after 20:00', expected=True)
elif media_info.get('_geoblocked'):
self.raise_geo_restricted(
'This video is not available due to geoblocking',
countries=self._GEO_COUNTRIES)
countries=self._GEO_COUNTRIES, metadata_available=True)
self._sort_formats(formats)

View File

@ -1242,7 +1242,7 @@ def extract_all(pattern):
entries = []
for num, media_meta in enumerate(medias, start=1):
formats, subtitles = self._extract_from_media_meta(media_meta, playlist_id)
if not formats:
if not formats and not self._downloader.params.get('ignore_no_formats'):
continue
self._sort_formats(formats)

View File

@ -545,9 +545,9 @@ def build_format_id(kind):
errors = json_data.get('errors')
if errors:
error = errors[0]
raise ExtractorError(
self.raise_no_formats(
error.get('message') or error.get('error_subcode') or error['error_code'], expected=True)
if (not self._downloader.params.get('allow_unplayable_formats')
elif (not self._downloader.params.get('allow_unplayable_formats')
and sources and num_drm_sources == len(sources)):
raise ExtractorError('This video is DRM protected.', expected=True)

View File

@ -5,7 +5,6 @@
from .common import InfoExtractor
from ..utils import (
clean_html,
ExtractorError,
int_or_none,
parse_iso8601,
qualities,
@ -187,14 +186,13 @@ def quality(quality_id, format_url):
'quality': quality(q, q_url),
})
self._sort_formats(formats)
slides = content_data.get('Slides')
zip_file = content_data.get('ZipFile')
if not formats and not slides and not zip_file:
raise ExtractorError(
self.raise_no_formats(
'None of recording, slides or zip are available for %s' % content_path)
self._sort_formats(formats)
subtitles = {}
for caption in content_data.get('Captions', []):

View File

@ -968,15 +968,27 @@ def report_login(self):
"""Report attempt to log in."""
self.to_screen('Logging in')
@staticmethod
def raise_login_required(msg='This video is only available for registered users'):
def raise_login_required(
self, msg='This video is only available for registered users', metadata_available=False):
if metadata_available and self._downloader.params.get('ignore_no_formats_error'):
self.report_warning(msg)
raise ExtractorError(
'%s. Use --username and --password or --netrc to provide account credentials.' % msg,
'%s. Use --cookies, --username and --password or --netrc to provide account credentials' % msg,
expected=True)
@staticmethod
def raise_geo_restricted(msg='This video is not available from your location due to geo restriction', countries=None):
raise GeoRestrictedError(msg, countries=countries)
def raise_geo_restricted(
self, msg='This video is not available from your location due to geo restriction',
countries=None, metadata_available=False):
if metadata_available and self._downloader.params.get('ignore_no_formats_error'):
self.report_warning(msg)
else:
raise GeoRestrictedError(msg, countries=countries)
def raise_no_formats(self, msg, expected=False, video_id=None):
if expected and self._downloader.params.get('ignore_no_formats_error'):
self.report_warning(msg, video_id)
else:
raise ExtractorError(msg, expected=expected, video_id=video_id)
# Methods for following #608
@staticmethod
@ -1670,6 +1682,8 @@ def calculate_preference(self, format):
def _sort_formats(self, formats, field_preference=[]):
if not formats:
if self._downloader.params.get('ignore_no_formats_error'):
return
raise ExtractorError('No video formats found')
format_sort = self.FormatSort() # params and to_screen are taken from the downloader
format_sort.evaluate_params(self._downloader.params, field_preference)

View File

@ -131,7 +131,7 @@ def _real_extract(self, url):
formats.extend(self._parse_smil_formats(
smil, smil_url, video_id, namespace))
if not formats and video.get('drm'):
raise ExtractorError('This video is DRM protected.', expected=True)
self.raise_no_formats('This video is DRM protected.', expected=True)
self._sort_formats(formats)
subtitles = {}

View File

@ -9,7 +9,6 @@
unified_strdate,
compat_str,
determine_ext,
ExtractorError,
update_url_query,
)
@ -140,7 +139,7 @@ def _real_extract(self, url):
'vcodec': 'none' if (width == 0 and height == 0) else None,
})
if not formats and video_data.get('expired'):
raise ExtractorError(
self.raise_no_formats(
'%s said: %s' % (self.IE_NAME, page_data['translations']['video_expired']),
expected=True)
self._sort_formats(formats)

View File

@ -625,8 +625,6 @@ def parse_attachment(attachment, key='media'):
subtitles_src = f[0].get('subtitles_src')
if subtitles_src:
subtitles.setdefault('en', []).append({'url': subtitles_src})
if not formats:
raise ExtractorError('Cannot find video formats')
process_formats(formats)

View File

@ -253,7 +253,7 @@ def add_source_format(urlh):
or 'unable to extract confirmation code')
if not formats and reason:
raise ExtractorError(reason, expected=True)
self.raise_no_formats(reason, expected=True)
self._sort_formats(formats)

View File

@ -184,7 +184,7 @@ def _real_extract(self, url):
geo_restricted = True
continue
if not formats and geo_restricted:
self.raise_geo_restricted(countries=['IN'])
self.raise_geo_restricted(countries=['IN'], metadata_available=True)
self._sort_formats(formats)
for f in formats:

View File

@ -136,7 +136,7 @@ def extract_formats(format_url, format_key=None, lang=None):
extract_formats(src)
if not formats and '>GEO_IP_NOT_ALLOWED<' in playerpage:
self.raise_geo_restricted(countries=['CZ'])
self.raise_geo_restricted(countries=['CZ'], metadata_available=True)
self._sort_formats(formats)

View File

@ -101,7 +101,7 @@ def extract_format(format_url, height=None):
if not formats:
if 'title="This video is no longer available"' in webpage:
raise ExtractorError(
self.raise_no_formats(
'Video %s is no longer available' % video_id, expected=True)
try:

View File

@ -6,7 +6,6 @@
from .common import InfoExtractor
from ..compat import compat_str
from ..utils import (
ExtractorError,
int_or_none,
js_to_json,
str_or_none,
@ -77,7 +76,7 @@ def _real_extract(self, url):
self._sort_formats(formats)
if not formats[0].get('width'):
if formats and not formats[0].get('width'):
formats[0]['vcodec'] = 'none'
title = self._og_search_title(webpage)
@ -183,7 +182,7 @@ def _real_extract(self, url):
if not formats:
archive_status = item.get('archiveStatus')
if archive_status != 'ARCHIVED':
raise ExtractorError('this video has been ' + archive_status.lower(), expected=True)
self.raise_no_formats('this video has been ' + archive_status.lower(), expected=True)
self._sort_formats(formats)
info['formats'] = formats
return info

View File

@ -97,11 +97,11 @@ def add_item(container, item_url, height, id_key='format_id', item_id=None):
error = clip.get('error')
if not formats and error:
if error == 404:
raise ExtractorError(
self.raise_no_formats(
'That clip does not exist.',
expected=True, video_id=video_id)
else:
raise ExtractorError(
self.raise_no_formats(
'An unknown error occurred ({0}).'.format(error),
video_id=video_id)

View File

@ -157,7 +157,7 @@ def _real_extract(self, url):
})
if not formats and cloudcast.get('isExclusive'):
self.raise_login_required()
self.raise_login_required(metadata_available=True)
self._sort_formats(formats)

View File

@ -247,7 +247,7 @@ def _get_info(self, url, video_id):
if not formats:
if not self._downloader.params.get('allow_unplayable_formats') and drm:
raise ExtractorError('This video is DRM protected.', expected=True)
self.raise_no_formats('This video is DRM protected.', expected=True)
return
self._sort_formats(formats)

View File

@ -260,7 +260,7 @@ def _real_extract(self, url):
if not formats:
payment_info = metadata.get('paymentInfo')
if payment_info:
raise ExtractorError('This video is paid, subscribe to download it', expected=True)
self.raise_no_formats('This video is paid, subscribe to download it', expected=True)
self._sort_formats(formats)

View File

@ -10,7 +10,6 @@
)
from ..utils import (
determine_ext,
ExtractorError,
float_or_none,
int_or_none,
try_get,
@ -85,7 +84,7 @@ def _extract(self, content_tree_url, video_id, domain=None, supportedformats=Non
'fps': float_or_none(stream.get('framerate')),
})
if not formats and not auth_data.get('authorized'):
raise ExtractorError('%s said: %s' % (
self.raise_no_formats('%s said: %s' % (
self.IE_NAME, auth_data['message']), expected=True)
self._sort_formats(formats)

View File

@ -79,7 +79,7 @@ def extract_entry(source):
formats.extend(self._extract_m3u8_formats(
m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native',
m3u8_id='hls', fatal=False))
if not formats:
if not formats and not self._downloader.params.get('ignore_no_formats'):
return
self._sort_formats(formats)
return {

View File

@ -94,7 +94,7 @@ def _extract_relinker_info(self, relinker_url, video_id):
})
if not formats and geoprotection is True:
self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
self.raise_geo_restricted(countries=self._GEO_COUNTRIES, metadata_available=True)
return dict((k, v) for k, v in {
'is_live': is_live,

View File

@ -202,7 +202,7 @@ def pv(name):
if not formats:
if (not self._downloader.params.get('allow_unplayable_formats')
and xpath_text(video_xml, './Clip/DRM', default=None)):
raise ExtractorError('This video is DRM protected.', expected=True)
self.raise_no_formats('This video is DRM protected.', expected=True)
ns_st_cds = pv('ns_st_cds')
if ns_st_cds != 'free':
raise ExtractorError('This video is %s.' % ns_st_cds, expected=True)

View File

@ -498,7 +498,7 @@ def add_format(f, protocol, is_preview=False):
f['vcodec'] = 'none'
if not formats and info.get('policy') == 'BLOCK':
self.raise_geo_restricted()
self.raise_geo_restricted(metadata_available=True)
self._sort_formats(formats)
user = info.get('user') or {}

View File

@ -77,7 +77,7 @@ def entries():
continue
formats = self._extract_m3u8_formats(
video_url.replace('.smil', '.m3u8'), video_id, 'mp4', fatal=False)
if not formats:
if not formats and not self._downloader.params.get('ignore_no_formats'):
continue
yield {
'id': video_id,

View File

@ -139,7 +139,7 @@ def _real_extract(self, url):
'format_id': ext + quality,
'url': video_url,
})
if not formats:
if not formats and not self._downloader.params.get('ignore_no_formats'):
continue
entry['formats'] = formats
entries.append(entry)

View File

@ -49,7 +49,7 @@ def _extract_video(self, video_info, video_id):
if not formats and rights.get('geoBlockedSweden'):
self.raise_geo_restricted(
'This video is only available in Sweden',
countries=self._GEO_COUNTRIES)
countries=self._GEO_COUNTRIES, metadata_available=True)
self._sort_formats(formats)
subtitles = {}

View File

@ -7,7 +7,6 @@
from .common import InfoExtractor
from ..utils import (
determine_ext,
ExtractorError,
float_or_none,
int_or_none,
parse_iso8601,
@ -156,10 +155,9 @@ def _real_extract(self, url):
for meta in (info.get('Metas') or []):
if (not self._downloader.params.get('allow_unplayable_formats')
and meta.get('Key') == 'Encryption' and meta.get('Value') == '1'):
raise ExtractorError(
self.raise_no_formats(
'This video is DRM protected.', expected=True)
# Most likely because geo-blocked
raise ExtractorError('No downloadable videos found', expected=True)
# Most likely because geo-blocked if no formats and no DRM
self._sort_formats(formats)
thumbnails = []

View File

@ -103,7 +103,7 @@ def _real_extract(self, url):
'filesize': int_or_none(item.get('fileSize')),
})
if not formats and data.get('drmProtected'):
raise ExtractorError('This video is DRM protected.', expected=True)
self.raise_no_formats('This video is DRM protected.', expected=True)
self._sort_formats(formats)
thumbnails = [{

View File

@ -107,7 +107,7 @@ def _real_extract(self, url):
video_id, ism_id='mss', fatal=False))
if not formats and info.get('is_geo_restricted'):
self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
self.raise_geo_restricted(countries=self._GEO_COUNTRIES, metadata_available=True)
self._sort_formats(formats)

View File

@ -298,7 +298,8 @@ def _real_extract(self, url):
if not formats and video.get('is_geo_blocked'):
self.raise_geo_restricted(
'This content might not be available in your country due to copyright reasons')
'This content might not be available in your country due to copyright reasons',
metadata_available=True)
self._sort_formats(formats)

View File

@ -10,7 +10,6 @@
compat_urllib_parse_urlparse,
)
from ..utils import (
ExtractorError,
int_or_none,
)
@ -193,8 +192,8 @@ def _real_extract(self, url):
error = item.get('error')
if error:
if error in ('Данное видео недоступно для просмотра на территории этой страны', 'Данное видео доступно для просмотра только на территории России'):
self.raise_geo_restricted(countries=['RU'])
raise ExtractorError(error, expected=True)
self.raise_geo_restricted(countries=['RU'], metadata_available=True)
self.raise_no_formats(error, expected=True)
self._sort_formats(formats)
return {

View File

@ -8,7 +8,6 @@
)
from ..utils import (
int_or_none,
ExtractorError,
)
@ -125,13 +124,13 @@ def _real_extract(self, url):
})
formats.append(fmt)
self._sort_formats(formats)
if not formats and video.get('vst') == 'dmca':
raise ExtractorError(
self.raise_no_formats(
'This video has been removed in response to a complaint received under the US Digital Millennium Copyright Act.',
expected=True)
self._sort_formats(formats)
title = video['title']
description = video.get('description')
thumbnail = self._proto_relative_url(video.get('thumbnail_src'), scheme='http:')

View File

@ -87,7 +87,7 @@ def extract_formats(manifest_urls):
extract_formats({delivery.get('format'): delivery.get('url')})
if not formats:
if delivery.get('drm'):
raise ExtractorError('This video is DRM protected.', expected=True)
self.raise_no_formats('This video is DRM protected.', expected=True)
manifest_urls = self._download_json(
'http://www.wat.tv/get/webhtml/' + video_id, video_id, fatal=False)
if manifest_urls:

View File

@ -239,7 +239,7 @@ def _extract_yahoo_video(self, video_id, country):
'm3u8_native', m3u8_id='hls', fatal=False))
if not formats and msg == 'geo restricted':
self.raise_geo_restricted()
self.raise_geo_restricted(metadata_available=True)
self._sort_formats(formats)

View File

@ -2050,7 +2050,7 @@ def feed_entry(name):
if not formats:
if not self._downloader.params.get('allow_unplayable_formats') and streaming_data.get('licenseInfos'):
raise ExtractorError(
self.raise_no_formats(
'This video is DRM protected.', expected=True)
pemr = try_get(
playability_status,
@ -2065,11 +2065,10 @@ def feed_entry(name):
if not countries:
regions_allowed = search_meta('regionsAllowed')
countries = regions_allowed.split(',') if regions_allowed else None
self.raise_geo_restricted(
subreason, countries)
self.raise_geo_restricted(subreason, countries, metadata_available=True)
reason += '\n' + subreason
if reason:
raise ExtractorError(reason, expected=True)
self.raise_no_formats(reason, expected=True)
self._sort_formats(formats)

View File

@ -3,7 +3,6 @@
from .common import InfoExtractor
from ..utils import (
ExtractorError,
int_or_none,
)
@ -48,8 +47,8 @@ def _extract_item(self, item, fatal):
return
msg = item['msg']
if msg == 'Sorry, this content is not available in your country.':
self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
raise ExtractorError(msg, expected=True)
self.raise_geo_restricted(countries=self._GEO_COUNTRIES, metadata_available=True)
self.raise_no_formats(msg, expected=True)
self._sort_formats(formats)
subtitles = None

View File

@ -749,6 +749,16 @@ def _dict_from_multiple_values_options_callback(
'-s', '--simulate',
action='store_true', dest='simulate', default=False,
help='Do not download the video and do not write anything to disk')
verbosity.add_option(
'--ignore-no-formats-error',
action='store_true', dest='ignore_no_formats_error', default=False,
help=(
'Ignore "No video formats" error. Usefull for extracting metadata '
'even if the video is not actually available for download (experimental)'))
verbosity.add_option(
'--no-ignore-no-formats-error',
action='store_false', dest='ignore_no_formats_error',
help='Throw error when no downloadable video formats are found (default)')
verbosity.add_option(
'--skip-download', '--no-download',
action='store_true', dest='skip_download', default=False,