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

Code before:
    _VALID_URL = r'https?://vod\.afreecatv\.com/player/(?P<id>\d+)/catchstory'
    _TESTS = [{
        'url': 'https://vod.afreecatv.com/player/103247/catchstory',
        'info_dict': {
            'id': '103247',
        },
        'playlist_count': 2,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        data = self._download_json(
            'https://api.m.afreecatv.com/catchstory/a/view', video_id, headers={'Referer': url},
            query={'aStoryListIdx': '', 'nStoryIdx': video_id}, impersonate=True)

        return self.playlist_result(self._entries(data), video_id)

    @staticmethod
    def _entries(data):
        # 'files' is always a list with 1 element
        yield from traverse_obj(data, (
            'data', lambda _, v: v['story_type'] == 'catch',
            'catch_list', lambda _, v: v['files'][0]['file'], {
                'id': ('files', 0, 'file_info_key', {str}),
                'url': ('files', 0, 'file', {url_or_none}),
                'ext': ('src_movie', {lambda v: determine_ext(v, 'mp4')}),
                'duration': ('files', 0, 'duration', {functools.partial(int_or_none, scale=1000)}),
                'title': ('title', {str}),
                'uploader': ('writer_nick', {str}),
                'uploader_id': ('writer_id', {str}),
                'thumbnail': ('thumb', {url_or_none}),
                'timestamp': ('write_timestamp', {int_or_none}),
            }))


class AfreecaTVLiveIE(AfreecaTVBaseIE):
    IE_NAME = 'afreecatv:live'
    IE_DESC = 'afreecatv.com livestreams'
    _VALID_URL = r'https?://play\.afreeca(?:tv)?\.com/(?P<id>[^/]+)(?:/(?P<bno>\d+))?'
    _TESTS = [{
        'url': 'https://play.afreecatv.com/pyh3646/237852185',
        'info_dict': {
            'id': '237852185',
            'ext': 'mp4',
            'title': '【 우루과이 오늘은 무슨일이? 】',
            'uploader': '박진우[JINU]',
            'uploader_id': 'pyh3646',
            'timestamp': 1640661495,
            'is_live': True,
        },
        'skip': 'Livestream has ended',

Review comment (suggestion):
we don't want this. the test's url is an m3u8 and this value is mp4. it will not download correctly if yt-dlp thinks an m3u8 is an mp4
```suggestion
```

Code after:
    _VALID_URL = r'https?://vod\.afreecatv\.com/player/(?P<id>\d+)/catchstory'
    _TESTS = [{
        'url': 'https://vod.afreecatv.com/player/103247/catchstory',
        'info_dict': {
            'id': '103247',
        },
        'playlist_count': 2,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        data = self._download_json(
            'https://api.m.afreecatv.com/catchstory/a/view', video_id, headers={'Referer': url},
            query={'aStoryListIdx': '', 'nStoryIdx': video_id}, impersonate=True)

        return self.playlist_result(self._entries(data), video_id)

    @staticmethod
    def _entries(data):
        # 'files' is always a list with 1 element
        yield from traverse_obj(data, (
            'data', lambda _, v: v['story_type'] == 'catch',
            'catch_list', lambda _, v: v['files'][0]['file'], {
                'id': ('files', 0, 'file_info_key', {str}),
                'url': ('files', 0, 'file', {url_or_none}),
                'duration': ('files', 0, 'duration', {functools.partial(int_or_none, scale=1000)}),
                'title': ('title', {str}),
                'uploader': ('writer_nick', {str}),
                'uploader_id': ('writer_id', {str}),
                'thumbnail': ('thumb', {url_or_none}),
                'timestamp': ('write_timestamp', {int_or_none}),
            }))


class AfreecaTVLiveIE(AfreecaTVBaseIE):
    IE_NAME = 'afreecatv:live'
    IE_DESC = 'afreecatv.com livestreams'
    _VALID_URL = r'https?://play\.afreeca(?:tv)?\.com/(?P<id>[^/]+)(?:/(?P<bno>\d+))?'
    _TESTS = [{
        'url': 'https://play.afreecatv.com/pyh3646/237852185',
        'info_dict': {
            'id': '237852185',
            'ext': 'mp4',
            'title': '【 우루과이 오늘은 무슨일이? 】',
            'uploader': '박진우[JINU]',
            'uploader_id': 'pyh3646',
            'timestamp': 1640661495,
            'is_live': True,
        },
        'skip': 'Livestream has ended',
    }, {