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

Code before:
    def _real_extract(self, url):
        program_id = self._match_id(url)

        webpage = self._download_webpage(f'https://www.nhk.or.jp/school/{program_id}/', program_id)

        title = (self._generic_title('', webpage)
                 or self._html_search_regex(r'<h3>([^<]+?)とは？\s*</h3>', webpage, 'title', fatal=False))
        title = re.sub(r'\s*\|\s*NHK\s+for\s+School\s*$', '', title) if title else None
        description = self._html_search_regex(
            r'(?s)<div\s+class="programDetail\s*">\s*<p>[^<]+</p>',
            webpage, 'description', fatal=False, group=0)

        bangumi_list = self._download_json(
            f'https://www.nhk.or.jp/school/{program_id}/meta/program.json', program_id)
        # they're always bangumi
        bangumis = [
            self.url_result(f'https://www2.nhk.or.jp/school/movie/bangumi.cgi?das_id={x}')
            for x in traverse_obj(bangumi_list, ('part', ..., 'part-video-dasid')) or []]

        return self.playlist_result(bangumis, program_id, title, description)


class NhkRadiruIE(InfoExtractor):
    _GEO_COUNTRIES = ['JP']
    IE_DESC = 'NHK らじる (Radiru/Rajiru)'
    _VALID_URL = r'https://www\.nhk\.or\.jp/radio/(?:player/ondemand|ondemand/detail)\.html\?p=(?P<id>(?P<site>[\da-zA-Z]+)_(?P<corner>[\da-zA-Z]+)(?:_(?P<headline>[\da-zA-Z]+))?)'
    # match https://www.nhk.or.jp/radio/player/ondemand.html (player) or https://www.nhk.or.jp/radio/ondemand/detail.html (programme page)
    # then grab contents of p and split the numbers up into what they are in the api
    _TESTS = [{
        'url': 'https://www.nhk.or.jp/radio/player/ondemand.html?p=0449_01_3853544',
        'skip': 'Episode expired on 2023-04-16',
        '_type': 'video',
        'info_dict': {
            'channel': 'NHK-FM',
            'description': '今回の前半は「ＮＥＷジャズ」特集と題して、曲名や演奏者の名前に「ＮＥＷ」がつく演奏や、新人の初リーダー作などを集めて聴いていく。',
            'ext': 'm4a',
            'id': '0449_01_3853544',
            'series': 'ジャズ・トゥナイト',
            'thumbnail': 'https://www.nhk.or.jp/prog/img/449/g449.jpg',
            'timestamp': 1680969600,
            'title': 'ジャズ・トゥナイト　ＮＥＷジャズ特集',
            'upload_date': '20230408',
            'release_timestamp': 1680962400,
            'release_date': '20230408',
            'was_live': True,
        },
    }, {
        'url': 'https://www.nhk.or.jp/radio/ondemand/detail.html?p=0458_01',
        '_type': 'playlist',
        'info_dict': {
            'id': '0458_01',

Review comment (suggestion):
- accept `http` URLs
- `id` group is not useful since its value is only used for playlists and we are constructing our own equivalent `programme_id` below
```suggestion
    _VALID_URL = r'https?://www\.nhk\.or\.jp/radio/(?:player/ondemand|ondemand/detail)\.html\?p=(?P<site>[\da-zA-Z]+)_(?P<corner>[\da-zA-Z]+)(?:_(?P<headline>[\da-zA-Z]+))?'
```

Code after:
    def _real_extract(self, url):
        program_id = self._match_id(url)

        webpage = self._download_webpage(f'https://www.nhk.or.jp/school/{program_id}/', program_id)

        title = (self._generic_title('', webpage)
                 or self._html_search_regex(r'<h3>([^<]+?)とは？\s*</h3>', webpage, 'title', fatal=False))
        title = re.sub(r'\s*\|\s*NHK\s+for\s+School\s*$', '', title) if title else None
        description = self._html_search_regex(
            r'(?s)<div\s+class="programDetail\s*">\s*<p>[^<]+</p>',
            webpage, 'description', fatal=False, group=0)

        bangumi_list = self._download_json(
            f'https://www.nhk.or.jp/school/{program_id}/meta/program.json', program_id)
        # they're always bangumi
        bangumis = [
            self.url_result(f'https://www2.nhk.or.jp/school/movie/bangumi.cgi?das_id={x}')
            for x in traverse_obj(bangumi_list, ('part', ..., 'part-video-dasid')) or []]

        return self.playlist_result(bangumis, program_id, title, description)


class NhkRadiruIE(InfoExtractor):
    _GEO_COUNTRIES = ['JP']
    IE_DESC = 'NHK らじる (Radiru/Rajiru)'
    _VALID_URL = r'https?://www\.nhk\.or\.jp/radio/(?:player/ondemand|ondemand/detail)\.html\?p=(?P<site>[\da-zA-Z]+)_(?P<corner>[\da-zA-Z]+)(?:_(?P<headline>[\da-zA-Z]+))?'
    _TESTS = [{
        'url': 'https://www.nhk.or.jp/radio/player/ondemand.html?p=0449_01_3853544',
        'skip': 'Episode expired on 2023-04-16',
        'info_dict': {
            'channel': 'NHK-FM',
            'description': 'md5:94b08bdeadde81a97df4ec882acce3e9',
            'ext': 'm4a',
            'id': '0449_01_3853544',
            'series': 'ジャズ・トゥナイト',
            'thumbnail': 'https://www.nhk.or.jp/prog/img/449/g449.jpg',
            'timestamp': 1680969600,
            'title': 'ジャズ・トゥナイト　ＮＥＷジャズ特集',
            'upload_date': '20230408',
            'release_timestamp': 1680962400,
            'release_date': '20230408',
            'was_live': True,
        },
    }, {
        # playlist, airs every weekday so it should _hopefully_ be okay forever
        'url': 'https://www.nhk.or.jp/radio/ondemand/detail.html?p=0458_01',
        'info_dict': {
            'id': '0458_01',
            'title': 'ベストオブクラシック',
            'description': '世界中の上質な演奏会をじっくり堪能する本格派クラシック番組。',
            'channel': 'NHK-FM',