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

Code before:
        }
    }, {
        # news
        'url': 'https://www.nhk.or.jp/radio/player/ondemand.html?p=F261_01_3855109',
        'skip': 'Expires on 2023-04-17',
        'info_dict': {
            'id': 'F261_01_3855109',
            'ext': 'm4a',
            'channel': 'NHKラジオ第1',
            'uploader': 'NHKラジオ第1',
            'timestamp': 1681635900,
            'release_date': '20230416',
            'series': 'NHKラジオニュース',
            'title': '午後６時のNHKニュース',
            'thumbnail': 'https://www.nhk.or.jp/radioondemand/json/F261/img/RADIONEWS_640.jpg',
            'upload_date': '20230416',
            'release_timestamp': 1681635600,
        },
    }]

    _api_config = None

    def _extract_extended_description(self, episode_id, aa_vinfo2, aa_vinfo3):
        service, area = aa_vinfo2.split(",")

        if not self._api_config:
            self._api_config = self._download_xml('https://www.nhk.or.jp/radio/config/config_web.xml',
                                                  episode_id, 'Downloading API information', fatal=False)

        full_meta = self._download_json(f'https:{self._api_config.find(".//url_program_detail").text}'.format(
                                        service=service, area=area, dateid=aa_vinfo3),
                                        episode_id, note='Downloading extended metadata', fatal=False)
        if not full_meta:
            return
        return join_nonempty("subtitle", "content", "act", "music", delim="\n\n",
                             from_dict=traverse_obj(full_meta, ('list', service, 0)))

    def _extract_episode_info(self, headline, programme_id, series_meta):
        episode_id = f'{programme_id}_{headline["headline_id"]}'
        episode = traverse_obj(headline, ('file_list', 0, {dict}))
        description = self._extract_extended_description(episode_id, episode.get("aa_vinfo2"),
                                                         episode.get("aa_vinfo3"))
        if not description:
            self.report_warning("Couldn't get extended description, falling back to summary")
            description = episode.get("file_title_sub")

        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

Review comment (suggestion):
checking truthiness of an etree element is no longer supported in py3.12 so we have to do this bit of cringe
```suggestion
        if not isinstance(self._api_config, xml.etree.ElementTree.Element):
```
&nbsp;
and then above
```py
import xml.etree.ElementTree
```

Code after:
        },
        'expected_warnings': ['Unable to download JSON metadata', 'Failed to get extended description'],
    }, {
        # news
        'url': 'https://www.nhk.or.jp/radio/player/ondemand.html?p=F261_01_3855109',
        'skip': 'Expires on 2023-04-17',
        'info_dict': {
            'id': 'F261_01_3855109',
            'ext': 'm4a',
            'channel': 'NHKラジオ第1',
            'uploader': 'NHKラジオ第1',
            'timestamp': 1681635900,
            'release_date': '20230416',
            'series': 'NHKラジオニュース',
            'title': '午後６時のNHKニュース',
            'thumbnail': 'https://www.nhk.or.jp/radioondemand/json/F261/img/RADIONEWS_640.jpg',
            'upload_date': '20230416',
            'release_timestamp': 1681635600,
        },
    }]

    _API_URL_TMPL = None

    def _extract_extended_description(self, episode_id, episode):
        service, _, area = traverse_obj(episode, ('aa_vinfo2', {str}, {lambda x: (x or '').partition(',')}))
        aa_vinfo3 = traverse_obj(episode, ('aa_vinfo3', {str}))
        detail_url = try_call(
            lambda: self._API_URL_TMPL.format(service=service, area=area, dateid=aa_vinfo3))
        if not detail_url:
            return

        full_meta = traverse_obj(
            self._download_json(detail_url, episode_id, 'Downloading extended metadata', fatal=False),
            ('list', service, 0, {dict})) or {}
        return join_nonempty('subtitle', 'content', 'act', 'music', delim='\n\n', from_dict=full_meta)

    def _extract_episode_info(self, headline, programme_id, series_meta):
        episode_id = f'{programme_id}_{headline["headline_id"]}'
        episode = traverse_obj(headline, ('file_list', 0, {dict}))
        description = self._extract_extended_description(episode_id, episode)
        if not description:
            self.report_warning('Failed to get extended description, falling back to summary')
            description = traverse_obj(episode, ('file_title_sub', {str}))

        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'),