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

Code before:
        'url': 'https://goodgame.ru/channel/Kochevnik',
        'info_dict': {
            'id': 'Kochevnik',
            'ext': 'mp4',
            'title': 'Кочетятр',
            'description': '',
            'thumbnail': r're:^https?://.*\.jpg$',
            'live_status': 'not_live',
        },
        'params': {
            'skip_download': 'm3u8',
        },
        'skip': 'HTTP Error 404: Not Found',
    }, {
        'url': 'https://goodgame.ru/channel/LampaRPG',
        'info_dict': {
            'id': 'LampaRPG',
            'ext': 'mp4',
            'title': r're:Рейтинговые герои.*$',
            'description': str,
            'thumbnail': r're:^https?://.*\.jpg$',
            'live_status': 'is_live',
        },
        'params': {
            'skip_download': 'm3u8',
        },
    }]

    def _real_extract(self, url):
        channel_id = self._match_id(url)

        response = self._download_json(f'https://api2.goodgame.ru/v2/streams/{channel_id}', channel_id)

        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
            f'https://hls.goodgame.ru/manifest/{response.get("id")}_master.m3u8',
            channel_id, 'mp4', m3u8_id='hls', live=True)
        self._sort_formats(formats)

        return {
            'id': channel_id,
            'formats': formats,
            'subtitles': subtitles,
            'title': traverse_obj(response, ('channel', 'title')),
            'description': clean_html(traverse_obj(response, ('channel', 'description'))),
            'thumbnail': traverse_obj(response, ('channel', 'thumb')),
            'is_live': True,
            'live_status': 'is_live' if response.get('status') == 'Live' else 'not_live',
        }


Review comment (suggestion):
```suggestion
        'params': {'skip_download': 'm3u8'},
        'skip: 'No longer live',
```

Code after:

class GoodGameIE(InfoExtractor):
    IE_NAME = 'goodgame:stream'
    _VALID_URL = r'https?://goodgame\.ru/channel/(?P<id>\w+)'
    _TESTS = [{
        'url': 'https://goodgame.ru/channel/Pomi/#autoplay',
        'info_dict': {
            'id': 'pomi',
            'ext': 'mp4',
            'title': r're:Reynor vs Special \(1/2,bo3\) Wardi Spring EU \- playoff \(финальный день\) \d{4}-\d{2}-\d{2} \d{2}:\d{2}$',
            'channel_id': '1644',
            'channel': 'Pomi',
            'channel_url': 'https://goodgame.ru/channel/Pomi/',
            'description': 'md5:4a87b775ee7b2b57bdccebe285bbe171',
            'thumbnail': r're:^https?://.*\.jpg$',
            'live_status': 'is_live',
            'view_count': int,
        },
        'params': {'skip_download': 'm3u8'},
        'skip': 'May not be online',
    }]

    def _real_extract(self, url):
        channel_name = self._match_id(url)
        response = self._download_json(f'https://api2.goodgame.ru/v2/streams/{channel_name}', channel_name)
        player_id = response['channel']['gg_player_src']

        formats, subtitles = [], {}
        if response.get('status') == 'Live':
            formats, subtitles = self._extract_m3u8_formats_and_subtitles(
                f'https://hls.goodgame.ru/manifest/{player_id}_master.m3u8',
                channel_name, 'mp4', live=True)
        else:
            self.raise_no_formats('User is offline', expected=True, video_id=channel_name)

        self._sort_formats(formats)
        return {
            'id': player_id,
            'formats': formats,
            'subtitles': subtitles,
            'title': traverse_obj(response, ('channel', 'title')),
            'channel': channel_name,
            'channel_id': str_or_none(traverse_obj(response, ('channel', 'id'))),
            'channel_url': response.get('url'),
            'description': clean_html(traverse_obj(response, ('channel', 'description'))),
            'thumbnail': traverse_obj(response, ('channel', 'thumb')),
            'is_live': bool(formats),
            'view_count': int_or_none(response.get('viewers')),
            'age_limit': 18 if traverse_obj(response, ('channel', 'adult')) else None,
        }