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

Code before:
        # fallback when extended metadata fails
        'url': 'https://www.nhk.or.jp/radio/player/ondemand.html?p=J8792PY43V_14_4177121',
        'skip': 'Expires on 2025-04-14',
        'info_dict': {
            'id': 'J8792PY43V_14_4177121',
            'ext': 'm4a',
            'title': '「白い蝶［ちょう］を探してみよう」いきもの☆いろいろ',
            'description': '海野 和男（昆虫写真家）',
            'uploader': 'NHK R1',
            'channel': 'NHK R1',
            'thumbnail': 'https://www.nhk.or.jp/radioondemand/json/J8792PY43V/img/corner/box_26_thumbnail.jpg',
            'series': 'マイあさ！ いきもの☆いろいろ',
            'series_id': 'J8792PY43V_14',
            'timestamp': 1741985700,
            'upload_date': '20250314',
            'release_timestamp': 1741982400,
            'release_date': '20250314',
        },
        'expected_warnings': ['Failed to download extended metadata: HTTP Error 404: Not Found'],
    }]

    _API_URL_TMPL = None

    # the following few functions are ported from https://www.nhk.or.jp/radio/assets/js/timetable_detail_new.js

    def _format_actlist(self, act_list):
        role_groups = {}
        for act in act_list:
            role = act.get('role')
            if role not in role_groups:
                role_groups[role] = []
            role_groups[role].append(act)

        formatted_roles = []
        for role, acts in role_groups.items():
            for i, act in enumerate(acts):
                res = f'【{role}】' if i == 0 and role is not None else ''
                if title := act.get('title'):
                    res += f'{title}…'
                res += act.get('name')
                formatted_roles.append(res)
        return join_nonempty(*formatted_roles, delim='，')

    def _fetch_artists(self, by_artist):
        if not by_artist or len(by_artist) == 0:
            return None
        artists = []
        for artist in by_artist:
            res = ''

            name = artist.get('name')

Review comment (suggestion):
more readable with the underscore IMO
```suggestion
    def _format_act_list(self, act_list):
```

Code after:
    }, {
        # fallback when extended metadata fails
        'url': 'https://www.nhk.or.jp/radio/player/ondemand.html?p=J8792PY43V_20_4253945',
        'skip': 'Expires on 2025-09-01',
        'info_dict': {
            'id': 'J8792PY43V_20_4253945',
            'ext': 'm4a',
            'title': '「後絶たない筋肉増強剤の使用」ワールドリポート',
            'description': '大濱 敦（ソウル支局）',
            'uploader': 'NHK R1',
            'channel': 'NHK R1',
            'thumbnail': 'https://www.nhk.or.jp/radioondemand/json/J8792PY43V/img/corner/box_31_thumbnail.jpg',
            'series': 'マイあさ！ ワールドリポート',
            'series_id': 'J8792PY43V_20',
            'timestamp': 1751837100,
            'upload_date': '20250706',
            'release_timestamp': 1751835600,
            'release_date': '20250706',

        },
        'expected_warnings': ['Failed to download extended metadata: HTTP Error 404: Not Found'],
    }]

    _API_URL_TMPL = None

    # The `_format_*` and `_make_*` functions are ported from: https://www.nhk.or.jp/radio/assets/js/timetable_detail_new.js

    def _format_act_list(self, act_list):
        role_groups = {}
        for act in traverse_obj(act_list, (..., {dict})):
            role = act.get('role')
            if role not in role_groups:
                role_groups[role] = []
            role_groups[role].append(act)

        formatted_roles = []
        for role, acts in role_groups.items():
            for i, act in enumerate(acts):
                res = f'【{role}】' if i == 0 and role is not None else ''
                if title := act.get('title'):
                    res += f'{title}…'
                formatted_roles.append(join_nonempty(res, act.get('name'), delim=''))
        return join_nonempty(*formatted_roles, delim='，')

    def _make_artists(self, track, key):
        artists = []
        for artist in traverse_obj(track, (key, ..., {dict})):
            if res := join_nonempty(*traverse_obj(artist, ((
                ('role', filter, {'{}…'.format}),
                ('part', filter, {'（{}）'.format}),
                ('name', filter),