mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-21 20:46:36 -05:00
[youtube] Fix format sorting when using alternate clients
This commit is contained in:
parent
5a1fc62b41
commit
2a9c6dcd22
1 changed files with 35 additions and 25 deletions
|
@ -2499,11 +2499,12 @@ def _extract_player_responses(self, clients, video_id, webpage, master_ytcfg, pl
|
||||||
|
|
||||||
def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
||||||
itags, stream_ids = [], []
|
itags, stream_ids = [], []
|
||||||
itag_qualities = {}
|
itag_qualities, res_qualities = {}, {}
|
||||||
q = qualities([
|
q = qualities([
|
||||||
# "tiny" is the smallest video-only format. But some audio-only formats
|
# Normally tiny is the smallest video-only formats. But
|
||||||
# was also labeled "tiny". It is not clear if such formats still exist
|
# audio-only formats with unknown quality may get tagged as tiny
|
||||||
'tiny', 'audio_quality_low', 'audio_quality_medium', 'audio_quality_high', # Audio only formats
|
'tiny',
|
||||||
|
'audio_quality_ultralow', 'audio_quality_low', 'audio_quality_medium', 'audio_quality_high', # Audio only formats
|
||||||
'small', 'medium', 'large', 'hd720', 'hd1080', 'hd1440', 'hd2160', 'hd2880', 'highres'
|
'small', 'medium', 'large', 'hd720', 'hd1080', 'hd1440', 'hd2160', 'hd2880', 'highres'
|
||||||
])
|
])
|
||||||
streaming_formats = traverse_obj(streaming_data, (..., ('formats', 'adaptiveFormats'), ...), default=[])
|
streaming_formats = traverse_obj(streaming_data, (..., ('formats', 'adaptiveFormats'), ...), default=[])
|
||||||
|
@ -2519,10 +2520,18 @@ def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
quality = fmt.get('quality')
|
quality = fmt.get('quality')
|
||||||
|
height = int_or_none(fmt.get('height'))
|
||||||
if quality == 'tiny' or not quality:
|
if quality == 'tiny' or not quality:
|
||||||
quality = fmt.get('audioQuality', '').lower() or quality
|
quality = fmt.get('audioQuality', '').lower() or quality
|
||||||
if itag and quality:
|
# The 3gp format (17) in android client has a quality of "small",
|
||||||
|
# but is actually worse than other formats
|
||||||
|
if itag == '17':
|
||||||
|
quality = 'tiny'
|
||||||
|
if quality:
|
||||||
|
if itag:
|
||||||
itag_qualities[itag] = quality
|
itag_qualities[itag] = quality
|
||||||
|
if height:
|
||||||
|
res_qualities[height] = quality
|
||||||
# FORMAT_STREAM_TYPE_OTF(otf=1) requires downloading the init fragment
|
# FORMAT_STREAM_TYPE_OTF(otf=1) requires downloading the init fragment
|
||||||
# (adding `&sq=0` to the URL) and parsing emsg box to determine the
|
# (adding `&sq=0` to the URL) and parsing emsg box to determine the
|
||||||
# number of fragment that would subsequently requested with (`&sq=N`)
|
# number of fragment that would subsequently requested with (`&sq=N`)
|
||||||
|
@ -2553,13 +2562,14 @@ def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
||||||
'filesize': int_or_none(fmt.get('contentLength')),
|
'filesize': int_or_none(fmt.get('contentLength')),
|
||||||
'format_id': itag,
|
'format_id': itag,
|
||||||
'format_note': ', '.join(filter(None, (
|
'format_note': ', '.join(filter(None, (
|
||||||
audio_track.get('displayName'), fmt.get('qualityLabel') or quality))),
|
audio_track.get('displayName'),
|
||||||
|
fmt.get('qualityLabel') or quality.replace('audio_quality_', '')))),
|
||||||
'fps': int_or_none(fmt.get('fps')),
|
'fps': int_or_none(fmt.get('fps')),
|
||||||
'height': int_or_none(fmt.get('height')),
|
'height': height,
|
||||||
'quality': q(quality),
|
'quality': q(quality),
|
||||||
'tbr': tbr,
|
'tbr': tbr,
|
||||||
'url': fmt_url,
|
'url': fmt_url,
|
||||||
'width': fmt.get('width'),
|
'width': int_or_none(fmt.get('width')),
|
||||||
'language': audio_track.get('id', '').split('.')[0],
|
'language': audio_track.get('id', '').split('.')[0],
|
||||||
}
|
}
|
||||||
mime_mobj = re.match(
|
mime_mobj = re.match(
|
||||||
|
@ -2567,11 +2577,6 @@ def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
||||||
if mime_mobj:
|
if mime_mobj:
|
||||||
dct['ext'] = mimetype2ext(mime_mobj.group(1))
|
dct['ext'] = mimetype2ext(mime_mobj.group(1))
|
||||||
dct.update(parse_codecs(mime_mobj.group(2)))
|
dct.update(parse_codecs(mime_mobj.group(2)))
|
||||||
# The 3gp format in android client has a quality of "small",
|
|
||||||
# but is actually worse than all other formats
|
|
||||||
if dct['ext'] == '3gp':
|
|
||||||
dct['quality'] = q('tiny')
|
|
||||||
dct['preference'] = -10
|
|
||||||
no_audio = dct.get('acodec') == 'none'
|
no_audio = dct.get('acodec') == 'none'
|
||||||
no_video = dct.get('vcodec') == 'none'
|
no_video = dct.get('vcodec') == 'none'
|
||||||
if no_audio:
|
if no_audio:
|
||||||
|
@ -2591,11 +2596,16 @@ def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
||||||
get_dash = not is_live and 'dash' not in skip_manifests and self.get_param('youtube_include_dash_manifest', True)
|
get_dash = not is_live and 'dash' not in skip_manifests and self.get_param('youtube_include_dash_manifest', True)
|
||||||
get_hls = 'hls' not in skip_manifests and self.get_param('youtube_include_hls_manifest', True)
|
get_hls = 'hls' not in skip_manifests and self.get_param('youtube_include_hls_manifest', True)
|
||||||
|
|
||||||
|
def guess_quality(f):
|
||||||
|
for val, qdict in ((f.get('format_id'), itag_qualities), (f.get('height'), res_qualities)):
|
||||||
|
if val in qdict:
|
||||||
|
return q(qdict[val])
|
||||||
|
return -1
|
||||||
|
|
||||||
for sd in streaming_data:
|
for sd in streaming_data:
|
||||||
hls_manifest_url = get_hls and sd.get('hlsManifestUrl')
|
hls_manifest_url = get_hls and sd.get('hlsManifestUrl')
|
||||||
if hls_manifest_url:
|
if hls_manifest_url:
|
||||||
for f in self._extract_m3u8_formats(
|
for f in self._extract_m3u8_formats(hls_manifest_url, video_id, 'mp4', fatal=False):
|
||||||
hls_manifest_url, video_id, 'mp4', fatal=False):
|
|
||||||
itag = self._search_regex(
|
itag = self._search_regex(
|
||||||
r'/itag/(\d+)', f['url'], 'itag', default=None)
|
r'/itag/(\d+)', f['url'], 'itag', default=None)
|
||||||
if itag in itags:
|
if itag in itags:
|
||||||
|
@ -2603,19 +2613,18 @@ def _extract_formats(self, streaming_data, video_id, player_url, is_live):
|
||||||
if itag:
|
if itag:
|
||||||
f['format_id'] = itag
|
f['format_id'] = itag
|
||||||
itags.append(itag)
|
itags.append(itag)
|
||||||
|
f['quality'] = guess_quality(f)
|
||||||
yield f
|
yield f
|
||||||
|
|
||||||
dash_manifest_url = get_dash and sd.get('dashManifestUrl')
|
dash_manifest_url = get_dash and sd.get('dashManifestUrl')
|
||||||
if dash_manifest_url:
|
if dash_manifest_url:
|
||||||
for f in self._extract_mpd_formats(
|
for f in self._extract_mpd_formats(dash_manifest_url, video_id, fatal=False):
|
||||||
dash_manifest_url, video_id, fatal=False):
|
|
||||||
itag = f['format_id']
|
itag = f['format_id']
|
||||||
if itag in itags:
|
if itag in itags:
|
||||||
continue
|
continue
|
||||||
if itag:
|
if itag:
|
||||||
itags.append(itag)
|
itags.append(itag)
|
||||||
if itag in itag_qualities:
|
f['quality'] = guess_quality(f)
|
||||||
f['quality'] = q(itag_qualities[itag])
|
|
||||||
filesize = int_or_none(self._search_regex(
|
filesize = int_or_none(self._search_regex(
|
||||||
r'/clen/(\d+)', f.get('fragment_base_url')
|
r'/clen/(\d+)', f.get('fragment_base_url')
|
||||||
or f['url'], 'file size', default=None))
|
or f['url'], 'file size', default=None))
|
||||||
|
@ -2740,13 +2749,14 @@ def feed_entry(name):
|
||||||
self.raise_no_formats(reason, expected=True)
|
self.raise_no_formats(reason, expected=True)
|
||||||
|
|
||||||
for f in formats:
|
for f in formats:
|
||||||
# TODO: detect if throttled
|
if '&c=WEB&' in f['url'] and '&ratebypass=yes&' not in f['url']: # throttled
|
||||||
if '&n=' in f['url']: # possibly throttled
|
|
||||||
f['source_preference'] = -10
|
f['source_preference'] = -10
|
||||||
# note = f.get('format_note')
|
note = f.get('format_note')
|
||||||
# f['format_note'] = f'{note} (throttled)' if note else '(throttled)'
|
f['format_note'] = f'{note} (throttled)' if note else '(throttled)'
|
||||||
|
|
||||||
self._sort_formats(formats)
|
# Source is given priority since formats that throttle are given lower source_preference
|
||||||
|
# When throttling issue is fully fixed, remove this
|
||||||
|
self._sort_formats(formats, ('quality', 'height', 'fps', 'source'))
|
||||||
|
|
||||||
keywords = get_first(video_details, 'keywords', expected_type=list) or []
|
keywords = get_first(video_details, 'keywords', expected_type=list) or []
|
||||||
if not keywords and webpage:
|
if not keywords and webpage:
|
||||||
|
|
Loading…
Reference in a new issue