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

Code before:
        data = self._search_nextjs_data(webpage, video_id)
        return traverse_obj(data, ('props', 'pageProps'))

    def _request_ext(self, url, video_id):
        urlh = self._request_webpage(url, video_id, note='Determining source extension')
        return urlhandle_detect_ext(urlh)

    def _extract_audio(self, episode, series):
        return {
            'vcodec': 'none',
            **traverse_obj(series, {
                'series': 'title',
                'series_id': 'id',
                'thumbnail': 'imageUrl',
            }),
            **traverse_obj(episode, {
                'id': 'id',
                'description': ('description', {clean_html}),
                'duration': ('duration', {parse_duration}),
                'thumbnail': 'imageUrl',
                'url': 'streamUrl',
                'timestamp': (['pubDate', 'startDate'], {unified_timestamp}),
                # pubDate for podcasts, startDate for radio catchup - that's all we need to have both in one
                'title': 'title',
            }, get_all=False)
        }


class GlobalPlayerLiveIE(GlobalPlayerBaseIE):
    _VALID_URL = r'https?://www\.globalplayer\.com/live/(?P<id>\w+)/\w+/$'
    _TESTS = [{
        'url': 'https://www.globalplayer.com/live/smoothchill/uk/',
        'info_dict': {
            'id': '2mx1E',
            'ext': 'aac',
            'title': str,
            'thumbnail': 'md5:407a54f3a18e54aa0326a399e68a7d50',
            'description': 'Music To Chill To',
            'live_status': 'is_live',
            'display_id': 'smoothchill-uk',
        }}, {
        # national station
        'url': 'https://www.globalplayer.com/live/heart/uk/',
        'info_dict': {
            'id': '2mwx4',
            'ext': 'aac',
            'title': str,
            'thumbnail': 'md5:6f13378a53ce55bcf57365a654e1b490',
            'live_status': 'is_live',
            'description': 'turn up the feel good!',
            'display_id': 'heart-uk',

Review comment (refactor):
edit: see pukkandan's reply, this suggestion is not necessary

`id` and `url` should be fatal; we'll already filter for them before extracting a playlist, and we don't want to return a single ep without id or url
```suggestion
    def _extract_audio(self, episode, series):
        return {
            'id': episode['id'],
            'url': episode['streamUrl'],
            'vcodec': 'none',
            **traverse_obj(series, {
                'series': 'title',
                'series_id': 'id',
                'thumbnail': 'imageUrl',
            }),
            **traverse_obj(episode, {
                'description': ('description', {clean_html}),
                'duration': ('duration', {parse_duration}),
                'thumbnail': 'imageUrl',
                'timestamp': (['pubDate', 'startDate'], {unified_timestamp}),
                'title': 'title',
            }, get_all=False)
        }
```

Code after:
        return self._search_nextjs_data(webpage, video_id)['props']['pageProps']

    def _request_ext(self, url, video_id):
        return urlhandle_detect_ext(self._request_webpage(  # Server rejects HEAD requests
            url, video_id, note='Determining source extension'))

    def _extract_audio(self, episode, series):
        return {
            'vcodec': 'none',
            **traverse_obj(series, {
                'series': 'title',
                'series_id': 'id',
                'thumbnail': 'imageUrl',
                'uploader': 'itunesAuthor',  # podcasts only
            }),
            **traverse_obj(episode, {
                'id': 'id',
                'description': ('description', {clean_html}),
                'duration': ('duration', {parse_duration}),
                'thumbnail': 'imageUrl',
                'url': 'streamUrl',
                'timestamp': (('pubDate', 'startDate'), {unified_timestamp}),
                'title': 'title',
            }, get_all=False)
        }


class GlobalPlayerLiveIE(GlobalPlayerBaseIE):
    _VALID_URL = r'https?://www\.globalplayer\.com/live/(?P<id>\w+)/\w+'
    _TESTS = [{
        'url': 'https://www.globalplayer.com/live/smoothchill/uk/',
        'info_dict': {
            'id': '2mx1E',
            'ext': 'aac',
            'display_id': 'smoothchill-uk',
            'title': 're:^Smooth Chill.+$',
            'thumbnail': 'https://herald.musicradio.com/media/f296ade8-50c9-4f60-911f-924e96873620.png',
            'description': 'Music To Chill To',
            'live_status': 'is_live',
        },
    }, {
        # national station
        'url': 'https://www.globalplayer.com/live/heart/uk/',
        'info_dict': {
            'id': '2mwx4',
            'ext': 'aac',
            'description': 'turn up the feel good!',
            'thumbnail': 'https://herald.musicradio.com/media/49b9e8cb-15bf-4bf2-8c28-a4850cc6b0f3.png',
            'live_status': 'is_live',
            'title': 're:^Heart UK.+$',
            'display_id': 'heart-uk',