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

Code before:

    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, 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'
    _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',
        'info_dict': {
            'id': 'v6528877',
            'ext': 'mp4',
            'title': 'LCK Summer Split - Week 6 Day 1',
            'thumbnail': r're:^https?://.*\.jpg$',
            'duration': 17208,
            'timestamp': 1435131734,
            'upload_date': '20150624',
            'uploader': 'Riot Games',

Review comment (refactor):
Maybe it would be simpler to do it like this:
```suggestion
    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),
                'player': 'twitchweb',
                'playlist_include_framerate': 'true',
                'sig': signature,
                'token': token,
            })
```
and then in the respective concrete IE classes:
```py
    _M3U8_PATH = 'vod'
```
```py
    _M3U8_PATH = 'api/channel/hls'
```
(and remove the `'video'` and `'stream'` args from the method calls)

Code after:

    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),
                'player': 'twitchweb',
                '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',
            'thumbnail': r're:^https?://.*\.jpg$',
            'duration': 17208,
            'timestamp': 1435131734,
            'upload_date': '20150624',
            'uploader': 'Riot Games',
            'uploader_id': 'riotgames',
            'view_count': int,
            'start_time': 310,