From adf2598eb888452cb10cc5f4bada3f4b43171d24 Mon Sep 17 00:00:00 2001 From: DmitryScaletta Date: Tue, 9 Jan 2024 02:57:04 +0300 Subject: [PATCH 1/2] [ie/Twitch] Fix video formats extraction --- yt_dlp/extractor/twitch.py | 52 ++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/yt_dlp/extractor/twitch.py b/yt_dlp/extractor/twitch.py index 3297ef09179..c1d40014aee 100644 --- a/yt_dlp/extractor/twitch.py +++ b/yt_dlp/extractor/twitch.py @@ -8,7 +8,6 @@ from ..compat import ( compat_parse_qs, compat_str, - compat_urllib_parse_urlencode, compat_urllib_parse_urlparse, ) from ..utils import ( @@ -191,6 +190,24 @@ def _get_thumbnails(self, thumbnail): 'url': thumbnail, }] if thumbnail else None + def _extract_twitch_m3u8_formats(self, type, id, token, signature): + URLS_MAP = { + 'video': '%s/vod/%s.m3u8', + 'stream': '%s/api/channel/hls/%s.m3u8' + } + query = { + 'allow_source': 'true', + 'allow_audio_only': 'true', + 'allow_spectre': 'true', + 'p': random.randint(1000000, 10000000), + 'player': 'twitchweb', + 'playlist_include_framerate': 'true', + 'sig': signature, + 'token': token, + } + return self._extract_m3u8_formats( + URLS_MAP[type] % (self._USHER_BASE, id), id, 'mp4', query=query) + class TwitchVodIE(TwitchBaseIE): IE_NAME = 'twitch:vod' @@ -532,20 +549,8 @@ def _real_extract(self, url): info = self._extract_info_gql(video, vod_id) access_token = self._download_access_token(vod_id, 'video', 'id') - formats = self._extract_m3u8_formats( - '%s/vod/%s.m3u8?%s' % ( - self._USHER_BASE, vod_id, - compat_urllib_parse_urlencode({ - 'allow_source': 'true', - 'allow_audio_only': 'true', - 'allow_spectre': 'true', - 'player': 'twitchweb', - 'playlist_include_framerate': 'true', - 'nauth': access_token['value'], - 'nauthsig': access_token['signature'], - })), - vod_id, 'mp4', entry_protocol='m3u8_native') - + formats = self._extract_twitch_m3u8_formats( + 'video', vod_id, access_token['value'], access_token['signature']) formats.extend(self._extract_storyboard(vod_id, video.get('storyboard'), info.get('duration'))) self._prefer_source(formats) @@ -1026,23 +1031,10 @@ def _real_extract(self, url): access_token = self._download_access_token( channel_name, 'stream', 'channelName') - token = access_token['value'] stream_id = stream.get('id') or channel_name - query = { - 'allow_source': 'true', - 'allow_audio_only': 'true', - 'allow_spectre': 'true', - 'p': random.randint(1000000, 10000000), - 'player': 'twitchweb', - 'playlist_include_framerate': 'true', - 'segment_preference': '4', - 'sig': access_token['signature'].encode('utf-8'), - 'token': token.encode('utf-8'), - } - formats = self._extract_m3u8_formats( - '%s/api/channel/hls/%s.m3u8' % (self._USHER_BASE, channel_name), - stream_id, 'mp4', query=query) + formats = self._extract_twitch_m3u8_formats( + 'stream', channel_name, access_token['value'], access_token['signature']) self._prefer_source(formats) view_count = stream.get('viewers') From 9c4094779d9d962a07ea5e31312f60d7b4ff30db Mon Sep 17 00:00:00 2001 From: DmitryScaletta Date: Tue, 9 Jan 2024 03:44:47 +0300 Subject: [PATCH 2/2] [ie/Twitch] Refactor extracting formats --- yt_dlp/extractor/twitch.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/yt_dlp/extractor/twitch.py b/yt_dlp/extractor/twitch.py index c1d40014aee..6dc0993afc7 100644 --- a/yt_dlp/extractor/twitch.py +++ b/yt_dlp/extractor/twitch.py @@ -190,23 +190,19 @@ def _get_thumbnails(self, thumbnail): 'url': thumbnail, }] if thumbnail else None - def _extract_twitch_m3u8_formats(self, type, id, token, signature): - URLS_MAP = { - 'video': '%s/vod/%s.m3u8', - 'stream': '%s/api/channel/hls/%s.m3u8' - } - query = { - 'allow_source': 'true', - 'allow_audio_only': 'true', - 'allow_spectre': 'true', - 'p': random.randint(1000000, 10000000), - 'player': 'twitchweb', - 'playlist_include_framerate': 'true', - 'sig': signature, - 'token': token, - } + def _extract_twitch_m3u8_formats(self, video_id, token, signature): + """Subclasses must define _M3U8_PATH""" return self._extract_m3u8_formats( - URLS_MAP[type] % (self._USHER_BASE, id), id, 'mp4', query=query) + f'{self._USHER_BASE}/{self._M3U8_PATH}/{video_id}.m3u8', video_id, 'mp4', query={ + 'allow_source': 'true', + 'allow_audio_only': 'true', + 'allow_spectre': 'true', + 'p': random.randint(1000000, 10000000), + 'player': 'twitchweb', + 'playlist_include_framerate': 'true', + 'sig': signature, + 'token': token, + }) class TwitchVodIE(TwitchBaseIE): @@ -220,6 +216,7 @@ class TwitchVodIE(TwitchBaseIE): ) (?P\d+) ''' + _M3U8_PATH = 'vod' _TESTS = [{ 'url': 'http://www.twitch.tv/riotgames/v/6528877?t=5m10s', @@ -550,7 +547,7 @@ def _real_extract(self, url): access_token = self._download_access_token(vod_id, 'video', 'id') formats = self._extract_twitch_m3u8_formats( - 'video', vod_id, access_token['value'], access_token['signature']) + vod_id, access_token['value'], access_token['signature']) formats.extend(self._extract_storyboard(vod_id, video.get('storyboard'), info.get('duration'))) self._prefer_source(formats) @@ -929,6 +926,7 @@ class TwitchStreamIE(TwitchBaseIE): ) (?P[^/#?]+) ''' + _M3U8_PATH = 'api/channel/hls' _TESTS = [{ 'url': 'http://www.twitch.tv/shroomztv', @@ -1034,7 +1032,7 @@ def _real_extract(self, url): stream_id = stream.get('id') or channel_name formats = self._extract_twitch_m3u8_formats( - 'stream', channel_name, access_token['value'], access_token['signature']) + channel_name, access_token['value'], access_token['signature']) self._prefer_source(formats) view_count = stream.get('viewers')