ronantakizawa/codereview-bench huggingface dataset:
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/rtvs.py (Python)

Code before:
import re

from .common import InfoExtractor
from ..utils import (
    parse_duration,
    traverse_obj,
    unified_timestamp,
)


class RTVSIE(InfoExtractor):
    IE_NAME = 'stvr'
    _VALID_URL = r'https?://(?:www\.)?(rtvs|stvr)\.sk/(?:radio|televizia)/archiv(?:/\d+)?/(?P<id>\d+)/?(?:[#?]|$)'
    _TESTS = [{
        # radio archive
        'url': 'http://www.rtvs.sk/radio/archiv/11224/414872',
        'md5': '134d5d6debdeddf8a5d761cbc9edacb8',
        'info_dict': {
            'id': '414872',
            'ext': 'mp3',
            'title': 'Ostrov pokladov 1 časť.mp3',
            'duration': 2854,
            'thumbnail': 'https://www.rtvs.sk/media/a501/image/file/2/0000/b1R8.rtvs.jpg',
            'display_id': '135331',
        },
    }, {
        # tv archive
        'url': 'http://www.rtvs.sk/televizia/archiv/8249/63118',
        'info_dict': {
            'id': '63118',
            'ext': 'mp4',
            'title': 'Amaro Džives - Náš deň',
            'description': 'Galavečer pri príležitosti Medzinárodného dňa Rómov.',
            'thumbnail': 'https://www.rtvs.sk/media/a501/image/file/2/0031/L7Qm.amaro_dzives_png.jpg',
            'timestamp': 1428555900,
            'upload_date': '20150409',
            'duration': 4986,
        },

Review comment (suggestion):
Let's use a non capturing group
```suggestion
    _VALID_URL = r'https?://(?:www\.)?(?:rtvs|stvr)\.sk/(?:radio|televizia)/archiv(?:/\d+)?/(?P<id>\d+)/?(?:[#?]|$)'
```

Code after:
import re

from .common import InfoExtractor
from ..utils import (
    parse_duration,
    traverse_obj,
    unified_timestamp,
)


class RTVSIE(InfoExtractor):
    IE_NAME = 'stvr'
    IE_DESC = 'Slovak Television and Radio (formerly RTVS)'
    _VALID_URL = r'https?://(?:www\.)?(?:rtvs|stvr)\.sk/(?:radio|televizia)/archiv(?:/\d+)?/(?P<id>\d+)/?(?:[#?]|$)'
    _TESTS = [{
        # radio archive
        'url': 'http://www.rtvs.sk/radio/archiv/11224/414872',
        'md5': '134d5d6debdeddf8a5d761cbc9edacb8',
        'info_dict': {
            'id': '414872',
            'ext': 'mp3',
            'title': 'Ostrov pokladov 1 časť.mp3',
            'duration': 2854,
            'thumbnail': 'https://www.stvr.sk/media/a501/image/file/2/0000/rtvs-00009383.png',
            'display_id': '135331',
        },
    }, {
        # tv archive
        'url': 'http://www.rtvs.sk/televizia/archiv/8249/63118',
        'info_dict': {
            'id': '63118',
            'ext': 'mp4',
            'title': 'Amaro Džives - Náš deň',
            'description': 'Galavečer pri príležitosti Medzinárodného dňa Rómov.',
            'thumbnail': 'https://www.stvr.sk/media/a501/image/file/2/0031/L7Qm.amaro_dzives_png.jpg',
            'timestamp': 1428555900,
            'upload_date': '20150409',
            'duration': 4986,
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/rtvs.py (Python)

Code before:
import re

from .common import InfoExtractor
from ..utils import (
    parse_duration,
    traverse_obj,
    unified_timestamp,
)


class RTVSIE(InfoExtractor):
    IE_NAME = 'stvr'
    _VALID_URL = r'https?://(?:www\.)?(?:rtvs|stvr)\.sk/(?:radio|televizia)/archiv(?:/\d+)?/(?P<id>\d+)/?(?:[#?]|$)'
    _TESTS = [{
        # radio archive
        'url': 'http://www.rtvs.sk/radio/archiv/11224/414872',
        'md5': '134d5d6debdeddf8a5d761cbc9edacb8',
        'info_dict': {
            'id': '414872',
            'ext': 'mp3',
            'title': 'Ostrov pokladov 1 časť.mp3',
            'duration': 2854,
            'thumbnail': 'https://www.stvr.sk/media/a501/image/file/2/0000/rtvs-00009383.png',
            'display_id': '135331',
        },
    }, {
        # tv archive
        'url': 'http://www.rtvs.sk/televizia/archiv/8249/63118',
        'info_dict': {
            'id': '63118',
            'ext': 'mp4',
            'title': 'Amaro Džives - Náš deň',
            'description': 'Galavečer pri príležitosti Medzinárodného dňa Rómov.',
            'thumbnail': 'https://www.stvr.sk/media/a501/image/file/2/0031/L7Qm.amaro_dzives_png.jpg',
            'timestamp': 1428555900,
            'upload_date': '20150409',
            'duration': 4986,

Review comment (suggestion):
```suggestion
    IE_NAME = 'stvr'
    IE_DESC = 'Slovak Television and Radio (formerly RTVS)'
```

Code after:
import re

from .common import InfoExtractor
from ..utils import (
    parse_duration,
    traverse_obj,
    unified_timestamp,
)


class RTVSIE(InfoExtractor):
    IE_NAME = 'stvr'
    IE_DESC = 'Slovak Television and Radio (formerly RTVS)'
    _VALID_URL = r'https?://(?:www\.)?(?:rtvs|stvr)\.sk/(?:radio|televizia)/archiv(?:/\d+)?/(?P<id>\d+)/?(?:[#?]|$)'
    _TESTS = [{
        # radio archive
        'url': 'http://www.rtvs.sk/radio/archiv/11224/414872',
        'md5': '134d5d6debdeddf8a5d761cbc9edacb8',
        'info_dict': {
            'id': '414872',
            'ext': 'mp3',
            'title': 'Ostrov pokladov 1 časť.mp3',
            'duration': 2854,
            'thumbnail': 'https://www.stvr.sk/media/a501/image/file/2/0000/rtvs-00009383.png',
            'display_id': '135331',
        },
    }, {
        # tv archive
        'url': 'http://www.rtvs.sk/televizia/archiv/8249/63118',
        'info_dict': {
            'id': '63118',
            'ext': 'mp4',
            'title': 'Amaro Džives - Náš deň',
            'description': 'Galavečer pri príležitosti Medzinárodného dňa Rómov.',
            'thumbnail': 'https://www.stvr.sk/media/a501/image/file/2/0031/L7Qm.amaro_dzives_png.jpg',
            'timestamp': 1428555900,
            'upload_date': '20150409',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/lrt.py (Python)

Code before:

from .common import InfoExtractor
from ..utils import (
    clean_html,
    merge_dicts,
    str_or_none,
    traverse_obj,
    unified_timestamp,
    url_or_none,
)


class LRTBaseIE(InfoExtractor):
    def _extract_js_var(self, webpage, var_name, default=None):
        return self._search_regex(
            fr'{var_name}\s*=\s*(["\'])((?:(?!\1).)+)\1',
            webpage, var_name.replace('_', ' '), default, group=2)


class LRTStreamIE(LRTBaseIE):
    _VALID_URL = r'https?://(?:www\.)?lrt\.lt/mediateka/tiesiogiai/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.lrt.lt/mediateka/tiesiogiai/lrt-opus',
        'info_dict': {
            'id': 'lrt-opus',
            'live_status': 'is_live',
            'title': 're:^LRT Opus.+$',

Review comment (refactor):
```suggestion
from .common import InfoExtractor
```

Code after:
from .common import InfoExtractor
from ..utils import (
    clean_html,
    merge_dicts,
    str_or_none,
    traverse_obj,
    unified_timestamp,
    url_or_none,
    urljoin,
)


class LRTBaseIE(InfoExtractor):
    def _extract_js_var(self, webpage, var_name, default=None):
        return self._search_regex(
            fr'{var_name}\s*=\s*(["\'])((?:(?!\1).)+)\1',
            webpage, var_name.replace('_', ' '), default, group=2)


class LRTStreamIE(LRTBaseIE):
    _VALID_URL = r'https?://(?:www\.)?lrt\.lt/mediateka/tiesiogiai/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.lrt.lt/mediateka/tiesiogiai/lrt-opus',
        'info_dict': {
            'id': 'lrt-opus',
            'live_status': 'is_live',
            'title': 're:^LRT Opus.+$',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/lrt.py (Python)

Code before:
            'timestamp': 1726143120,
            'upload_date': '20240912',
            'tags': list,
            'thumbnail': r're:https?://.+/.+\.jpe?g',
            'categories': list,
        },
    }, {
        'url': 'https://www.lrt.lt/radioteka/irasas/2000304654/vakaras-su-knyga-svetlana-aleksijevic-cernobylio-malda-v-dalis?season=%2Fmediateka%2Faudio%2Fvakaras-su-knyga%2F2023',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id, path = self._match_valid_url(url).groups()

        base_url = 'https://www.lrt.lt'
        api_url = 'https://www.lrt.lt/radioteka/api/media'
        media_url = f'/mediateka/irasas/{video_id}/{path}'
        media = self._download_json(api_url, video_id, query={'url': media_url})
        return traverse_obj(media, {
            'id': ('id', {int}, {str_or_none}),
            'title': ('title', {str}),
            'tags': ('tags', ..., 'name'),
            'categories': ('playlist_item', 'category', {lambda x: [x]}),
            'description': ('content', {clean_html}, {str}),
            'timestamp': ('date', {lambda x: x.replace('.', '/')}, {unified_timestamp}),
            'thumbnail': ('playlist_item', 'image', {lambda x: f'{base_url}{x}'}, {url_or_none}),
            'formats': ('playlist_item', 'file', {lambda x: self._extract_m3u8_formats(x, video_id)}),
        })


Review comment (suggestion):
we can use `urljoin` here which simplifies things and handles url validation for us
```suggestion
            'thumbnail': ('playlist_item', 'image', {urljoin('https://www.lrt.lt')}),
```

Code after:
            'timestamp': 1726143120,
            'upload_date': '20240912',
            'tags': 'count:5',
            'thumbnail': r're:https?://.+/.+\.jpe?g',
            'categories': ['Daiktiniai įrodymai'],
        },
    }, {
        'url': 'https://www.lrt.lt/radioteka/irasas/2000304654/vakaras-su-knyga-svetlana-aleksijevic-cernobylio-malda-v-dalis?season=%2Fmediateka%2Faudio%2Fvakaras-su-knyga%2F2023',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id, path = self._match_valid_url(url).group('id', 'path')
        media = self._download_json(
            'https://www.lrt.lt/radioteka/api/media', video_id,
            query={'url': f'/mediateka/irasas/{video_id}/{path}'})

        return traverse_obj(media, {
            'id': ('id', {int}, {str_or_none}),
            'title': ('title', {str}),
            'tags': ('tags', ..., 'name', {str}),
            'categories': ('playlist_item', 'category', {str}, filter, all, filter),
            'description': ('content', {clean_html}, {str}),
            'timestamp': ('date', {lambda x: x.replace('.', '/')}, {unified_timestamp}),
            'thumbnail': ('playlist_item', 'image', {urljoin('https://www.lrt.lt')}),
            'formats': ('playlist_item', 'file', {lambda x: self._extract_m3u8_formats(x, video_id)}),
        })
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/lrt.py (Python)

Code before:
            'timestamp': 1726143120,
            'upload_date': '20240912',
            'tags': list,
            'thumbnail': r're:https?://.+/.+\.jpe?g',
            'categories': list,
        },
    }, {
        'url': 'https://www.lrt.lt/radioteka/irasas/2000304654/vakaras-su-knyga-svetlana-aleksijevic-cernobylio-malda-v-dalis?season=%2Fmediateka%2Faudio%2Fvakaras-su-knyga%2F2023',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id, path = self._match_valid_url(url).groups()

        base_url = 'https://www.lrt.lt'
        api_url = 'https://www.lrt.lt/radioteka/api/media'
        media_url = f'/mediateka/irasas/{video_id}/{path}'
        media = self._download_json(api_url, video_id, query={'url': media_url})
        return traverse_obj(media, {
            'id': ('id', {int}, {str_or_none}),
            'title': ('title', {str}),
            'tags': ('tags', ..., 'name'),
            'categories': ('playlist_item', 'category', {lambda x: [x]}),
            'description': ('content', {clean_html}, {str}),
            'timestamp': ('date', {lambda x: x.replace('.', '/')}, {unified_timestamp}),
            'thumbnail': ('playlist_item', 'image', {lambda x: f'{base_url}{x}'}, {url_or_none}),
            'formats': ('playlist_item', 'file', {lambda x: self._extract_m3u8_formats(x, video_id)}),
        })


Review comment (security):
I think I may have mentioned this in another PR of yours that I generally don't like calling the `_extract_*_formats*` helpers in traversal transformations (again because they are always called). Just saying it again in case I am misremembering authors. But here it is fine since we always need to call it and it's always fatal

Code after:
            'timestamp': 1726143120,
            'upload_date': '20240912',
            'tags': 'count:5',
            'thumbnail': r're:https?://.+/.+\.jpe?g',
            'categories': ['Daiktiniai įrodymai'],
        },
    }, {
        'url': 'https://www.lrt.lt/radioteka/irasas/2000304654/vakaras-su-knyga-svetlana-aleksijevic-cernobylio-malda-v-dalis?season=%2Fmediateka%2Faudio%2Fvakaras-su-knyga%2F2023',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id, path = self._match_valid_url(url).group('id', 'path')
        media = self._download_json(
            'https://www.lrt.lt/radioteka/api/media', video_id,
            query={'url': f'/mediateka/irasas/{video_id}/{path}'})

        return traverse_obj(media, {
            'id': ('id', {int}, {str_or_none}),
            'title': ('title', {str}),
            'tags': ('tags', ..., 'name', {str}),
            'categories': ('playlist_item', 'category', {str}, filter, all, filter),
            'description': ('content', {clean_html}, {str}),
            'timestamp': ('date', {lambda x: x.replace('.', '/')}, {unified_timestamp}),
            'thumbnail': ('playlist_item', 'image', {urljoin('https://www.lrt.lt')}),
            'formats': ('playlist_item', 'file', {lambda x: self._extract_m3u8_formats(x, video_id)}),
        })
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/lrt.py (Python)

Code before:

from .common import InfoExtractor
from ..utils import (
    clean_html,
    merge_dicts,
    str_or_none,
    traverse_obj,
    unified_timestamp,
    url_or_none,
)


class LRTBaseIE(InfoExtractor):
    def _extract_js_var(self, webpage, var_name, default=None):
        return self._search_regex(
            fr'{var_name}\s*=\s*(["\'])((?:(?!\1).)+)\1',
            webpage, var_name.replace('_', ' '), default, group=2)


class LRTStreamIE(LRTBaseIE):
    _VALID_URL = r'https?://(?:www\.)?lrt\.lt/mediateka/tiesiogiai/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.lrt.lt/mediateka/tiesiogiai/lrt-opus',
        'info_dict': {
            'id': 'lrt-opus',
            'live_status': 'is_live',
            'title': 're:^LRT Opus.+$',
            'ext': 'mp4',
        },
    }]

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

Review comment (suggestion):
```suggestion
    url_or_none,
    urljoin,
```

Code after:
from .common import InfoExtractor
from ..utils import (
    clean_html,
    merge_dicts,
    str_or_none,
    traverse_obj,
    unified_timestamp,
    url_or_none,
    urljoin,
)


class LRTBaseIE(InfoExtractor):
    def _extract_js_var(self, webpage, var_name, default=None):
        return self._search_regex(
            fr'{var_name}\s*=\s*(["\'])((?:(?!\1).)+)\1',
            webpage, var_name.replace('_', ' '), default, group=2)


class LRTStreamIE(LRTBaseIE):
    _VALID_URL = r'https?://(?:www\.)?lrt\.lt/mediateka/tiesiogiai/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.lrt.lt/mediateka/tiesiogiai/lrt-opus',
        'info_dict': {
            'id': 'lrt-opus',
            'live_status': 'is_live',
            'title': 're:^LRT Opus.+$',
            'ext': 'mp4',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/roya.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import ExtractorError


class RoyaIE(InfoExtractor):
    _VALID_URL = r'https?://roya\.tv/live-stream/(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://roya.tv/live-stream/1',
        'info_dict': {
            'id': '1',
            'title': r're:Roya TV \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'is_live': True,
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/21',
        'info_dict': {
            'id': '21',
            'title': r're:Roya News \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'is_live': True,
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/10000',
        'only_matching': True,
    }]

    def _real_extract(self, url):

Review comment (refactor):
Let's name this `RoyaLiveIE`, as `RoyaIE` would be the extractor for vods
```suggestion
class RoyaLiveIE(InfoExtractor):
```

Code after:
from .common import InfoExtractor
from ..utils.traversal import traverse_obj


class RoyaLiveIE(InfoExtractor):
    _VALID_URL = r'https?://roya\.tv/live-stream/(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://roya.tv/live-stream/1',
        'info_dict': {
            'id': '1',
            'title': r're:Roya TV \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/21',
        'info_dict': {
            'id': '21',
            'title': r're:Roya News \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/10000',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        media_id = self._match_id(url)
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/roya.py (Python)

Code before:
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/21',
        'info_dict': {
            'id': '21',
            'title': r're:Roya News \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'is_live': True,
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/10000',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        media_id = self._match_id(url)
        stream_json = self._download_json(f'https://ticket.roya-tv.com/api/v5/fastchannel/{media_id}', media_id)

        secured_url = None
        if stream_json:
            secured_url = stream_json.get('data', {}).get('secured_url')

        if not secured_url:
            raise ExtractorError('Failed to extract stream')

        title = self.get_title(media_id)

        return {
            'id': media_id,
            'url': secured_url,
            'ext': 'mp4',
            'title': title,
            'is_live': 'live-stream' in url,
        }

    def get_title(self, media_id):
        schedule = self._download_json('https://backend.roya.tv/api/v01/channels/schedule-pagination', media_id)
        if schedule:
            schedule_data = schedule.get('data', {})
            if len(schedule_data) > 0:
                schedule_today = schedule_data[0]
                channel_schedules = schedule_today.get('channel', {})
                for channel_schedule in channel_schedules:
                    if str(channel_schedule.get('id')) == media_id:
                        return channel_schedule.get('title')
        return None


Review comment (suggestion):
As the URL is required this can just be fatal
```suggestion
        stream_url = self._download_json(
            f'https://ticket.roya-tv.com/api/v5/fastchannel/{media_id}', media_id)['data']['secured_url']
```

Code after:
        },
    }, {
        'url': 'https://roya.tv/live-stream/21',
        'info_dict': {
            'id': '21',
            'title': r're:Roya News \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/10000',
        'only_matching': True,
    }]

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

        stream_url = self._download_json(
            f'https://ticket.roya-tv.com/api/v5/fastchannel/{media_id}', media_id)['data']['secured_url']

        title = traverse_obj(
            self._download_json('https://backend.roya.tv/api/v01/channels/schedule-pagination', media_id, fatal=False),
            ('data', 0, 'channel', lambda _, v: str(v['id']) == media_id, 'title', {str}, any))

        return {
            'id': media_id,
            'formats': self._extract_m3u8_formats(stream_url, media_id, 'mp4', m3u8_id='hls', live=True),
            'title': title,
            'is_live': True,
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/roya.py (Python)

Code before:
    }, {
        'url': 'https://roya.tv/live-stream/21',
        'info_dict': {
            'id': '21',
            'title': r're:Roya News \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'is_live': True,
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/10000',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        media_id = self._match_id(url)
        stream_json = self._download_json(f'https://ticket.roya-tv.com/api/v5/fastchannel/{media_id}', media_id)

        secured_url = None
        if stream_json:
            secured_url = stream_json.get('data', {}).get('secured_url')

        if not secured_url:
            raise ExtractorError('Failed to extract stream')

        title = self.get_title(media_id)

        return {
            'id': media_id,
            'url': secured_url,
            'ext': 'mp4',
            'title': title,
            'is_live': 'live-stream' in url,
        }

    def get_title(self, media_id):
        schedule = self._download_json('https://backend.roya.tv/api/v01/channels/schedule-pagination', media_id)
        if schedule:
            schedule_data = schedule.get('data', {})
            if len(schedule_data) > 0:
                schedule_today = schedule_data[0]
                channel_schedules = schedule_today.get('channel', {})
                for channel_schedule in channel_schedules:
                    if str(channel_schedule.get('id')) == media_id:
                        return channel_schedule.get('title')
        return None


Review comment (refactor):
We can simplify this with `traverse_obj`
```suggestion
        title = traverse_obj(
            self._download_json('https://backend.roya.tv/api/v01/channels/schedule-pagination', media_id),
            ('data', 0, 'channel', lambda _, v: str(v['id']) == media_id, 'title', {str}, any))
```

Code after:
        'url': 'https://roya.tv/live-stream/21',
        'info_dict': {
            'id': '21',
            'title': r're:Roya News \d{4}-\d{2}-\d{2} \d{2}:\d{2}',
            'ext': 'mp4',
            'live_status': 'is_live',
        },
    }, {
        'url': 'https://roya.tv/live-stream/10000',
        'only_matching': True,
    }]

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

        stream_url = self._download_json(
            f'https://ticket.roya-tv.com/api/v5/fastchannel/{media_id}', media_id)['data']['secured_url']

        title = traverse_obj(
            self._download_json('https://backend.roya.tv/api/v01/channels/schedule-pagination', media_id, fatal=False),
            ('data', 0, 'channel', lambda _, v: str(v['id']) == media_id, 'title', {str}, any))

        return {
            'id': media_id,
            'formats': self._extract_m3u8_formats(stream_url, media_id, 'mp4', m3u8_id='hls', live=True),
            'title': title,
            'is_live': True,
        }