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

Code before:
                             'query': 'query getUserVideo($videoId: ID!) { video(id: $videoId) { title publicUrl programId tvSeasonNumber tvSeasonEpisodeNumber series { title } } }'}).encode(),
            headers={'Content-Type': 'application/json'})
        result = traverse_obj(result, ('data', 'video'), default={})
        if not result or not result.get('publicUrl'):
            raise ExtractorError('Show not found in A&E feed (too new?)', expected=True,
                                 video_id=remove_start(filter_value, '/'))
        title = result['title']
        video_id = result['programId']
        media_url = result['publicUrl']
        theplatform_metadata = self._download_theplatform_metadata(self._search_regex(
            r'https?://link\.theplatform\.com/s/([^?]+)', media_url, 'theplatform_path'), video_id)
        info = self._parse_theplatform_metadata(theplatform_metadata)
        auth = None
        if theplatform_metadata.get('AETN$isBehindWall'):
            resource = self._get_mvpd_resource(
                requestor_id, theplatform_metadata['title'],
                theplatform_metadata.get('AETN$PPL_pplProgramId') or theplatform_metadata.get('AETN$PPL_pplProgramId_OLD'),
                traverse_obj(theplatform_metadata, ('ratings', 0, 'rating')))
            auth = self._extract_mvpd_auth(
                url, video_id, requestor_id, resource, software_statement)
        info.update(self._extract_aen_smil(media_url, video_id, auth))
        info.update({
            'title': title,
            'series': (result.get('series') or {}).get('title'),
            'season_number': int_or_none(result.get('tvSeasonNumber')),
            'episode_number': int_or_none(result.get('tvSeasonEpisodeNumber')),
        })
        return info


class AENetworksIE(AENetworksBaseIE):
    IE_NAME = 'aenetworks'
    IE_DESC = 'A+E Networks: A&E, Lifetime, History.com, FYI Network and History Vault'
    _VALID_URL = AENetworksBaseIE._BASE_URL_REGEX + r'''(?P<id>
        shows/[^/?#]+/season-\d+/episode-\d+|
        (?P<type>movie|special)s/[^/?#]+(?P<extra>/[^/?#]+)?|
        (?:shows/[^/?#]+/)?videos/[^/?#]+
    )'''

    _TESTS = [{
        'url': 'http://www.history.com/shows/mountain-men/season-1/episode-1',
        'info_dict': {
            'id': '22253814',
            'ext': 'mp4',
            'title': 'Winter Is Coming',
            'description': 'md5:a40e370925074260b1c8a633c632c63a',
            'timestamp': 1338306241,
            'upload_date': '20120529',
            'uploader': 'AENE-NEW',
            'duration': 2592.0,
            'thumbnail': r're:https?://.+/.+\.jpg',

Review comment (suggestion):
```suggestion
            **traverse_obj(result, {
                'series': ('series', 'title', {str}),
                'season_number': ('tvSeasonNumber', {int_or_none}),
                'episode_number': ('tvSeasonEpisodeNumber', {int_or_none}),
            }),
```

Code after:
        return {
            'id': video_id,
            'formats': formats,
            'subtitles': subtitles,
        }

    def _extract_aetn_info(self, domain, filter_key, filter_value, url):
        requestor_id, brand, software_statement = self._DOMAIN_MAP[domain]
        if filter_key == 'canonical':
            webpage = self._download_webpage(url, filter_value)
            graphql_video_id = self._search_regex(
                r'<meta\b[^>]+\bcontent="[^"]*\btpid/(\d+)"', webpage,
                'id') or self._html_search_meta('videoId', webpage, 'GraphQL video ID', fatal=True)
        else:
            graphql_video_id = filter_value

        result = self._download_json(
            'https://yoga.appsvcs.aetnd.com/', graphql_video_id,
            query={
                'brand': brand,
                'mode': 'live',
                'platform': 'web',
            },
            data=json.dumps({
                'operationName': 'getUserVideo',
                'variables': {
                    'videoId': graphql_video_id,
                },
                'query': self._GRAPHQL_QUERY,
            }).encode(),
            headers={
                'Content-Type': 'application/json',
            })

        result = traverse_obj(result, ('data', 'video', {dict}))
        media_url = traverse_obj(result, ('publicUrl', {url_or_none}))
        if not media_url:
            raise ExtractorError('Show not found in A&E feed (too new?)', expected=True,
                                 video_id=remove_start(filter_value, '/'))
        title = result['title']
        video_id = result['programId']
        theplatform_metadata = self._download_theplatform_metadata(self._search_regex(
            r'https?://link\.theplatform\.com/s/([^?]+)', media_url, 'theplatform_path'), video_id)
        info = self._parse_theplatform_metadata(theplatform_metadata)
        auth = None
        if theplatform_metadata.get('AETN$isBehindWall'):
            resource = self._get_mvpd_resource(
                requestor_id, theplatform_metadata['title'],
                theplatform_metadata.get('AETN$PPL_pplProgramId') or theplatform_metadata.get('AETN$PPL_pplProgramId_OLD'),
                traverse_obj(theplatform_metadata, ('ratings', 0, 'rating')))
            auth = self._extract_mvpd_auth(