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

Code before:
                qq = qualities(['base', 'mobilesource', 'main'])
                streams = traverse_obj(stream_server_data, ('llfmp4', 'streams')) or {}
                for mode, ws_url in streams.items():
                    formats.append({
                        'url': ws_url,
                        'format_id': 'ws-%s' % mode,
                        'ext': 'mp4',
                        'quality': qq(mode),
                        # TwitCasting simply sends moof atom directly over WS
                        'protocol': 'websocket_frag',
                    })

            self._sort_formats(formats)

            infodict = {
                'formats': formats
            }
        else:
            infodict = {
                '_type': 'multi_video',
                'entries': [{
                    'id': f'{video_id}-{num}',
                    'url': m3u8_url,
                    'ext': 'mp4',
                    # has to be ffmpeg because the requesting them at once will cause download failure
                    # (https://github.com/yt-dlp/yt-dlp/issues/382)
                    'protocol': 'm3u8',
                    'http_headers': self._M3U8_HEADERS,
                    **base_dict,
                } for (num, m3u8_url) in enumerate(m3u8_urls)],
            }

        return {
            'id': video_id,
            **base_dict,
            **infodict,
        }


class TwitCastingLiveIE(InfoExtractor):
    _VALID_URL = r'https?://(?:[^/]+\.)?twitcasting\.tv/(?P<id>[^/]+)/?(?:[#?]|$)'
    _TESTS = [{
        'url': 'https://twitcasting.tv/ivetesangalo',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        uploader_id = self._match_id(url)
        self.to_screen(
            'Downloading live video of user {0}. '
            'Pass "https://twitcasting.tv/{0}/show" to download the history'.format(uploader_id))

Review comment (bug):
```suggestion
                    # Requesting the manifests here will cause download to fail.
                    # So use ffmpeg instead. See: https://github.com/yt-dlp/yt-dlp/issues/382
```

Code after:
                    formats.append({
                        'url': ws_url,
                        'format_id': 'ws-%s' % mode,
                        'ext': 'mp4',
                        'quality': qq(mode),
                        # TwitCasting simply sends moof atom directly over WS
                        'protocol': 'websocket_frag',
                    })

            self._sort_formats(formats)

            infodict = {
                'formats': formats
            }
        else:
            infodict = {
                '_type': 'multi_video',
                'entries': [{
                    'id': f'{video_id}-{num}',
                    'url': m3u8_url,
                    'ext': 'mp4',
                    # Requesting the manifests here will cause download to fail.
                    # So use ffmpeg instead. See: https://github.com/yt-dlp/yt-dlp/issues/382
                    'protocol': 'm3u8',
                    'http_headers': self._M3U8_HEADERS,
                    **base_dict,
                } for (num, m3u8_url) in enumerate(m3u8_urls)],
            }

        return {
            'id': video_id,
            **base_dict,
            **infodict,
        }


class TwitCastingLiveIE(InfoExtractor):
    _VALID_URL = r'https?://(?:[^/]+\.)?twitcasting\.tv/(?P<id>[^/]+)/?(?:[#?]|$)'
    _TESTS = [{
        'url': 'https://twitcasting.tv/ivetesangalo',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        uploader_id = self._match_id(url)
        self.to_screen(
            'Downloading live video of user {0}. '
            'Pass "https://twitcasting.tv/{0}/show" to download the history'.format(uploader_id))

        webpage = self._download_webpage(url, uploader_id)
        current_live = self._search_regex(