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

Code before:
            'description': '',
            'upload_date': '20220505',
        },
        'params': {
            'skip_download': True,
        },
        'skip': 'this video has been removed',
    }, {
        'url': 'https://www.dr.dk/lyd/p4kbh/regionale-nyheder-kh4/regionale-nyheder-2023-03-14-10-30-9',
        'info_dict': {
            'ext': 'mp4',
            'id': '14802310112',
            'timestamp': 1678786200,
            'duration': 120.043,
            'season_id': 'urn:dr:mu:bundle:63a4f7c87140143504b6710f',
            'series': 'P4 København regionale nyheder',
            'upload_date': '20230314',
            'release_year': 0,
            'description': 'Hør seneste regionale nyheder fra P4 København.',
            'season': 'Regionale nyheder',
            'title': 'Regionale nyheder',
        },
    }]

    def _real_extract(self, url):
        raw_video_id, is_radio_url = self._match_valid_url(url).group('id', 'radio')
        webpage = self._download_webpage(url, raw_video_id)
        if '>Programmet er ikke længere tilgængeligt' in webpage:
            raise ExtractorError(
                'Video %s is not available' % raw_video_id, expected=True)
        json_data = self._search_json(r'window\.__data\s*=', webpage, 'data', raw_video_id)
        item = traverse_obj(json_data, ('cache', 'page', Ellipsis, (None, ('entries', 0)), 'item'), get_all=False)
        itemId = item.get('id')
        videoId = item['customId'].split(':')[-1]
        deviceId = uuid.uuid1()
        token = self._download_json('https://isl.dr-massive.com/api/authorization/anonymous-sso?device=web_browser&ff=idp%2Cldp&lang=da', videoId, headers={'Content-Type': 'application/json'}, data=json.dumps({'deviceId': str(deviceId), 'scopes': ['Catalog'], 'optout': True}).encode('utf-8'))[0]['value']
        data = self._download_json('https://production.dr-massive.com/api/account/items/{0}/videos?delivery=stream&device=web_browser&ff=idp%2Cldp%2Crpt&lang=da&resolution=HD-1080&sub=Anonymous'.format(itemId), videoId, headers={'authorization': 'Bearer {0}'.format(token)})
        formats = []
        subtitles = {}
        for fmt in data:
            formatId = fmt['format'] or 'na'
            accessService = fmt['accessService']
            preference = None
            if accessService in ('SpokenSubtitles', 'SignLanguage', 'VisuallyInterpreted'):
                preference = -1
                formatId += '-%s' % accessService
            elif accessService == 'StandardVideo':
                preference = 1
            fmts, subs = self._extract_m3u8_formats_and_subtitles(fmt['url'], videoId, 'mp4', entry_protocol='m3u8_native', preference=preference, m3u8_id=formatId, fatal=False)
            formats.extend(fmts)
            self._merge_subtitles(subs, target=subtitles)

Review comment (suggestion):
`is_radio_url` is now completely unused. Does the new API no longer require different treatment for radio programs?
If yes, it should no longer be matched.

Code after:
            return

        token_response = self._download_json(
            'https://production.dr-massive.com/api/authorization/anonymous-sso', None,
            note='Downloading anonymous token', headers={
                'content-type': 'application/json',
            }, query={
                'device': 'web_browser',
                'ff': 'idp,ldp,rpt',
                'lang': 'da',
                'supportFallbackToken': 'true',
            }, data=json.dumps({
                'deviceId': str(uuid.uuid4()),
                'scopes': ['Catalog'],
                'optout': True,
            }).encode())

        self._TOKEN = traverse_obj(
            token_response, (lambda _, x: x['type'] == 'UserAccount', 'value', {str}), get_all=False)
        if not self._TOKEN:
            raise ExtractorError('Unable to get anonymous token')

    def _real_extract(self, url):
        url_slug = self._match_id(url)
        webpage = self._download_webpage(url, url_slug)

        json_data = self._search_json(
            r'window\.__data\s*=', webpage, 'data', url_slug, fatal=False) or {}
        item = traverse_obj(
            json_data, ('cache', 'page', ..., (None, ('entries', 0)), 'item', {dict}), get_all=False)
        if item:
            item_id = item.get('id')
        else:
            item_id = url_slug.rsplit('_', 1)[-1]
            item = self._download_json(
                f'https://production-cdn.dr-massive.com/api/items/{item_id}', item_id,
                note='Attempting to download backup item data', query={
                    'device': 'web_browser',
                    'expand': 'all',
                    'ff': 'idp,ldp,rpt',
                    'geoLocation': 'dk',
                    'isDeviceAbroad': 'false',
                    'lang': 'da',
                    'segments': 'drtv,optedout',
                    'sub': 'Anonymous',
                })

        video_id = try_call(lambda: item['customId'].rsplit(':', 1)[-1]) or item_id
        stream_data = self._download_json(
            f'https://production.dr-massive.com/api/account/items/{item_id}/videos', video_id,
            note='Downloading stream data', query={