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

Code before:
            'episode': '돌싱포맨 저격수들 등장!',
            'episode_number': 104,
        },
    }]

    def request_details(self, video_id, rscuse=''):
        return self._download_json(
            f'https://api.play.sbs.co.kr/1.0/sbs_vodall/{video_id}', video_id,
            note=f'Downloading m3u8 information {rscuse}',
            query={
                'platform': 'pcweb',
                'protocol': 'download',
                'absolute_show': 'Y',
                'service': 'program',
                'ssl': 'Y',
                'rscuse': rscuse,
            })

    def _real_extract(self, url):
        video_id = self._match_id(url)

        details = self.request_details(video_id)
        source = traverse_obj(details, ('vod', 'source', 'mediasource'))

        formats = []
        for stream in traverse_obj(details, ('vod', 'source', 'mediasourcelist'), default=[source]):
            if not stream.get('mediaurl'):
                alt_details = self.request_details(video_id, rscuse=stream.get('mediarscuse'))
                new_source = traverse_obj(alt_details, ('vod', 'source', 'mediasource'))
                if new_source.get('mediarscuse') == source.get('mediarscuse') or not new_source.get('mediaurl'):
                    continue
                stream = new_source
            formats.append({
                'url': stream.get('mediaurl'),
                'format_id': stream.get('mediarscuse'),
                'format_note': stream.get('medianame'),
                **parse_resolution(stream.get('quality')),
                'preference': int_or_none(stream.get('mediarscuse'))
            })

        caption_url = traverse_obj(details, ('vod', 'source', 'subtitle', {url_or_none}))
        subtitles = {'ko': [{'url': caption_url}]} if caption_url else None

        return {
            'id': video_id,
            **traverse_obj(details, ('vod', {
                'title': ('info', 'title'),
                'duration': ('info', 'duration', {int_or_none}),
                'view_count': ('info', 'viewcount', {int_or_none}),
                'like_count': ('info', 'likecount', {int_or_none}),
                'description': ('info', 'synopsis', {clean_html}),

Review comment (suggestion):
could filter here to ensure that we always get a list, and that we always fallback to `[source]` if `mediasourcelist` doesn't have what we need
```suggestion
        for stream in traverse_obj(details, (
            'vod', 'source', 'mediasourcelist', lambda _, v: v['mediaurl'] or v['mediarscuse']
        ), default=[source]):
```

Code after:
            'episode': '돌싱포맨 저격수들 등장!',
            'episode_number': 104,
        },
    }]

    def _call_api(self, video_id, rscuse=''):
        return self._download_json(
            f'https://api.play.sbs.co.kr/1.0/sbs_vodall/{video_id}', video_id,
            note=f'Downloading m3u8 information {rscuse}',
            query={
                'platform': 'pcweb',
                'protocol': 'download',
                'absolute_show': 'Y',
                'service': 'program',
                'ssl': 'Y',
                'rscuse': rscuse,
            })

    def _real_extract(self, url):
        video_id = self._match_id(url)

        details = self._call_api(video_id)
        source = traverse_obj(details, ('vod', 'source', 'mediasource', {dict})) or {}

        formats = []
        for stream in traverse_obj(details, (
            'vod', 'source', 'mediasourcelist', lambda _, v: v['mediaurl'] or v['mediarscuse']
        ), default=[source]):
            if not stream.get('mediaurl'):
                new_source = traverse_obj(
                    self._call_api(video_id, rscuse=stream['mediarscuse']),
                    ('vod', 'source', 'mediasource', {dict})) or {}
                if new_source.get('mediarscuse') == source.get('mediarscuse') or not new_source.get('mediaurl'):
                    continue
                stream = new_source
            formats.append({
                'url': stream['mediaurl'],
                'format_id': stream.get('mediarscuse'),
                'format_note': stream.get('medianame'),
                **parse_resolution(stream.get('quality')),
                'preference': int_or_none(stream.get('mediarscuse'))
            })

        caption_url = traverse_obj(details, ('vod', 'source', 'subtitle', {url_or_none}))

        return {
            'id': video_id,
            **traverse_obj(details, ('vod', {
                'title': ('info', 'title'),
                'duration': ('info', 'duration', {int_or_none}),
                'view_count': ('info', 'viewcount', {int_or_none}),