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

Code before:
            'duration': int_or_none(t.get('duration')),
            'timestamp': unified_timestamp(content.get('editorialDate')),
            'thumbnails': thumbnails,
            'chapters': chapters or None,
            'episode': title,
            **traverse_obj(content, ('programmeItem', 0, 'http://zdf.de/rels/target', {
                'series_id': ('http://zdf.de/rels/cmdm/series', 'seriesUuid'),
                'series': ('http://zdf.de/rels/cmdm/series', 'seriesTitle'),
                'season': ('http://zdf.de/rels/cmdm/season', 'seasonTitle'),
                'season_number': ('http://zdf.de/rels/cmdm/season', 'seasonNumber'),
                'season_id': ('http://zdf.de/rels/cmdm/season', 'seasonUuid'),
                'episode_number': 'episodeNumber',
                'episode_id': 'contentId',
            })),
        })

    def _extract_regular(self, url, player, video_id):
        player_content_v2 = player['content']
        player_content_v3 = update_url_query(player_content_v2, {'profile': 'player-3'})

        content = try_call(
            lambda: self._call_api(player_content_v3, video_id, 'content', player['apiToken'], url),
            lambda: self._call_api(player_content_v2, video_id, 'content', player['apiToken'], url),
        )

        return self._extract_entry(player_content_v2, player, content, video_id)

    def _extract_mobile(self, video_id):
        video = self._download_v2_doc(video_id)

        formats = []
        formitaeten = try_get(video, lambda x: x['document']['formitaeten'], list)
        document = formitaeten and video['document']
        if formitaeten:
            title = document['titel']
            content_id = document['basename']

            format_urls = set()
            for f in formitaeten or []:
                self._extract_format(content_id, formats, format_urls, f)

        thumbnails = []
        teaser_bild = document.get('teaserBild')
        if isinstance(teaser_bild, dict):
            for thumbnail_key, thumbnail in teaser_bild.items():
                thumbnail_url = try_get(
                    thumbnail, lambda x: x['url'], str)
                if thumbnail_url:
                    thumbnails.append({
                        'url': thumbnail_url,
                        'id': thumbnail_key,

Review comment (refactor):
I don't understand the `try_call` usage. It doesn't suppress `ExtractorError`, so the fallback will never be used. I would do this:

```suggestion
        player_url = player['content']

        for query in ({'profile': 'player-3'}, None):
            try:
                content = self._call_api(
                    update_url_query(player_url, query),
                    video_id, 'content', player['apiToken'], url)
            except ExtractorError as e:
                if query is None:
                    raise
                self.report_warning(f'{video_id}: {e.orig_msg}; retrying with v2 profile')

        return self._extract_entry(player_url, player, content, video_id)
```

Code after:
            'thumbnails': thumbnails,
            'chapters': chapters or None,
            'episode': title,
            **traverse_obj(content, ('programmeItem', 0, 'http://zdf.de/rels/target', {
                'series_id': ('http://zdf.de/rels/cmdm/series', 'seriesUuid', {str}),
                'series': ('http://zdf.de/rels/cmdm/series', 'seriesTitle', {str}),
                'season': ('http://zdf.de/rels/cmdm/season', 'seasonTitle', {str}),
                'season_number': ('http://zdf.de/rels/cmdm/season', 'seasonNumber', {int_or_none}),
                'season_id': ('http://zdf.de/rels/cmdm/season', 'seasonUuid', {str}),
                'episode_number': ('episodeNumber', {int_or_none}),
                'episode_id': ('contentId', {str}),
            })),
        })

    def _extract_regular(self, url, player, video_id):
        player_url = player['content']

        try:
            content = self._call_api(
                update_url_query(player_url, {'profile': 'player-3'}),
                video_id, 'content', player['apiToken'], url)
        except ExtractorError as e:
            self.report_warning(f'{video_id}: {e.orig_msg}; retrying with v2 profile')
            content = self._call_api(
                player_url, video_id, 'content', player['apiToken'], url)

        return self._extract_entry(player_url, player, content, video_id)

    def _extract_mobile(self, video_id):
        video = self._download_v2_doc(video_id)

        formats = []
        formitaeten = try_get(video, lambda x: x['document']['formitaeten'], list)
        document = formitaeten and video['document']
        if formitaeten:
            title = document['titel']
            content_id = document['basename']

            format_urls = set()
            for f in formitaeten or []:
                self._extract_format(content_id, formats, format_urls, f)

        thumbnails = []
        teaser_bild = document.get('teaserBild')
        if isinstance(teaser_bild, dict):
            for thumbnail_key, thumbnail in teaser_bild.items():
                thumbnail_url = try_get(
                    thumbnail, lambda x: x['url'], str)
                if thumbnail_url:
                    thumbnails.append({
                        'url': thumbnail_url,