aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpukkandan <pukkandan.ytdlp@gmail.com>2021-04-17 05:39:58 +0530
committerpukkandan <pukkandan.ytdlp@gmail.com>2021-04-17 08:40:30 +0530
commitb7da73eb19e00e4eab43ec7de129e9aa12f6d5d3 (patch)
treea87c490ae5d4de7e95c7b7a6cb9e5184d4827fd8
parent6a39ee13f7613767905a4669d1d0247aafc5a12c (diff)
downloadhypervideo-pre-b7da73eb19e00e4eab43ec7de129e9aa12f6d5d3.tar.lz
hypervideo-pre-b7da73eb19e00e4eab43ec7de129e9aa12f6d5d3.tar.xz
hypervideo-pre-b7da73eb19e00e4eab43ec7de129e9aa12f6d5d3.zip
Add option `--ignore-no-formats-error`
* Ignores the "no video format" and similar errors * Experimental - Some extractors may still throw these errors
-rw-r--r--yt_dlp/YoutubeDL.py36
-rw-r--r--yt_dlp/__init__.py1
-rw-r--r--yt_dlp/extractor/afreecatv.py2
-rw-r--r--yt_dlp/extractor/ard.py4
-rw-r--r--yt_dlp/extractor/bbc.py2
-rw-r--r--yt_dlp/extractor/brightcove.py4
-rw-r--r--yt_dlp/extractor/channel9.py6
-rw-r--r--yt_dlp/extractor/common.py26
-rw-r--r--yt_dlp/extractor/corus.py2
-rw-r--r--yt_dlp/extractor/disney.py3
-rw-r--r--yt_dlp/extractor/facebook.py2
-rw-r--r--yt_dlp/extractor/googledrive.py2
-rw-r--r--yt_dlp/extractor/hotstar.py2
-rw-r--r--yt_dlp/extractor/iprima.py2
-rw-r--r--yt_dlp/extractor/keezmovies.py2
-rw-r--r--yt_dlp/extractor/line.py5
-rw-r--r--yt_dlp/extractor/medaltv.py4
-rw-r--r--yt_dlp/extractor/mixcloud.py2
-rw-r--r--yt_dlp/extractor/npo.py2
-rw-r--r--yt_dlp/extractor/odnoklassniki.py2
-rw-r--r--yt_dlp/extractor/ooyala.py3
-rw-r--r--yt_dlp/extractor/philharmoniedeparis.py2
-rw-r--r--yt_dlp/extractor/rai.py2
-rw-r--r--yt_dlp/extractor/ruutu.py2
-rw-r--r--yt_dlp/extractor/soundcloud.py2
-rw-r--r--yt_dlp/extractor/sportdeutschland.py2
-rw-r--r--yt_dlp/extractor/steam.py2
-rw-r--r--yt_dlp/extractor/svt.py2
-rw-r--r--yt_dlp/extractor/toggle.py6
-rw-r--r--yt_dlp/extractor/tv2.py2
-rw-r--r--yt_dlp/extractor/tv4.py2
-rw-r--r--yt_dlp/extractor/tvplay.py3
-rw-r--r--yt_dlp/extractor/videomore.py5
-rw-r--r--yt_dlp/extractor/vube.py7
-rw-r--r--yt_dlp/extractor/wat.py2
-rw-r--r--yt_dlp/extractor/yahoo.py2
-rw-r--r--yt_dlp/extractor/youtube.py7
-rw-r--r--yt_dlp/extractor/zingmp3.py5
-rw-r--r--yt_dlp/options.py10
39 files changed, 103 insertions, 76 deletions
diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py
index d7cbdd047..7cda3fc8f 100644
--- a/yt_dlp/YoutubeDL.py
+++ b/yt_dlp/YoutubeDL.py
@@ -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 @@ class YoutubeDL(object):
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 @@ class YoutubeDL(object):
# 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 @@ class YoutubeDL(object):
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):
diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py
index 90a3116ea..4f0684236 100644
--- a/yt_dlp/__init__.py
+++ b/yt_dlp/__init__.py
@@ -466,6 +466,7 @@ def _real_main(argv=None):
'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,
diff --git a/yt_dlp/extractor/afreecatv.py b/yt_dlp/extractor/afreecatv.py
index af0587ae6..016a4d24a 100644
--- a/yt_dlp/extractor/afreecatv.py
+++ b/yt_dlp/extractor/afreecatv.py
@@ -323,7 +323,7 @@ class AfreecaTVIE(InfoExtractor):
'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()
diff --git a/yt_dlp/extractor/ard.py b/yt_dlp/extractor/ard.py
index 294da7c51..4d90be714 100644
--- a/yt_dlp/extractor/ard.py
+++ b/yt_dlp/extractor/ard.py
@@ -36,12 +36,12 @@ class ARDMediathekBaseIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/bbc.py b/yt_dlp/extractor/bbc.py
index e8d000bbb..333796c80 100644
--- a/yt_dlp/extractor/bbc.py
+++ b/yt_dlp/extractor/bbc.py
@@ -1242,7 +1242,7 @@ class BBCIE(BBCCoUkIE):
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)
diff --git a/yt_dlp/extractor/brightcove.py b/yt_dlp/extractor/brightcove.py
index 8b29ca993..d2fd10064 100644
--- a/yt_dlp/extractor/brightcove.py
+++ b/yt_dlp/extractor/brightcove.py
@@ -545,9 +545,9 @@ class BrightcoveNewIE(AdobePassIE):
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)
diff --git a/yt_dlp/extractor/channel9.py b/yt_dlp/extractor/channel9.py
index 09cacf6d3..258e96ca6 100644
--- a/yt_dlp/extractor/channel9.py
+++ b/yt_dlp/extractor/channel9.py
@@ -5,7 +5,6 @@ import re
from .common import InfoExtractor
from ..utils import (
clean_html,
- ExtractorError,
int_or_none,
parse_iso8601,
qualities,
@@ -187,14 +186,13 @@ class Channel9IE(InfoExtractor):
'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', []):
diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py
index 40ea9339f..9ead6db2d 100644
--- a/yt_dlp/extractor/common.py
+++ b/yt_dlp/extractor/common.py
@@ -968,15 +968,27 @@ class InfoExtractor(object):
"""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 @@ class InfoExtractor(object):
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)
diff --git a/yt_dlp/extractor/corus.py b/yt_dlp/extractor/corus.py
index e11aadf14..de61f42e4 100644
--- a/yt_dlp/extractor/corus.py
+++ b/yt_dlp/extractor/corus.py
@@ -131,7 +131,7 @@ class CorusIE(ThePlatformFeedIE):
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 = {}
diff --git a/yt_dlp/extractor/disney.py b/yt_dlp/extractor/disney.py
index 0eee82fd6..e1ae62ac6 100644
--- a/yt_dlp/extractor/disney.py
+++ b/yt_dlp/extractor/disney.py
@@ -9,7 +9,6 @@ from ..utils import (
unified_strdate,
compat_str,
determine_ext,
- ExtractorError,
update_url_query,
)
@@ -140,7 +139,7 @@ class DisneyIE(InfoExtractor):
'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)
diff --git a/yt_dlp/extractor/facebook.py b/yt_dlp/extractor/facebook.py
index 7a76dbb22..b68b90bd3 100644
--- a/yt_dlp/extractor/facebook.py
+++ b/yt_dlp/extractor/facebook.py
@@ -625,8 +625,6 @@ class FacebookIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/googledrive.py b/yt_dlp/extractor/googledrive.py
index 4eefcb70c..7b5bf280f 100644
--- a/yt_dlp/extractor/googledrive.py
+++ b/yt_dlp/extractor/googledrive.py
@@ -253,7 +253,7 @@ class GoogleDriveIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/hotstar.py b/yt_dlp/extractor/hotstar.py
index e2e923539..22cccf2b2 100644
--- a/yt_dlp/extractor/hotstar.py
+++ b/yt_dlp/extractor/hotstar.py
@@ -184,7 +184,7 @@ class HotStarIE(HotStarBaseIE):
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:
diff --git a/yt_dlp/extractor/iprima.py b/yt_dlp/extractor/iprima.py
index 648ae6741..28e660972 100644
--- a/yt_dlp/extractor/iprima.py
+++ b/yt_dlp/extractor/iprima.py
@@ -136,7 +136,7 @@ class IPrimaIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/keezmovies.py b/yt_dlp/extractor/keezmovies.py
index c3eb74c17..cfdd0eb8e 100644
--- a/yt_dlp/extractor/keezmovies.py
+++ b/yt_dlp/extractor/keezmovies.py
@@ -101,7 +101,7 @@ class KeezMoviesIE(InfoExtractor):
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:
diff --git a/yt_dlp/extractor/line.py b/yt_dlp/extractor/line.py
index 2526daa77..41ac8d422 100644
--- a/yt_dlp/extractor/line.py
+++ b/yt_dlp/extractor/line.py
@@ -6,7 +6,6 @@ import re
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 @@ class LineTVIE(InfoExtractor):
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 @@ class LineLiveIE(LineLiveBaseIE):
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
diff --git a/yt_dlp/extractor/medaltv.py b/yt_dlp/extractor/medaltv.py
index 1603b55f6..4bca6f053 100644
--- a/yt_dlp/extractor/medaltv.py
+++ b/yt_dlp/extractor/medaltv.py
@@ -97,11 +97,11 @@ class MedalTVIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/mixcloud.py b/yt_dlp/extractor/mixcloud.py
index 69319857d..b8ccd0ab4 100644
--- a/yt_dlp/extractor/mixcloud.py
+++ b/yt_dlp/extractor/mixcloud.py
@@ -157,7 +157,7 @@ class MixcloudIE(MixcloudBaseIE):
})
if not formats and cloudcast.get('isExclusive'):
- self.raise_login_required()
+ self.raise_login_required(metadata_available=True)
self._sort_formats(formats)
diff --git a/yt_dlp/extractor/npo.py b/yt_dlp/extractor/npo.py
index ca6dbfc81..573a89092 100644
--- a/yt_dlp/extractor/npo.py
+++ b/yt_dlp/extractor/npo.py
@@ -247,7 +247,7 @@ class NPOIE(NPOBaseIE):
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)
diff --git a/yt_dlp/extractor/odnoklassniki.py b/yt_dlp/extractor/odnoklassniki.py
index 7ed9fac55..0ce2e3776 100644
--- a/yt_dlp/extractor/odnoklassniki.py
+++ b/yt_dlp/extractor/odnoklassniki.py
@@ -260,7 +260,7 @@ class OdnoklassnikiIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/ooyala.py b/yt_dlp/extractor/ooyala.py
index eb957b8fe..7204dfecd 100644
--- a/yt_dlp/extractor/ooyala.py
+++ b/yt_dlp/extractor/ooyala.py
@@ -10,7 +10,6 @@ from ..compat import (
)
from ..utils import (
determine_ext,
- ExtractorError,
float_or_none,
int_or_none,
try_get,
@@ -85,7 +84,7 @@ class OoyalaBaseIE(InfoExtractor):
'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)
diff --git a/yt_dlp/extractor/philharmoniedeparis.py b/yt_dlp/extractor/philharmoniedeparis.py
index 03da64b11..9545adebf 100644
--- a/yt_dlp/extractor/philharmoniedeparis.py
+++ b/yt_dlp/extractor/philharmoniedeparis.py
@@ -79,7 +79,7 @@ class PhilharmonieDeParisIE(InfoExtractor):
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 {
diff --git a/yt_dlp/extractor/rai.py b/yt_dlp/extractor/rai.py
index 6c2191bb3..05cf84ba5 100644
--- a/yt_dlp/extractor/rai.py
+++ b/yt_dlp/extractor/rai.py
@@ -94,7 +94,7 @@ class RaiBaseIE(InfoExtractor):
})
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,
diff --git a/yt_dlp/extractor/ruutu.py b/yt_dlp/extractor/ruutu.py
index f9f30e3dd..5030c01cd 100644
--- a/yt_dlp/extractor/ruutu.py
+++ b/yt_dlp/extractor/ruutu.py
@@ -202,7 +202,7 @@ class RuutuIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/soundcloud.py b/yt_dlp/extractor/soundcloud.py
index 103b23bf7..35d34af02 100644
--- a/yt_dlp/extractor/soundcloud.py
+++ b/yt_dlp/extractor/soundcloud.py
@@ -498,7 +498,7 @@ class SoundcloudIE(InfoExtractor):
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 {}
diff --git a/yt_dlp/extractor/sportdeutschland.py b/yt_dlp/extractor/sportdeutschland.py
index 3e497a939..e70d1a477 100644
--- a/yt_dlp/extractor/sportdeutschland.py
+++ b/yt_dlp/extractor/sportdeutschland.py
@@ -77,7 +77,7 @@ class SportDeutschlandIE(InfoExtractor):
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,
diff --git a/yt_dlp/extractor/steam.py b/yt_dlp/extractor/steam.py
index a6a191ceb..c70bdefe2 100644
--- a/yt_dlp/extractor/steam.py
+++ b/yt_dlp/extractor/steam.py
@@ -139,7 +139,7 @@ class SteamIE(InfoExtractor):
'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)
diff --git a/yt_dlp/extractor/svt.py b/yt_dlp/extractor/svt.py
index aba9bb447..5b377ea83 100644
--- a/yt_dlp/extractor/svt.py
+++ b/yt_dlp/extractor/svt.py
@@ -49,7 +49,7 @@ class SVTBaseIE(InfoExtractor):
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 = {}
diff --git a/yt_dlp/extractor/toggle.py b/yt_dlp/extractor/toggle.py
index 1e2a2d819..fe1841081 100644
--- a/yt_dlp/extractor/toggle.py
+++ b/yt_dlp/extractor/toggle.py
@@ -7,7 +7,6 @@ import re
from .common import InfoExtractor
from ..utils import (
determine_ext,
- ExtractorError,
float_or_none,
int_or_none,
parse_iso8601,
@@ -156,10 +155,9 @@ class ToggleIE(InfoExtractor):
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 = []
diff --git a/yt_dlp/extractor/tv2.py b/yt_dlp/extractor/tv2.py
index 334b7d540..f3480de56 100644
--- a/yt_dlp/extractor/tv2.py
+++ b/yt_dlp/extractor/tv2.py
@@ -103,7 +103,7 @@ class TV2IE(InfoExtractor):
'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 = [{
diff --git a/yt_dlp/extractor/tv4.py b/yt_dlp/extractor/tv4.py
index b73bab9a8..b8ad4fafc 100644
--- a/yt_dlp/extractor/tv4.py
+++ b/yt_dlp/extractor/tv4.py
@@ -107,7 +107,7 @@ class TV4IE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/tvplay.py b/yt_dlp/extractor/tvplay.py
index 0d858c025..739c61cdd 100644
--- a/yt_dlp/extractor/tvplay.py
+++ b/yt_dlp/extractor/tvplay.py
@@ -298,7 +298,8 @@ class TVPlayIE(InfoExtractor):
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)
diff --git a/yt_dlp/extractor/videomore.py b/yt_dlp/extractor/videomore.py
index e0c10aa5b..05ae74e33 100644
--- a/yt_dlp/extractor/videomore.py
+++ b/yt_dlp/extractor/videomore.py
@@ -10,7 +10,6 @@ from ..compat import (
compat_urllib_parse_urlparse,
)
from ..utils import (
- ExtractorError,
int_or_none,
)
@@ -193,8 +192,8 @@ class VideomoreIE(InfoExtractor):
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 {
diff --git a/yt_dlp/extractor/vube.py b/yt_dlp/extractor/vube.py
index 8ce3a6b81..c92b47e63 100644
--- a/yt_dlp/extractor/vube.py
+++ b/yt_dlp/extractor/vube.py
@@ -8,7 +8,6 @@ from ..compat import (
)
from ..utils import (
int_or_none,
- ExtractorError,
)
@@ -125,13 +124,13 @@ class VubeIE(InfoExtractor):
})
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:')
diff --git a/yt_dlp/extractor/wat.py b/yt_dlp/extractor/wat.py
index f1bccc2d6..05dcc1f17 100644
--- a/yt_dlp/extractor/wat.py
+++ b/yt_dlp/extractor/wat.py
@@ -87,7 +87,7 @@ class WatIE(InfoExtractor):
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:
diff --git a/yt_dlp/extractor/yahoo.py b/yt_dlp/extractor/yahoo.py
index a17b10d6e..ecf2f5f48 100644
--- a/yt_dlp/extractor/yahoo.py
+++ b/yt_dlp/extractor/yahoo.py
@@ -239,7 +239,7 @@ class YahooIE(InfoExtractor):
'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)
diff --git a/yt_dlp/extractor/youtube.py b/yt_dlp/extractor/youtube.py
index 6d5ef0193..6c1a5b881 100644
--- a/yt_dlp/extractor/youtube.py
+++ b/yt_dlp/extractor/youtube.py
@@ -2050,7 +2050,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
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 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
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)
diff --git a/yt_dlp/extractor/zingmp3.py b/yt_dlp/extractor/zingmp3.py
index 207c04f5e..a3edc158f 100644
--- a/yt_dlp/extractor/zingmp3.py
+++ b/yt_dlp/extractor/zingmp3.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import (
- ExtractorError,
int_or_none,
)
@@ -48,8 +47,8 @@ class ZingMp3BaseIE(InfoExtractor):
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
diff --git a/yt_dlp/options.py b/yt_dlp/options.py
index cced9fb89..fef1e4b15 100644
--- a/yt_dlp/options.py
+++ b/yt_dlp/options.py
@@ -750,6 +750,16 @@ def parseOpts(overrideArguments=None):
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,
help='Do not download the video but write all related files (Alias: --no-download)')