[extractor] Better error message for DRM (#729)

Closes #636
This commit is contained in:
pukkandan 2021-08-23 01:38:38 +05:30 committed by GitHub
parent 9b5fa9ee7c
commit 88acdbc269
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 66 additions and 62 deletions

View file

@ -668,11 +668,6 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
bestvideo+bestaudio), output to given bestvideo+bestaudio), output to given
container format. One of mkv, mp4, ogg, container format. One of mkv, mp4, ogg,
webm, flv. Ignored if no merge is required webm, flv. Ignored if no merge is required
--allow-unplayable-formats Allow unplayable formats to be listed and
downloaded. All video post-processing will
also be turned off
--no-allow-unplayable-formats Do not allow unplayable formats to be
listed or downloaded (default)
## Subtitle Options: ## Subtitle Options:
--write-subs Write subtitle file --write-subs Write subtitle file
@ -1470,6 +1465,8 @@ These options are not intended to be used by the end-user
--test Download only part of video for testing extractors --test Download only part of video for testing extractors
--youtube-print-sig-code For testing youtube signatures --youtube-print-sig-code For testing youtube signatures
--allow-unplayable-formats List unplayable formats also
--no-allow-unplayable-formats Default
#### Old aliases #### Old aliases

View file

@ -497,6 +497,12 @@ class YoutubeDL(object):
self.report_warning( self.report_warning(
'Python version %d.%d is not supported! Please update to Python 3.6 or above' % sys.version_info[:2]) 'Python version %d.%d is not supported! Please update to Python 3.6 or above' % sys.version_info[:2])
if self.params.get('allow_unplayable_formats'):
self.report_warning(
'You have asked for unplayable formats to be listed/downloaded. '
'This is a developer option intended for debugging. '
'If you experience any issues while using this option, DO NOT open a bug report')
def check_deprecated(param, option, suggestion): def check_deprecated(param, option, suggestion):
if self.params.get(param) is not None: if self.params.get(param) is not None:
self.report_warning('%s is deprecated. Use %s instead' % (option, suggestion)) self.report_warning('%s is deprecated. Use %s instead' % (option, suggestion))
@ -827,6 +833,14 @@ class YoutubeDL(object):
except UnicodeEncodeError: except UnicodeEncodeError:
self.to_screen('Deleting existing file') self.to_screen('Deleting existing file')
def raise_no_formats(self, has_drm=False, forced=False):
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)
else:
self.report_warning(msg)
def parse_outtmpl(self): def parse_outtmpl(self):
outtmpl_dict = self.params.get('outtmpl', {}) outtmpl_dict = self.params.get('outtmpl', {})
if not isinstance(outtmpl_dict, dict): if not isinstance(outtmpl_dict, dict):
@ -2151,11 +2165,12 @@ class YoutubeDL(object):
else: else:
formats = info_dict['formats'] formats = info_dict['formats']
if not self.params.get('allow_unplayable_formats'):
formats = [f for f in formats if not f.get('has_drm')]
info_dict['__has_drm'] = len(info_dict.get('formats') or ['']) > len(formats)
if not formats: if not formats:
if not self.params.get('ignore_no_formats_error'): self.raise_no_formats(info_dict.get('__has_drm'))
raise ExtractorError('No video formats found!')
else:
self.report_warning('No video formats found!')
def is_wellformed(f): def is_wellformed(f):
url = f.get('url') url = f.get('url')
@ -2219,7 +2234,7 @@ class YoutubeDL(object):
# TODO Central sorting goes here # TODO Central sorting goes here
if formats and formats[0] is not info_dict: if not formats or formats[0] is not info_dict:
# only set the 'formats' fields if the original info_dict list them # only set the 'formats' fields if the original info_dict list them
# otherwise we end up with a circular reference, the first (and unique) # otherwise we end up with a circular reference, the first (and unique)
# element in the 'formats' field in info_dict is info_dict itself, # element in the 'formats' field in info_dict is info_dict itself,
@ -2232,7 +2247,8 @@ class YoutubeDL(object):
self.list_thumbnails(info_dict) self.list_thumbnails(info_dict)
if self.params.get('listformats'): if self.params.get('listformats'):
if not info_dict.get('formats') and not info_dict.get('url'): if not info_dict.get('formats') and not info_dict.get('url'):
raise ExtractorError('No video formats found', expected=True) self.to_screen('%s has no formats' % info_dict['id'])
else:
self.list_formats(info_dict) self.list_formats(info_dict)
if self.params.get('listsubtitles'): if self.params.get('listsubtitles'):
if 'automatic_captions' in info_dict: if 'automatic_captions' in info_dict:
@ -2410,6 +2426,8 @@ class YoutubeDL(object):
self.to_stdout(json.dumps(self.sanitize_info(info_dict))) self.to_stdout(json.dumps(self.sanitize_info(info_dict)))
def dl(self, name, info, subtitle=False, test=False): def dl(self, name, info, subtitle=False, test=False):
if not info.get('url'):
self.raise_no_formats(info.get('__has_drm'), forced=True)
if test: if test:
verbose = self.params.get('verbose') verbose = self.params.get('verbose')

View file

@ -549,7 +549,7 @@ class BrightcoveNewIE(AdobePassIE):
error.get('message') or error.get('error_subcode') or error['error_code'], expected=True) error.get('message') or error.get('error_subcode') or error['error_code'], expected=True)
elif (not self.get_param('allow_unplayable_formats') elif (not self.get_param('allow_unplayable_formats')
and sources and num_drm_sources == len(sources)): and sources and num_drm_sources == len(sources)):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
self._sort_formats(formats) self._sort_formats(formats)

View file

@ -147,9 +147,6 @@ class CeskaTelevizeIE(InfoExtractor):
is_live = item.get('type') == 'LIVE' is_live = item.get('type') == 'LIVE'
formats = [] formats = []
for format_id, stream_url in item.get('streamUrls', {}).items(): for format_id, stream_url in item.get('streamUrls', {}).items():
if (not self.get_param('allow_unplayable_formats')
and 'drmOnly=true' in stream_url):
continue
if 'playerType=flash' in stream_url: if 'playerType=flash' in stream_url:
stream_formats = self._extract_m3u8_formats( stream_formats = self._extract_m3u8_formats(
stream_url, playlist_id, 'mp4', 'm3u8_native', stream_url, playlist_id, 'mp4', 'm3u8_native',
@ -158,6 +155,9 @@ class CeskaTelevizeIE(InfoExtractor):
stream_formats = self._extract_mpd_formats( stream_formats = self._extract_mpd_formats(
stream_url, playlist_id, stream_url, playlist_id,
mpd_id='dash-%s' % format_id, fatal=False) mpd_id='dash-%s' % format_id, fatal=False)
if 'drmOnly=true' in stream_url:
for f in stream_formats:
f['has_drm'] = True
# See https://github.com/ytdl-org/youtube-dl/issues/12119#issuecomment-280037031 # See https://github.com/ytdl-org/youtube-dl/issues/12119#issuecomment-280037031
if format_id == 'audioDescription': if format_id == 'audioDescription':
for f in stream_formats: for f in stream_formats:

View file

@ -203,6 +203,7 @@ class InfoExtractor(object):
width : height ratio as float. width : height ratio as float.
* no_resume The server does not support resuming the * no_resume The server does not support resuming the
(HTTP or RTMP) download. Boolean. (HTTP or RTMP) download. Boolean.
* has_drm The format has DRM and cannot be downloaded. Boolean
* downloader_options A dictionary of downloader options as * downloader_options A dictionary of downloader options as
described in FileDownloader described in FileDownloader
RTMP formats can also have the additional fields: page_url, RTMP formats can also have the additional fields: page_url,
@ -1024,6 +1025,9 @@ class InfoExtractor(object):
return self._downloader.params.get(name, default, *args, **kwargs) return self._downloader.params.get(name, default, *args, **kwargs)
return default return default
def report_drm(self, video_id, partial=False):
self.raise_no_formats('This video is DRM protected', expected=True, video_id=video_id)
def report_extraction(self, id_or_name): def report_extraction(self, id_or_name):
"""Report information extraction.""" """Report information extraction."""
self.to_screen('%s: Extracting information' % id_or_name) self.to_screen('%s: Extracting information' % id_or_name)
@ -1752,9 +1756,7 @@ class InfoExtractor(object):
def _sort_formats(self, formats, field_preference=[]): def _sort_formats(self, formats, field_preference=[]):
if not formats: if not formats:
if self.get_param('ignore_no_formats_error'):
return return
raise ExtractorError('No video formats found')
format_sort = self.FormatSort() # params and to_screen are taken from the downloader format_sort = self.FormatSort() # params and to_screen are taken from the downloader
format_sort.evaluate_params(self._downloader.params, field_preference) format_sort.evaluate_params(self._downloader.params, field_preference)
if self.get_param('verbose', False): if self.get_param('verbose', False):
@ -1992,9 +1994,7 @@ class InfoExtractor(object):
if '#EXT-X-FAXS-CM:' in m3u8_doc: # Adobe Flash Access if '#EXT-X-FAXS-CM:' in m3u8_doc: # Adobe Flash Access
return formats, subtitles return formats, subtitles
if (not self.get_param('allow_unplayable_formats') has_drm = re.search(r'#EXT-X-SESSION-KEY:.*?URI="skd://', m3u8_doc)
and re.search(r'#EXT-X-SESSION-KEY:.*?URI="skd://', m3u8_doc)): # Apple FairPlay
return formats, subtitles
def format_url(url): def format_url(url):
return url if re.match(r'^https?://', url) else compat_urlparse.urljoin(m3u8_url, url) return url if re.match(r'^https?://', url) else compat_urlparse.urljoin(m3u8_url, url)
@ -2040,6 +2040,7 @@ class InfoExtractor(object):
'protocol': entry_protocol, 'protocol': entry_protocol,
'preference': preference, 'preference': preference,
'quality': quality, 'quality': quality,
'has_drm': has_drm,
} for idx in _extract_m3u8_playlist_indices(m3u8_doc=m3u8_doc)] } for idx in _extract_m3u8_playlist_indices(m3u8_doc=m3u8_doc)]
return formats, subtitles return formats, subtitles
@ -2573,8 +2574,6 @@ class InfoExtractor(object):
extract_Initialization(segment_template) extract_Initialization(segment_template)
return ms_info return ms_info
skip_unplayable = not self.get_param('allow_unplayable_formats')
mpd_duration = parse_duration(mpd_doc.get('mediaPresentationDuration')) mpd_duration = parse_duration(mpd_doc.get('mediaPresentationDuration'))
formats = [] formats = []
subtitles = {} subtitles = {}
@ -2585,12 +2584,8 @@ class InfoExtractor(object):
'timescale': 1, 'timescale': 1,
}) })
for adaptation_set in period.findall(_add_ns('AdaptationSet')): for adaptation_set in period.findall(_add_ns('AdaptationSet')):
if skip_unplayable and is_drm_protected(adaptation_set):
continue
adaption_set_ms_info = extract_multisegment_info(adaptation_set, period_ms_info) adaption_set_ms_info = extract_multisegment_info(adaptation_set, period_ms_info)
for representation in adaptation_set.findall(_add_ns('Representation')): for representation in adaptation_set.findall(_add_ns('Representation')):
if skip_unplayable and is_drm_protected(representation):
continue
representation_attrib = adaptation_set.attrib.copy() representation_attrib = adaptation_set.attrib.copy()
representation_attrib.update(representation.attrib) representation_attrib.update(representation.attrib)
# According to [1, 5.3.7.2, Table 9, page 41], @mimeType is mandatory # According to [1, 5.3.7.2, Table 9, page 41], @mimeType is mandatory
@ -2662,6 +2657,8 @@ class InfoExtractor(object):
'acodec': 'none', 'acodec': 'none',
'vcodec': 'none', 'vcodec': 'none',
} }
if is_drm_protected(adaptation_set) or is_drm_protected(representation):
f['has_drm'] = True
representation_ms_info = extract_multisegment_info(representation, adaption_set_ms_info) representation_ms_info = extract_multisegment_info(representation, adaption_set_ms_info)
def prepare_template(template_name, identifiers): def prepare_template(template_name, identifiers):
@ -2848,9 +2845,6 @@ class InfoExtractor(object):
""" """
if ism_doc.get('IsLive') == 'TRUE': if ism_doc.get('IsLive') == 'TRUE':
return [], {} return [], {}
if (not self.get_param('allow_unplayable_formats')
and ism_doc.find('Protection') is not None):
return [], {}
duration = int(ism_doc.attrib['Duration']) duration = int(ism_doc.attrib['Duration'])
timescale = int_or_none(ism_doc.get('TimeScale')) or 10000000 timescale = int_or_none(ism_doc.get('TimeScale')) or 10000000
@ -2941,6 +2935,7 @@ class InfoExtractor(object):
'acodec': 'none' if stream_type == 'video' else fourcc, 'acodec': 'none' if stream_type == 'video' else fourcc,
'protocol': 'ism', 'protocol': 'ism',
'fragments': fragments, 'fragments': fragments,
'has_drm': ism_doc.find('Protection') is not None,
'_download_params': { '_download_params': {
'stream_type': stream_type, 'stream_type': stream_type,
'duration': duration, 'duration': duration,

View file

@ -130,7 +130,7 @@ class CorusIE(ThePlatformFeedIE):
formats.extend(self._parse_smil_formats( formats.extend(self._parse_smil_formats(
smil, smil_url, video_id, namespace)) smil, smil_url, video_id, namespace))
if not formats and video.get('drm'): if not formats and video.get('drm'):
self.raise_no_formats('This video is DRM protected.', expected=True) self.report_drm(video_id)
self._sort_formats(formats) self._sort_formats(formats)
subtitles = {} subtitles = {}

View file

@ -176,8 +176,8 @@ class CrackleIE(InfoExtractor):
'width': mfs_info['width'], 'width': mfs_info['width'],
'height': mfs_info['height'], 'height': mfs_info['height'],
}) })
if not formats and has_drm and not ignore_no_formats: if not formats and has_drm:
raise ExtractorError('The video is DRM protected', expected=True) self.report_drm(video_id)
self._sort_formats(formats) self._sort_formats(formats)
description = media.get('Description') description = media.get('Description')

View file

@ -97,7 +97,7 @@ class GloboIE(InfoExtractor):
'http://api.globovideos.com/videos/%s/playlist' % video_id, 'http://api.globovideos.com/videos/%s/playlist' % video_id,
video_id)['videos'][0] video_id)['videos'][0]
if not self.get_param('allow_unplayable_formats') and video.get('encrypted') is True: if not self.get_param('allow_unplayable_formats') and video.get('encrypted') is True:
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
title = video['title'] title = video['title']

View file

@ -182,7 +182,8 @@ class HotStarIE(HotStarBaseIE):
title = video_data['title'] title = video_data['title']
if not self.get_param('allow_unplayable_formats') and video_data.get('drmProtected'): if not self.get_param('allow_unplayable_formats') and video_data.get('drmProtected'):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
headers = {'Referer': 'https://www.hotstar.com/in'} headers = {'Referer': 'https://www.hotstar.com/in'}
formats = [] formats = []
subs = {} subs = {}

View file

@ -4,7 +4,6 @@ from __future__ import unicode_literals
from .common import InfoExtractor from .common import InfoExtractor
from ..utils import ( from ..utils import (
ExtractorError,
float_or_none, float_or_none,
int_or_none, int_or_none,
parse_iso8601, parse_iso8601,
@ -35,7 +34,7 @@ class NineCNineMediaIE(InfoExtractor):
if (not self.get_param('allow_unplayable_formats') if (not self.get_param('allow_unplayable_formats')
and try_get(content_package, lambda x: x['Constraints']['Security']['Type'])): and try_get(content_package, lambda x: x['Constraints']['Security']['Type'])):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(content_id)
manifest_base_url = content_package_url + 'manifest.' manifest_base_url = content_package_url + 'manifest.'
formats = [] formats = []

View file

@ -66,11 +66,12 @@ class NineNowIE(InfoExtractor):
video_data = common_data['video'] video_data = common_data['video']
if not self.get_param('allow_unplayable_formats') and video_data.get('drm'):
raise ExtractorError('This video is DRM protected.', expected=True)
brightcove_id = video_data.get('brightcoveId') or 'ref:' + video_data['referenceId'] brightcove_id = video_data.get('brightcoveId') or 'ref:' + video_data['referenceId']
video_id = compat_str(video_data.get('id') or brightcove_id) video_id = compat_str(video_data.get('id') or brightcove_id)
if not self.get_param('allow_unplayable_formats') and video_data.get('drm'):
self.report_drm(video_id)
title = common_data['name'] title = common_data['name']
thumbnails = [{ thumbnails = [{

View file

@ -247,8 +247,7 @@ class NPOIE(NPOBaseIE):
if not formats: if not formats:
if not self.get_param('allow_unplayable_formats') and drm: if not self.get_param('allow_unplayable_formats') and drm:
self.raise_no_formats('This video is DRM protected.', expected=True) self.report_drm(video_id)
return
self._sort_formats(formats) self._sort_formats(formats)

View file

@ -35,7 +35,7 @@ class ProSiebenSat1BaseIE(InfoExtractor):
})[0] })[0]
if not self.get_param('allow_unplayable_formats') and video.get('is_protected') is True: if not self.get_param('allow_unplayable_formats') and video.get('is_protected') is True:
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(clip_id)
formats = [] formats = []
if self._ACCESS_ID: if self._ACCESS_ID:

View file

@ -281,7 +281,7 @@ class RaiPlayIE(RaiBaseIE):
(lambda x: x['rights_management']['rights']['drm'], (lambda x: x['rights_management']['rights']['drm'],
lambda x: x['program_info']['rights_management']['rights']['drm']), lambda x: x['program_info']['rights_management']['rights']['drm']),
dict): dict):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
title = media['name'] title = media['name']
video = media['video'] video = media['video']

View file

@ -202,7 +202,7 @@ class RuutuIE(InfoExtractor):
if not formats: if not formats:
if (not self.get_param('allow_unplayable_formats') if (not self.get_param('allow_unplayable_formats')
and xpath_text(video_xml, './Clip/DRM', default=None)): and xpath_text(video_xml, './Clip/DRM', default=None)):
self.raise_no_formats('This video is DRM protected.', expected=True) self.report_drm(video_id)
ns_st_cds = pv('ns_st_cds') ns_st_cds = pv('ns_st_cds')
if ns_st_cds != 'free': if ns_st_cds != 'free':
raise ExtractorError('This video is %s.' % ns_st_cds, expected=True) raise ExtractorError('This video is %s.' % ns_st_cds, expected=True)

View file

@ -119,7 +119,7 @@ class ShahidIE(ShahidBaseIE):
'playout/new/url/' + video_id, video_id)['playout'] 'playout/new/url/' + video_id, video_id)['playout']
if not self.get_param('allow_unplayable_formats') and playout.get('drm'): if not self.get_param('allow_unplayable_formats') and playout.get('drm'):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
formats = self._extract_m3u8_formats(re.sub( formats = self._extract_m3u8_formats(re.sub(
# https://docs.aws.amazon.com/mediapackage/latest/ug/manifest-filtering.html # https://docs.aws.amazon.com/mediapackage/latest/ug/manifest-filtering.html

View file

@ -83,7 +83,7 @@ class SonyLIVIE(InfoExtractor):
content = self._call_api( content = self._call_api(
'1.5', 'IN/CONTENT/VIDEOURL/VOD/' + video_id, video_id) '1.5', 'IN/CONTENT/VIDEOURL/VOD/' + video_id, video_id)
if not self.get_param('allow_unplayable_formats') and content.get('isEncrypted'): if not self.get_param('allow_unplayable_formats') and content.get('isEncrypted'):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
dash_url = content['videoURL'] dash_url = content['videoURL']
headers = { headers = {
'x-playback-session-id': '%s-%d' % (uuid.uuid4().hex, time.time() * 1000) 'x-playback-session-id': '%s-%d' % (uuid.uuid4().hex, time.time() * 1000)

View file

@ -155,8 +155,7 @@ class ToggleIE(InfoExtractor):
for meta in (info.get('Metas') or []): for meta in (info.get('Metas') or []):
if (not self.get_param('allow_unplayable_formats') if (not self.get_param('allow_unplayable_formats')
and meta.get('Key') == 'Encryption' and meta.get('Value') == '1'): and meta.get('Key') == 'Encryption' and meta.get('Value') == '1'):
self.raise_no_formats( self.report_drm(video_id)
'This video is DRM protected.', expected=True)
# Most likely because geo-blocked if no formats and no DRM # Most likely because geo-blocked if no formats and no DRM
self._sort_formats(formats) self._sort_formats(formats)

View file

@ -103,7 +103,7 @@ class TV2IE(InfoExtractor):
'filesize': int_or_none(item.get('fileSize')), 'filesize': int_or_none(item.get('fileSize')),
}) })
if not formats and data.get('drmProtected'): if not formats and data.get('drmProtected'):
self.raise_no_formats('This video is DRM protected.', expected=True) self.report_drm(video_id)
self._sort_formats(formats) self._sort_formats(formats)
thumbnails = [{ thumbnails = [{

View file

@ -247,8 +247,7 @@ class VidioLiveIE(VidioBaseIE):
formats = [] formats = []
if stream_meta.get('is_drm'): if stream_meta.get('is_drm'):
if not self.get_param('allow_unplayable_formats'): if not self.get_param('allow_unplayable_formats'):
self.raise_no_formats( self.report_drm(video_id)
'This video is DRM protected.', expected=True)
if stream_meta.get('is_premium'): if stream_meta.get('is_premium'):
sources = self._download_json( sources = self._download_json(
'https://www.vidio.com/interactions_stream.json?video_id=%s&type=livestreamings' % video_id, 'https://www.vidio.com/interactions_stream.json?video_id=%s&type=livestreamings' % video_id,

View file

@ -3,7 +3,6 @@ from __future__ import unicode_literals
from .common import InfoExtractor from .common import InfoExtractor
from ..utils import ( from ..utils import (
ExtractorError,
merge_dicts, merge_dicts,
urljoin, urljoin,
) )
@ -47,7 +46,7 @@ class WakanimIE(InfoExtractor):
r'encryption%3D(c(?:enc|bc(?:s-aapl)?))', r'encryption%3D(c(?:enc|bc(?:s-aapl)?))',
m3u8_url, 'encryption', default=None) m3u8_url, 'encryption', default=None)
if encryption in ('cenc', 'cbcs-aapl'): if encryption in ('cenc', 'cbcs-aapl'):
raise ExtractorError('This video is DRM protected.', expected=True) self.report_drm(video_id)
formats = self._extract_m3u8_formats( formats = self._extract_m3u8_formats(
m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native', m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native',

View file

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

View file

@ -2793,8 +2793,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
if not formats: if not formats:
if not self.get_param('allow_unplayable_formats') and traverse_obj(streaming_data, (..., 'licenseInfos')): if not self.get_param('allow_unplayable_formats') and traverse_obj(streaming_data, (..., 'licenseInfos')):
self.raise_no_formats( self.report_drm(video_id)
'This video is DRM protected.', expected=True)
pemr = get_first( pemr = get_first(
playability_statuses, playability_statuses,
('errorScreen', 'playerErrorMessageRenderer'), expected_type=dict) or {} ('errorScreen', 'playerErrorMessageRenderer'), expected_type=dict) or {}

View file

@ -580,13 +580,11 @@ def parseOpts(overrideArguments=None):
video_format.add_option( video_format.add_option(
'--allow-unplayable-formats', '--allow-unplayable-formats',
action='store_true', dest='allow_unplayable_formats', default=False, action='store_true', dest='allow_unplayable_formats', default=False,
help=( help=optparse.SUPPRESS_HELP)
'Allow unplayable formats to be listed and downloaded. '
'All video post-processing will also be turned off'))
video_format.add_option( video_format.add_option(
'--no-allow-unplayable-formats', '--no-allow-unplayable-formats',
action='store_false', dest='allow_unplayable_formats', action='store_false', dest='allow_unplayable_formats',
help='Do not allow unplayable formats to be listed or downloaded (default)') help=optparse.SUPPRESS_HELP)
subtitles = optparse.OptionGroup(parser, 'Subtitle Options') subtitles = optparse.OptionGroup(parser, 'Subtitle Options')
subtitles.add_option( subtitles.add_option(