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

Code before:
        info['title'] = file.get('file_title')
        info['description'] = file.get('file_title_sub')
        # info['webpage_url'] = file.get('share_url')
        info['thumbnail'] = headline.get('headline_image')
        info['container'] = 'm4a_dash'  # force fixup so seeking works
        info['was_live'] = True  # it's radio catch-up

        aa_vinfo4 = file.get('aa_vinfo4')
        # have to use whatever this is to get an actual air date
        # there is an onair_date var, but it's natural language that doesnt have half of what we need anyway
        info['release_timestamp'] = self._decode_time(aa_vinfo4.split('_')[0])
        # open_time is when it was put on vod
        info['timestamp'] = self._decode_time(file.get('open_time'))

        return info

    def _real_extract(self, url):
        video_id, site_id, corner_id, headline_id = self._match_valid_url(url).groups()

        programme_id = f'{site_id}_{corner_id}'
        json_url = f'https://www.nhk.or.jp/radioondemand/json/{site_id}/bangumi_{programme_id}.json'
        meta = self._download_json(json_url, programme_id)['main']

        series = meta.get('program_name')
        channel = meta.get('media_name')
        thumbnail = meta.get('thumbnail_c') or meta.get('thumbnail_p')

        detail_list = meta.get('detail_list')

        result = None

        # if it's 0123_45_6789 - a specific episode (as opposed to 0123_45 - the whole programme)
        if headline_id is not None:
            # we are downloading a single episode
            headline = (next((i for i in detail_list if i.get('headline_id') == headline_id), None))
            result = self._extract_episode_info(headline, programme_id)
            result['series'] = series
            result['channel'] = channel
            result['thumbnail'] = result.get('thumbnail') or thumbnail
        else:
            # we are downloading a whole playlist/show
            series_description = meta.get('site_detail')
            # series_url = meta.get('share_url')
            result = {
                '_type': 'playlist',
                'channel': channel,
                'thumbnail': thumbnail,
                'title': series,
                'description': series_description,
                # 'webpage_url': series_url,
                'id': video_id,

Review comment (refactor):
A dict will be easier to pass around. We can pass it to `_extract_episode_info` and let that method handle the info_dict update for single episodes and playlist entries, and also pass it to the playlist result
```suggestion
        series_meta = traverse_obj(meta, {
            'title': 'program_name',
            'channel': 'media_name',
            'thumbnail': (('thumbnail_c', 'thumbnail_p'), {url_or_none}),
        }, get_all=False)
```

Code after:
            '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',
                'description': 'file_title_sub',
                'timestamp': ('open_time', {unified_timestamp}),
                'release_timestamp': ('aa_vinfo4', {lambda x: x.split('_')[0]}, {unified_timestamp}),
            }),
        }

    def _real_extract(self, url):
        site_id, corner_id, headline_id = self._match_valid_url(url).group('site', 'corner', 'headline')
        programme_id = f'{site_id}_{corner_id}'

        if site_id == 'F261':
            json_url = 'https://www.nhk.or.jp/s-media/news/news-site/list/v1/all.json'
        else:
            json_url = f'https://www.nhk.or.jp/radioondemand/json/{site_id}/bangumi_{programme_id}.json'

        meta = self._download_json(json_url, programme_id)['main']

        series_meta = traverse_obj(meta, {
            'title': 'program_name',
            'channel': 'media_name',
            'thumbnail': (('thumbnail_c', 'thumbnail_p'), {url_or_none}),
        }, get_all=False)

        if headline_id:
            return self._extract_episode_info(
                traverse_obj(meta, (
                    'detail_list', lambda _, v: v['headline_id'] == headline_id), get_all=False),
                programme_id, series_meta)

        def entries():
            for headline in traverse_obj(meta, ('detail_list', ..., {dict})):
                yield self._extract_episode_info(headline, programme_id, series_meta)

        return self.playlist_result(
            entries(), programme_id, playlist_description=meta.get('site_detail'), **series_meta)


class NhkRadioNewsPageIE(InfoExtractor):
    _VALID_URL = r'https?://www\.nhk\.or\.jp/radionews/?(?:$|[?#])'
    _TESTS = [{
        # airs daily, on-the-hour most hours
        'url': 'https://www.nhk.or.jp/radionews/',
        'playlist_mincount': 5,
        'info_dict': {
            'id': 'F261_01',