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

Code before:
        track_id = self._match_id(url)
        track_info = self._download_json(
            f'https://api.idagio.com/v2.0/metadata/tracks/{track_id}', track_id, fatal=False)

        content_info = self._download_json(
            f'https://api.idagio.com/v1.8/content/track/{track_id}', track_id,
            query={
                'quality': '0',
                'format': '2',
                'client_type': 'web-4',
            })

        return {
            'ext': 'mp3',
            'vcodec': 'none',
            'id': track_id,
            'url': traverse_obj(content_info, ('url', {url_or_none})),
            **traverse_obj(track_info, ('result', {
                'title': ('piece', 'title', {str}),
                'timestamp': ('recording', 'created_at', {int_or_none(scale=1000)}),
                'location': ('recording', 'location', {str}),
                'duration': ('duration', {int_or_none}),
                'track': ('piece', 'title', {str}),
                'artists': ('recording', ('conductor', ('ensembles', ...), ('soloists', ...)), 'name', {str}, all),
                'composers': ('piece', 'workpart', 'work', 'composer', 'name', {str}, all),
                'genres': ('piece', 'workpart', 'work', ('genre', 'subgenre'), 'title', {str}, all),
            })),
        }


class IdagioRecordingIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/(?P<id>\d+)(?![^#]*[&?]trackId=\d+)'
    _TESTS = [{
        'url': 'https://app.idagio.com/recordings/30576934',
        'info_dict': {
            'id': '30576934',
            'title': 'Variations on an Original Theme op. 36',
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'timestamp': 1554474370,
            'modified_timestamp': 1554474370,
            'modified_date': '20190405',
            'upload_date': '20190405',
        },
        'playlist_count': 15,
    }]

    def _real_extract(self, url):
        recording_id = self._match_id(url)
        recording_info = self._download_json(f'https://api.idagio.com/v2.0/metadata/recordings/{recording_id}',

Review comment (suggestion):
```suggestion
                'artists': ('recording', ('conductor', ('ensembles', ...), ('soloists', ...)), 'name', {str}, filter),
                'composers': ('piece', 'workpart', 'work', 'composer', 'name', {str}, filter, all, filter),
                'genres': ('piece', 'workpart', 'work', ('genre', 'subgenre'), 'title', {str}, filter),
```

Code after:
    def _real_extract(self, url):
        track_id = self._match_id(url)
        track_info = self._download_json(
            f'https://api.idagio.com/v2.0/metadata/tracks/{track_id}',
            track_id, fatal=False, expected_status=406)
        if traverse_obj(track_info, 'error_code') == 'idagio.error.blocked.location':
            self.raise_geo_restricted()

        content_info = self._download_json(
            f'https://api.idagio.com/v1.8/content/track/{track_id}', track_id,
            query={
                'quality': '0',
                'format': '2',
                'client_type': 'web-4',
            })

        return {
            'ext': 'mp3',
            'vcodec': 'none',
            'id': track_id,
            'url': traverse_obj(content_info, ('url', {url_or_none})),
            **traverse_obj(track_info, ('result', {
                'title': ('piece', 'title', {str}),
                'timestamp': ('recording', 'created_at', {int_or_none(scale=1000)}),
                'location': ('recording', 'location', {str}),
                'duration': ('duration', {int_or_none}),
                'track': ('piece', 'title', {str}),
                'artists': ('recording', ('conductor', ('ensembles', ...), ('soloists', ...)), 'name', {str}, filter),
                'composers': ('piece', 'workpart', 'work', 'composer', 'name', {str}, filter, all, filter),
                'genres': ('piece', 'workpart', 'work', ('genre', 'subgenre'), 'title', {str}, filter),
            })),
        }


class IdagioPlaylistBaseIE(InfoExtractor):
    """Subclasses must set _API_URL_TMPL and define _parse_playlist_metadata"""
    _PLAYLIST_ID_KEY = 'id'  # vs. 'display_id'

    def _entries(self, playlist_info):
        for track_data in traverse_obj(playlist_info, ('tracks', lambda _, v: v['id'] and v['recording']['id'])):
            track_id = track_data['id']
            recording_id = track_data['recording']['id']
            yield self.url_result(
                f'https://app.idagio.com/recordings/{recording_id}?trackId={track_id}',
                ie=IdagioTrackIE, video_id=track_id)

    def _real_extract(self, url):
        playlist_id = self._match_id(url)
        playlist_info = self._download_json(
            self._API_URL_TMPL.format(playlist_id), playlist_id)['result']