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

Code before:
        },
    }]

    def _download_api_json(self, video_id):
        api_url = f'https://www.cbc.ca/listen/api/v1/clips/{video_id}'
        raw = self._download_webpage(api_url, video_id,
                                     note='Downloading episode JSON')
        api_json = self._parse_json(raw, video_id)

        return api_json.get('data')

    def _extract_webpage_data(self, url, video_id):
        webpage = self._download_webpage(url, video_id)
        preloaded_state = self._search_json(
            r'window\.__PRELOADED_STATE__\s*=', webpage, 'preloaded state',
            video_id, transform_source=js_to_json)

        show_data = traverse_obj(preloaded_state, (
            ['podcastDetailData', 'showDetailData'], ..., {dict}, any))

        return traverse_obj(show_data, (
            'episodes', lambda _, v: str(v['clipID']) == video_id, any, {require('episode data')}))

    def _real_extract(self, url):
        video_id = self._match_id(url)
        data = self._extract_webpage_data(url, video_id)

        if not data:
            self.to_screen('Unable to extract data from webpage. Trying public api.')
            data = self._download_api_json(video_id)

            if not data:
                raise ExtractorError('Unable to extract urls', expected=True)

        formats = [{
            'url': data.get('url') or data.get('src'),
        }]

        return {
            'id': video_id,
            'title': data.get('title'),
            'description': data.get('description'),
            'timestamp': data.get('releasedAt'),
            'formats': formats,
            'duration': data.get('duration'),
            'webpage_url': url,
        }


Review comment (refactor):
I'd prioritize the api extraction
```suggestion
        data = traverse_obj(self._download_json(
            f'https://www.cbc.ca/listen/api/v1/clips/{video_id}', video_id), 'data', {dict})
```

Code after:
        },
    }]

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

        response = self._download_json(
            f'https://www.cbc.ca/listen/api/v1/clips/{video_id}', video_id, fatal=False)
        data = traverse_obj(response, ('data', {dict}))
        if not data:
            self.report_warning('API failed to return data. Falling back to webpage parsing')
            webpage = self._download_webpage(url, video_id)
            preloaded_state = self._search_json(
                r'window\.__PRELOADED_STATE__\s*=', webpage, 'preloaded state',
                video_id, transform_source=js_to_json)
            data = traverse_obj(preloaded_state, (
                ('podcastDetailData', 'showDetailData'), ..., 'episodes',
                lambda _, v: str(v['clipID']) == video_id, any, {require('episode data')}))

        return {
            'id': video_id,
            **traverse_obj(data, {
                'url': (('src', 'url'), {url_or_none}, any),
                'title': ('title', {str}),
                'description': ('description', {str}),
                'release_timestamp': ('releasedAt', {int_or_none(scale=1000)}),
                'timestamp': ('airdate', {int_or_none(scale=1000)}),
                'duration': ('duration', {int_or_none}),
            }),
        }