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

Code before:
        'url': 'https://tunein.com/podcasts/World-News/BBC-News-p14/',
        'info_dict': {
            'id': 'p14',
            'title': 'BBC News',
        },
        'playlist_mincount': 35,
    }]

    @classmethod
    def suitable(cls, url):
        return False if TuneInPodcastEpisodeIE.suitable(url) else super().suitable(url)

    def _fetch_page(self, url, podcast_id, page=0):
        items = self._call_api(
            podcast_id, 'contents', f'Downloading page {page + 1}', query={
                'filter': 't:free',
                'limit': self._PAGE_SIZE,
                'offset': page * self._PAGE_SIZE,
            },
        )['Items']

        if items:
            for item in traverse_obj(items, (
                ..., 'GuideId', {str}, filter, all, filter,
            )):
                yield self.url_result(update_url_query(url, {'topicId': item[1:]}))

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

        return self.playlist_result(OnDemandPagedList(
            functools.partial(self._fetch_page, url, podcast_id), self._PAGE_SIZE),
            podcast_id, traverse_obj(self._call_api(podcast_id), ('Item', 'Title', {str})))


class TuneInPodcastEpisodeIE(TuneInBaseIE):
    IE_NAME = 'tunein:podcast'
    _VALID_URL = r'https?://tunein\.com/podcasts(?:/[^/?#]+){1,2}(?P<series_id>p\d+)/?\?(?:[^#]+&)?(?i:topicid)=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://tunein.com/podcasts/Technology-Podcasts/Artificial-Intelligence-p1153019/?topicId=236404354',
        'info_dict': {
            'id': 't236404354',
            'ext': 'mp3',
            'title': '#351 – MrBeast: Future of YouTube, Twitter, TikTok, and Instagram',
            'alt_title': 'Technology Podcasts >',
            'cast': 'count:1',
            'description': 'md5:1029895354ef073ff00f20b82eb6eb71',
            'display_id': '236404354',
            'duration': 8330,
            'thumbnail': r're:https?://.+',
            'timestamp': 1673458571,

Review comment (suggestion):
```suggestion
        for item in traverse_obj(items, (..., 'GuideId', {str}, filter)):
            yield self.url_result(update_url_query(url, {'topicId': item[1:]}))
```

Code after:
        'url': 'https://tunein.com/podcasts/World-News/BBC-News-p14/',
        'info_dict': {
            'id': 'p14',
            'title': 'BBC News',
        },
        'playlist_mincount': 35,
    }]

    @classmethod
    def suitable(cls, url):
        return False if TuneInPodcastEpisodeIE.suitable(url) else super().suitable(url)

    def _fetch_page(self, url, podcast_id, page=0):
        items = self._call_api(
            podcast_id, 'contents', f'Downloading page {page + 1}', query={
                'filter': 't:free',
                'limit': self._PAGE_SIZE,
                'offset': page * self._PAGE_SIZE,
            },
        )['Items']

        for item in traverse_obj(items, (..., 'GuideId', {str}, filter)):
            yield self.url_result(update_url_query(url, {'topicId': item[1:]}))

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

        return self.playlist_result(OnDemandPagedList(
            functools.partial(self._fetch_page, url, podcast_id), self._PAGE_SIZE),
            podcast_id, traverse_obj(self._call_api(podcast_id), ('Item', 'Title', {str})))


class TuneInPodcastEpisodeIE(TuneInBaseIE):
    IE_NAME = 'tunein:podcast'
    _VALID_URL = r'https?://tunein\.com/podcasts(?:/[^/?#]+){1,2}(?P<series_id>p\d+)/?\?(?:[^#]+&)?(?i:topicid)=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://tunein.com/podcasts/Technology-Podcasts/Artificial-Intelligence-p1153019/?topicId=236404354',
        'info_dict': {
            'id': 't236404354',
            'ext': 'mp3',
            'title': '#351 – MrBeast: Future of YouTube, Twitter, TikTok, and Instagram',
            'alt_title': 'Technology Podcasts >',
            'cast': 'count:1',
            'description': 'md5:1029895354ef073ff00f20b82eb6eb71',
            'display_id': '236404354',
            'duration': 8330,
            'thumbnail': r're:https?://.+',
            'timestamp': 1673458571,
            'upload_date': '20230111',
            'series': 'Lex Fridman Podcast',
            'series_id': 'p1153019',