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

Code before:
        # vod.tvp.pl
        if info.get('vortalName') == 'vod':
            info_dict.update({
                'title': '%s, %s' % (info.get('title'), info.get('subtitle')),
                'series': info.get('title'),
                'season': info.get('season'),
                'episode_number': info.get('episode'),
            })

        return info_dict


class TVPVODBaseIE(InfoExtractor):
    _API_BASE_URL = 'https://vod.tvp.pl/api/products'

    def _call_api(self, resource, video_id, query={}, **kwargs):
        is_valid = lambda x: x >= 200 and x < 300
        is_handled_error = lambda x: x >= 400 and x < 500
        document, urlh = self._download_json_handle(
            f'{self._API_BASE_URL}/{resource}', video_id,
            query={'lang': 'pl', 'platform': 'BROWSER', **query},
            expected_status=lambda x: is_valid(x) or is_handled_error(x), **kwargs)
        if is_valid(urlh.status):
            return document
        error_code = document.get('code')
        raise ExtractorError(f'Response from Woronicza: {error_code}')

    def _parse_video(self, video, with_url=True):
        info_dict = traverse_obj(video, {
            'id': ('id', {str_or_none}),
            'title': 'title',
            'age_limit': ('rating', {int_or_none}),
            'duration': ('duration', {int_or_none}),
            'episode_number': ('number', {int_or_none}),
            'series': ('season', 'serial', 'title', {str_or_none}),
            'thumbnails': ('images', ..., ..., {'url': ('url', {url_or_none})}),
        })
        info_dict['description'] = clean_html(video.get('lead') or video.get('description'))
        if with_url:
            info_dict.update({
                '_type': 'url',
                'url': video['webUrl'],
                'ie_key': TVPVODVideoIE.ie_key(),
            })
        return info_dict


class TVPVODVideoIE(TVPVODBaseIE):
    IE_NAME = 'tvp:vod'
    _VALID_URL = r'https?://vod\.tvp\.pl/[a-z\d-]+,\d+/[a-z\d-]+(?<!-odcinki)(?:-odcinki,\d+/odcinek-\d+,S\d+E\d+)?,(?P<id>\d+)(?:\?[^#]+)?(?:#.+)?$'


Review comment (refactor):
```suggestion
        raise ExtractorError(f'Woronicza said: {document.get("code")}')
```

Code after:
        # vod.tvp.pl
        if info.get('vortalName') == 'vod':
            info_dict.update({
                'title': '%s, %s' % (info.get('title'), info.get('subtitle')),
                'series': info.get('title'),
                'season': info.get('season'),
                'episode_number': info.get('episode'),
            })

        return info_dict


class TVPVODBaseIE(InfoExtractor):
    _API_BASE_URL = 'https://vod.tvp.pl/api/products'

    def _call_api(self, resource, video_id, query={}, **kwargs):
        is_valid = lambda x: 200 <= x < 300
        document, urlh = self._download_json_handle(
            f'{self._API_BASE_URL}/{resource}', video_id,
            query={'lang': 'pl', 'platform': 'BROWSER', **query},
            expected_status=lambda x: is_valid(x) or 400 <= x < 500, **kwargs)
        if is_valid(urlh.status):
            return document
        raise ExtractorError(f'Woronicza said: {document.get("code")} (HTTP {urlh.status})')

    def _parse_video(self, video, with_url=True):
        info_dict = traverse_obj(video, {
            'id': ('id', {str_or_none}),
            'title': 'title',
            'age_limit': ('rating', {int_or_none}),
            'duration': ('duration', {int_or_none}),
            'episode_number': ('number', {int_or_none}),
            'series': ('season', 'serial', 'title', {str_or_none}),
            'thumbnails': ('images', ..., ..., {'url': ('url', {url_or_none})}),
        })
        info_dict['description'] = clean_html(dict_get(video, ('lead', 'description')))
        if with_url:
            info_dict.update({
                '_type': 'url',
                'url': video['webUrl'],
                'ie_key': TVPVODVideoIE.ie_key(),
            })
        return info_dict


class TVPVODVideoIE(TVPVODBaseIE):
    IE_NAME = 'tvp:vod'
    _VALID_URL = r'https?://vod\.tvp\.pl/[a-z\d-]+,\d+/[a-z\d-]+(?<!-odcinki)(?:-odcinki,\d+/odcinek-\d+,S\d+E\d+)?,(?P<id>\d+)(?:\?[^#]+)?(?:#.+)?$'

    _TESTS = [{
        'url': 'https://vod.tvp.pl/dla-dzieci,24/laboratorium-alchemika-odcinki,309338/odcinek-24,S01E24,311357',