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

Code before:
            'duration': 65,
            'release_date': '20231028',
            'thumbnail': 'http://img.vod.mbn.co.kr/vod2/952/2023/09/11/20230911130223_22_952_1054797_1080_7.jpg',
            'series': '완벽한 결혼의 정석',
        },
    }]

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

        content_cls_cd = self._search_regex(r'"\?content_cls_cd=(\d+)&', webpage, 'content_cls_cd', default='20')
        media_info = self._download_json(
            f'https://www.mbn.co.kr/player/mbnVodPlayer_2020.mbn?content_cls_cd={content_cls_cd}&content_id={content_id}&relay_type=1',
            content_id, note='Fetching playback data')

        formats = []
        for stream in media_info.get('movie_list'):
            if not stream.get('url'):
                continue
            location = re.sub(r'/(?:chunklist|playlist)(?:_pd180000)?\.m3u8', '/manifest.m3u8', stream['url'])
            m3u8_url = self._download_webpage(
                f'https://www.mbn.co.kr/player/mbnStreamAuth_new_vod.mbn?vod_url={location}',
                content_id, note='Generating authenticated m3u8 url')

            formats.extend(self._extract_m3u8_formats(m3u8_url, content_id))

        return {
            'id': content_id,
            'title': media_info.get('movie_title'),
            'duration': int_or_none(media_info.get('play_sec')),
            'release_date': unified_strdate(media_info.get('bcast_date').replace('.', '')),
            'thumbnail': media_info.get('movie_start_Img'),
            'series': media_info.get('prog_nm'),
            'episode_number': int_or_none(media_info.get('ad_contentnumber')),
            'formats': formats,
        }


Review comment (refactor):
since we are potentially extracting multiple m3u8s, I think this should be non-fatal
```suggestion
            formats.extend(self._extract_m3u8_formats(m3u8_url, content_id, fatal=False))
```

Code after:
            'ext': 'mp4',
            'title': '[2차 티저] MBN 주말 미니시리즈 <완벽한 결혼의 정석> l 그녀에게 주어진 두 번째 인생',
            'duration': 65,
            'release_date': '20231028',
            'thumbnail': 'http://img.vod.mbn.co.kr/vod2/952/2023/09/11/20230911130223_22_952_1054797_1080_7.jpg',
            'series': '완벽한 결혼의 정석',
        },
    }]

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

        content_cls_cd = self._search_regex(
            r'"\?content_cls_cd=(\d+)&', webpage, 'content cls cd', fatal=False) or '20'
        media_info = self._download_json(
            'https://www.mbn.co.kr/player/mbnVodPlayer_2020.mbn', content_id,
            note='Fetching playback data', query={
                'content_cls_cd': content_cls_cd,
                'content_id': content_id,
                'relay_type': '1',
            })

        formats = []
        for stream_url in traverse_obj(media_info, ('movie_list', ..., 'url', {url_or_none})):
            stream_url = re.sub(r'/(?:chunk|play)list(?:_pd\d+)?\.m3u8', '/manifest.m3u8', stream_url)
            final_url = url_or_none(self._download_webpage(
                f'https://www.mbn.co.kr/player/mbnStreamAuth_new_vod.mbn?vod_url={stream_url}',
                content_id, note='Fetching authenticated m3u8 url'))

            formats.extend(self._extract_m3u8_formats(final_url, content_id, fatal=False))

        return {
            'id': content_id,
            **traverse_obj(media_info, {
                'title': ('movie_title', {str}),
                'duration': ('play_sec', {int_or_none}),
                'release_date': ('bcast_date', {lambda x: x.replace('.', '')}, {unified_strdate}),
                'thumbnail': ('movie_start_Img', {url_or_none}),
                'series': ('prog_nm', {str}),
                'episode_number': ('ad_contentnumber', {int_or_none}),
            }),
            'formats': formats,
        }