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

Code before:

        about = response.get('about')
        thumbnails = []
        thumbnails.extend(self._get_thumbnails(traverse_obj(about, ('eyecatch', {dict.items})), ''))
        if eyecatch_list := about.get('eyecatchList'):
            for num, v in enumerate(eyecatch_list):
                thumbnails.extend(self._get_thumbnails(v.items(), join_nonempty('list', num), preference=-2))
        thumbnails.extend(self._get_thumbnails(traverse_obj(about, ('partOfSeries', 'eyecatch', {dict.items})), 'series', preference=-3))

        return filter_dict({
            'description': self._format_description(response),
            'cast': traverse_obj(response, ('misc', 'actList', ..., 'name')),
            'thumbnails': thumbnails,
            **traverse_obj(response, {
                'title': ('name', {str}),
                'timestamp': ('endDate', {unified_timestamp}),
                'release_timestamp': ('startDate', {unified_timestamp}),
                'duration': ('duration', {parse_duration}),
            }),
            **traverse_obj(response, ('identifierGroup', {
                'series': 'radioSeriesName',
                'series_id': 'radioSeriesId',
                'episode': 'radioEpisodeName',
                'episode_id': 'radioEpisodeId',
                'categories': ('genre', ..., ['name1', 'name2'], all, {orderedSet}),
            })),
            'channel': station,
            'uploader': station,
        })

    def _extract_episode_info(self, episode, programme_id, series_meta):
        episode_id = f'{programme_id}_{episode["id"]}'
        aa_vinfo = traverse_obj(episode, ('aa_contents_id', {lambda x: x.split(';')}))
        extended_metadata = self._extract_extended_metadata(episode_id, aa_vinfo)
        fallback_start_time, _, fallback_end_time = traverse_obj(
            aa_vinfo, (4, {str}, {lambda x: (x or '').partition('_')}))

        return {
            **series_meta,
            'id': episode_id,
            'formats': self._extract_m3u8_formats(episode.get('stream_url'), episode_id, fatal=False),
            'container': 'm4a_dash',  # force fixup, AAC-only HLS
            'was_live': True,
            'title': episode.get('program_title'),
            'description': episode.get('program_sub_title'),  # fallback
            'timestamp': unified_timestamp(fallback_end_time),
            'release_timestamp': unified_timestamp(fallback_start_time),
            **extended_metadata,
        }

    def _extract_news_info(self, headline, programme_id, series_meta):

Review comment (suggestion):
```suggestion
            **traverse_obj(response, ('identifierGroup', {
                'series': ('radioSeriesName', {str})
                'series_id': ('radioSeriesId', {str})
                'episode': ('radioEpisodeName', {str})
                'episode_id': ('radioEpisodeId', {str})
                'categories': ('genre', ..., ['name1', 'name2'], {str}, all, {orderedSet}),
            })),
```

Code after:
            }),
            **traverse_obj(response, ('identifierGroup', {
                'series': ('radioSeriesName', {str}),
                'series_id': ('radioSeriesId', {str}),
                'episode': ('radioEpisodeName', {str}),
                'episode_id': ('radioEpisodeId', {str}),
                'categories': ('genre', ..., ['name1', 'name2'], {str}, all, {orderedSet}),
            })),
            'channel': station,
            'uploader': station,
        })

    def _extract_episode_info(self, episode, programme_id, series_meta):
        episode_id = f'{programme_id}_{episode["id"]}'
        aa_vinfo = traverse_obj(episode, ('aa_contents_id', {lambda x: x.split(';')}))
        extended_metadata = self._extract_extended_metadata(episode_id, aa_vinfo)
        fallback_start_time, _, fallback_end_time = traverse_obj(
            aa_vinfo, (4, {str}, {lambda x: (x or '').partition('_')}))

        return {
            **series_meta,
            'id': episode_id,
            'formats': self._extract_m3u8_formats(episode.get('stream_url'), episode_id, fatal=False),
            'container': 'm4a_dash',  # force fixup, AAC-only HLS
            'was_live': True,
            'title': episode.get('program_title'),
            'description': episode.get('program_sub_title'),  # fallback
            'timestamp': unified_timestamp(fallback_end_time),
            'release_timestamp': unified_timestamp(fallback_start_time),
            **extended_metadata,
        }

    def _extract_news_info(self, headline, programme_id, series_meta):
        episode_id = f'{programme_id}_{headline["headline_id"]}'
        episode = traverse_obj(headline, ('file_list', 0, {dict}))

        return {
            **series_meta,
            'id': episode_id,
            'formats': self._extract_m3u8_formats(episode.get('file_name'), episode_id, fatal=False),
            'container': 'm4a_dash',  # force fixup, AAC-only HLS
            'was_live': True,
            'series': series_meta.get('title'),
            'thumbnail': url_or_none(headline.get('headline_image')) or series_meta.get('thumbnail'),
            **traverse_obj(episode, {
                'title': ('file_title', {str}),
                'description': ('file_title_sub', {str}),
                'timestamp': ('open_time', {unified_timestamp}),
                'release_timestamp': ('aa_vinfo4', {lambda x: x.split('_')[0]}, {unified_timestamp}),
            }),
        }