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

Code before:
            'media_type': 'episode',
            'timestamp': 1706472362,
            'upload_date': '20240128',
        }
    }, {
        'url': 'https://on.orf.at/video/3220355',
        'md5': 'f94d98e667cf9a3851317efb4e136662',
        'info_dict': {
            'id': '3220355',
            'ext': 'mp4',
            'duration': 445.04,
            'thumbnail': 'https://api-tvthek.orf.at/assets/segments/0002/60/thumb_159573_segments_highlight_teaser.png',
            'title': '50 Jahre Burgenland: Der Festumzug',
            'description': 'md5:1560bf855119544ee8c4fa5376a2a6b0',
            'media_type': 'episode',
            'timestamp': 52916400,
            'upload_date': '19710905',
        }
    }]

    def _extract_video(self, video_id):
        encrypted_id = base64.b64encode(f'3dSlfek03nsLKdj4Jsd{video_id}'.encode()).decode()
        api_json = self._download_json(
            f'https://api-tvthek.orf.at/api/v4.3/public/episode/encrypted/{encrypted_id}', video_id)

        if api_json.get('is_drm_protected'):
            self.report_drm(video_id)

        formats, subtitles = [], {}
        for manifest_type in traverse_obj(api_json, ('sources', {dict.keys}, ...)):
            for manifest_url in traverse_obj(api_json, ('sources', manifest_type, ..., 'src', {url_or_none})):
                if manifest_type == 'hls':
                    fmts, subs = self._extract_m3u8_formats_and_subtitles(
                        manifest_url, video_id, fatal=False, m3u8_id='hls')
                elif manifest_type == 'dash':
                    fmts, subs = self._extract_mpd_formats_and_subtitles(
                        manifest_url, video_id, fatal=False, mpd_id='dash')
                else:
                    continue
                formats.extend(fmts)
                self._merge_subtitles(subs, target=subtitles)

        for sub_url in traverse_obj(api_json, (
                '_embedded', 'subtitle',
                ('xml_url', 'sami_url', 'stl_url', 'ttml_url', 'srt_url', 'vtt_url'), {url_or_none})):
            self._merge_subtitles({'de': [{'url': sub_url}]}, target=subtitles)

        return {
            'id': video_id,
            'formats': formats,
            'subtitles': subtitles,

Review comment (suggestion):
Turns out there was a reason to use `traverse_obj` here, to not be fatal during error handling
```suggestion
        if traverse_obj(api_json, 'is_drm_protected'):
```

Code after:
            'media_type': 'episode',
            'timestamp': 1706472362,
            'upload_date': '20240128',
        }
    }, {
        'url': 'https://on.orf.at/video/3220355',
        'md5': 'f94d98e667cf9a3851317efb4e136662',
        'info_dict': {
            'id': '3220355',
            'ext': 'mp4',
            'duration': 445.04,
            'thumbnail': 'https://api-tvthek.orf.at/assets/segments/0002/60/thumb_159573_segments_highlight_teaser.png',
            'title': '50 Jahre Burgenland: Der Festumzug',
            'description': 'md5:1560bf855119544ee8c4fa5376a2a6b0',
            'media_type': 'episode',
            'timestamp': 52916400,
            'upload_date': '19710905',
        }
    }]

    def _extract_video(self, video_id):
        encrypted_id = base64.b64encode(f'3dSlfek03nsLKdj4Jsd{video_id}'.encode()).decode()
        api_json = self._download_json(
            f'https://api-tvthek.orf.at/api/v4.3/public/episode/encrypted/{encrypted_id}', video_id)

        if traverse_obj(api_json, 'is_drm_protected'):
            self.report_drm(video_id)

        formats, subtitles = [], {}
        for manifest_type in traverse_obj(api_json, ('sources', {dict.keys}, ...)):
            for manifest_url in traverse_obj(api_json, ('sources', manifest_type, ..., 'src', {url_or_none})):
                if manifest_type == 'hls':
                    fmts, subs = self._extract_m3u8_formats_and_subtitles(
                        manifest_url, video_id, fatal=False, m3u8_id='hls')
                elif manifest_type == 'dash':
                    fmts, subs = self._extract_mpd_formats_and_subtitles(
                        manifest_url, video_id, fatal=False, mpd_id='dash')
                else:
                    continue
                formats.extend(fmts)
                self._merge_subtitles(subs, target=subtitles)

        for sub_url in traverse_obj(api_json, (
                '_embedded', 'subtitle',
                ('xml_url', 'sami_url', 'stl_url', 'ttml_url', 'srt_url', 'vtt_url'), {url_or_none})):
            self._merge_subtitles({'de': [{'url': sub_url}]}, target=subtitles)

        return {
            'id': video_id,
            'formats': formats,
            'subtitles': subtitles,