Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/twitch.py (Python)

Code before:
              }
            }''' % (method, param_name, video_id),
        }
        return self._download_base_gql(
            video_id, ops,
            'Downloading %s access token GraphQL' % token_kind)['data'][method]

    def _get_thumbnails(self, thumbnail):
        return [{
            'url': re.sub(r'\d+x\d+(\.\w+)($|(?=[?#]))', r'0x0\g<1>', thumbnail),
            'preference': 1,
        }, {
            'url': thumbnail,
        }] if thumbnail else None

    def _extract_twitch_m3u8_formats(self, video_id, token, signature):
        """Subclasses must define _M3U8_PATH"""
        return self._extract_m3u8_formats(
            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),
                "platform": "web",
                'player': 'twitchweb',
                "supported_codecs": "av1,h265,h264",
                'playlist_include_framerate': 'true',
                'sig': signature,
                'token': token,
            })


class TwitchVodIE(TwitchBaseIE):
    IE_NAME = 'twitch:vod'
    _VALID_URL = r'''(?x)
                    https?://
                        (?:
                            (?:(?:www|go|m)\.)?twitch\.tv/(?:[^/]+/v(?:ideo)?|videos)/|
                            player\.twitch\.tv/\?.*?\bvideo=v?|
                            www\.twitch\.tv/[^/]+/schedule\?vodID=
                        )
                        (?P<id>\d+)
                    '''
    _M3U8_PATH = 'vod'

    _TESTS = [{
        'url': 'http://www.twitch.tv/riotgames/v/6528877?t=5m10s',
        'info_dict': {
            'id': 'v6528877',
            'ext': 'mp4',
            'title': 'LCK Summer Split - Week 6 Day 1',

Review comment (suggestion):
```suggestion
                'platform': 'web',
                'player': 'twitchweb',
                'supported_codecs': 'av1,h265,h264',
```

Code after:
              }
            }''' % (method, param_name, video_id),
        }
        return self._download_base_gql(
            video_id, ops,
            'Downloading %s access token GraphQL' % token_kind)['data'][method]

    def _get_thumbnails(self, thumbnail):
        return [{
            'url': re.sub(r'\d+x\d+(\.\w+)($|(?=[?#]))', r'0x0\g<1>', thumbnail),
            'preference': 1,
        }, {
            'url': thumbnail,
        }] if thumbnail else None

    def _extract_twitch_m3u8_formats(self, path, video_id, token, signature):
        formats = self._extract_m3u8_formats(
            f'{self._USHER_BASE}/{path}/{video_id}.m3u8', video_id, 'mp4', query={
                'allow_source': 'true',
                'allow_audio_only': 'true',
                'allow_spectre': 'true',
                'p': random.randint(1000000, 10000000),
                'platform': 'web',
                'player': 'twitchweb',
                'supported_codecs': 'av1,h265,h264',
                'playlist_include_framerate': 'true',
                'sig': signature,
                'token': token,
            })
        for fmt in formats:
            if fmt.get('vcodec') and fmt['vcodec'].startswith('av01'):
                # mpegts does not yet have proper support for av1
                fmt['downloader_options'] = {'ffmpeg_args_out': ['-f', 'mp4']}

        return formats


class TwitchVodIE(TwitchBaseIE):
    IE_NAME = 'twitch:vod'
    _VALID_URL = r'''(?x)
                    https?://
                        (?:
                            (?:(?:www|go|m)\.)?twitch\.tv/(?:[^/]+/v(?:ideo)?|videos)/|
                            player\.twitch\.tv/\?.*?\bvideo=v?|
                            www\.twitch\.tv/[^/]+/schedule\?vodID=
                        )
                        (?P<id>\d+)
                    '''

    _TESTS = [{
        'url': 'http://www.twitch.tv/riotgames/v/6528877?t=5m10s',