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

Code before:

    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')
            role = artist.get('role')
            part = artist.get('part')

            if role != '':
                res += f'{role}…'
            if part != '':
                res += f'（{part}）'
            res += name

            if res != '':
                artists.append(res)
        if len(artists) == 0:
            return None
        return '、'.join(artists)

    def _fetch_duration(self, duration):
        d = parse_duration(duration)
        if d is None:
            return None
        hours, remainder = divmod(d, 3600)
        minutes, seconds = divmod(remainder, 60)
        res = '（'
        if hours > 0:
            res += f'{int(hours)}時間'
        if minutes > 0:
            res += f'{int(minutes)}分'
        res += f'{int(seconds):02}秒）'
        return res

    def _format_musiclist(self, music_list):
        if not music_list or len(music_list) == 0:
            return None

        tracks = []

        for track in music_list:
            track_details = []

            if name := track.get('name'):
                track_details.append(f'「{name}」')
            if lyricist := track.get('lyricist'):
                track_details.append(f'{lyricist}:作詞')

Review comment (suggestion):
same thing about the method name here, and let's traverse inside the method?
```suggestion
    def _get_duration(self, track, key):
        d = traverse_obj(track, (key, {parse_duration}))
```

Code after:
        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),
            ), {str})), delim=''):
                artists.append(res)

        return '、'.join(artists) or None

    def _make_duration(self, track, key):
        d = traverse_obj(track, (key, {parse_duration}))
        if d is None:
            return None
        hours, remainder = divmod(d, 3600)
        minutes, seconds = divmod(remainder, 60)
        res = '（'
        if hours > 0:
            res += f'{int(hours)}時間'
        if minutes > 0:
            res += f'{int(minutes)}分'
        res += f'{int(seconds):02}秒）'
        return res

    def _format_music_list(self, music_list):
        tracks = []
        for track in traverse_obj(music_list, (..., {dict})):
            track_details = traverse_obj(track, ((
                ('name', filter, {'「{}」'.format}),
                ('lyricist', filter, {'{}:作詞'.format}),
                ('composer', filter, {'{}:作曲'.format}),
                ('arranger', filter, {'{}:編曲'.format}),
            ), {str}))

            track_details.append(self._make_artists(track, 'byArtist'))
            track_details.append(self._make_duration(track, 'duration'))

            if label := join_nonempty('label', 'code', delim=' ', from_dict=track):
                track_details.append(f'＜{label}＞')
            if location := traverse_obj(track, ('location', {str})):
                track_details.append(f'～{location}～')
            tracks.append(join_nonempty(*track_details, delim='\n'))
        return '\n\n'.join(tracks)

    def _format_description(self, response):
        detailed_description = traverse_obj(response, ('detailedDescription', {dict})) or {}
        return join_nonempty(