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

Code before:
        'only_matching': True,
    }]

    _METADATA_KEY = 'documents'

    def _generate_playlist_entries(self, profile_id, profile_response):
        for page_num in itertools.count(2):
            for entry in profile_response['items']:
                yield self.url_result(
                    f'https://www.radiofrance.fr/{entry["path"]}', **traverse_obj(entry, {
                        'title': 'title',
                        'description': 'standFirst',
                        'timestamp': 'publishedDate',
                        'thumbnail': ('visual', 'src'),
                    }))

            next_cursor = profile_response['pagination']['next']
            if not next_cursor:
                break

            profile_response = self._download_json(
                f'https://www.radiofrance.fr/api/v2.1/taxonomy/{profile_id}/documents', profile_id,
                note=f'Downloading page {page_num}', query={
                    'relation': 'personality',
                    'cursor': next_cursor
                })


class RadioFranceProgramScheduleIE(RadioFranceBase):
    _VALID_URL = rf'''(?x)
        {RadioFranceBase._VALID_URL_BASE}
        /(?P<station>{"|".join(RadioFranceBase._STATIONS)})
        /grille-programmes(?:\?date=(?P<date>[\d-]+))?
    '''

    _TESTS = [{
        'url': 'https://www.radiofrance.fr/franceinter/grille-programmes?date=17-02-2023',
        'info_dict': {
            'id': 'franceinter-program-20230217',
            'upload_date': '20230217',
        },
        'playlist_count': 25,
    }, {
        'url': 'https://www.radiofrance.fr/franceculture/grille-programmes?date=01-02-2023',
        'info_dict': {
            'id': 'franceculture-program-20230201',
            'upload_date': '20230201',
        },
        'playlist_count': 25,
    }, {
        'url': 'https://www.radiofrance.fr/mouv/grille-programmes?date=19-03-2023',

Review comment (suggestion):
This is the only part that is different. You could do something like this and move rest to base class:
```py
    def _call_api(self, profile_id, cursor, page_num):
        resp = self._download_json(...)
        resp['next'] = traverse_obj(resp, ('pagination', 'next'))
        return resp
```

Code after:
            'display_id': 'thomas-pesquet',
            'title': 'Thomas Pesquet',
            'description': 'Astronaute à l\'agence spatiale européenne',
        },
        'playlist_mincount': 212,
    }, {
        'url': 'https://www.radiofrance.fr/personnes/eugenie-bastie',
        'info_dict': {
            'id': '9593050b-0183-4972-a0b5-d8f699079e02',
            'display_id': 'eugenie-bastie',
            'title': 'Eugénie Bastié',
            'description': 'Journaliste et essayiste',
            'thumbnail': r're:^https?://.*\.(?:jpg|png)',
        },
        'playlist_mincount': 39,
    }, {
        'url': 'https://www.radiofrance.fr/personnes/lea-salame',
        'only_matching': True,
    }]

    _METADATA_KEY = 'documents'

    def _call_api(self, profile_id, cursor, page_num):
        resp = self._download_json(
            f'https://www.radiofrance.fr/api/v2.1/taxonomy/{profile_id}/documents', profile_id,
            note=f'Downloading page {page_num}', query={
                'relation': 'personality',
                'cursor': cursor,
            })

        resp['next'] = traverse_obj(resp, ('pagination', 'next'))
        return resp


class RadioFranceProgramScheduleIE(RadioFranceBaseIE):
    _VALID_URL = rf'''(?x)
        {RadioFranceBaseIE._VALID_URL_BASE}
        /(?P<station>{RadioFranceBaseIE._STATIONS_RE})
        /grille-programmes(?:\?date=(?P<date>[\d-]+))?
    '''

    _TESTS = [{
        'url': 'https://www.radiofrance.fr/franceinter/grille-programmes?date=17-02-2023',
        'info_dict': {
            'id': 'franceinter-program-20230217',
            'upload_date': '20230217',
        },
        'playlist_count': 25,
    }, {
        'url': 'https://www.radiofrance.fr/franceculture/grille-programmes?date=01-02-2023',
        'info_dict': {