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

Code before:
        'note': 'This extractor is used by AcademyMel extractor, which has a login feature'
    }]

    def _real_extract(self, url):
        valid_url = self._match_valid_url(url)

        if not valid_url:
            raise ExtractorError('Invalid URL found', expected=True)

        webpage = self._download_webpage(url,
                                         None,
                                         fatal=True,
                                         note='Retrieving metadata...',
                                         errnote='Failed to retrieve metadata')

        window_configs = self._search_json(
            r'window\.configs\s*=\s*',
            webpage,
            'config',
            video_id=None,
            fatal=True)

        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
            window_configs.get('masterPlaylistUrl'),
            window_configs.get('videoId'))

        return {
            'id': str(window_configs.get('videoId')),
            'title': window_configs.get('videoHash'),
            'thumbnail': window_configs.get('thumbnailUrl'),
            'duration': int(window_configs.get('videoDuration')),
            'formats': formats,
            'subtitles': subtitles
        }


Review comment (refactor):
`video_id` and the m3u8 URL can (and should be) fatal
```suggestion
        window_configs = self._search_json(
            r'window\.configs\s*=', webpage, 'config', None)
        video_id = str(window_configs['videoId'])
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
            window_configs['masterPlaylistUrl'], video_id)
```

Code after:
            'thumbnail': 'https://preview-htz.kinescopecdn.net/preview/190bdf93f1b29735309853a7a19e24b3/preview.jpg?version=1702370546&host=vh-80',
            'duration': 1693
        },
        'skip': 'JWT expired',
    }]

    def _real_extract(self, url):
        webpage = self._download_webpage(url, None, 'Downloading player page')
        window_configs = self._search_json(
            r'window\.configs\s*=', webpage, 'config', None)
        video_id = str(window_configs['gcFileId'])
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
            window_configs['masterPlaylistUrl'], video_id)

        return {
            **traverse_obj(window_configs, {
                'title': ('videoHash', {str}),
                'thumbnail': ('previewUrl', {url_or_none}),
                'duration': ('videoDuration', {int_or_none}),
            }),
            'id': video_id,
            'formats': formats,
            'subtitles': subtitles
        }


class GetCourseRuIE(InfoExtractor):
    _NETRC_MACHINE = 'getcourseru'
    _DOMAINS = [
        'academymel.online',
        'marafon.mani-beauty.com',
        'on.psbook.ru'
    ]
    _BASE_URL_RE = rf'https?://(?:(?!player02\.)[^.]+\.getcourse\.(?:ru|io)|{"|".join(map(re.escape, _DOMAINS))})'
    _VALID_URL = [
        rf'{_BASE_URL_RE}/(?!pl/|teach/)(?P<id>[^?#]+)',
        rf'{_BASE_URL_RE}/(:?pl/)?teach/control/lesson/view\?(?:[^#]+&)?id=(?P<id>\d+)',
    ]
    _TESTS = [{
        'url': 'http://academymel.online/3video_1',
        'info_dict': {
            'id': '3059742',
            'display_id': '3video_1',
            'title': 'Промоуроки Академии МЕЛ',
        },
        'playlist_count': 1,
        'playlist': [{
            'info_dict': {
                'id': '513573381',
                'ext': 'mp4',
                'title': 'Промоуроки Академии МЕЛ',