From 4bc19adc8798e7564513898cf34adc432c6c5709 Mon Sep 17 00:00:00 2001 From: sepro Date: Sat, 20 Sep 2025 00:38:34 +0200 Subject: [PATCH] [ie/ttinglive] Adapt FlexTV extractor to new domain (#14375) Closes #14342 Authored by: seproDev --- yt_dlp/extractor/flextv.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/yt_dlp/extractor/flextv.py b/yt_dlp/extractor/flextv.py index f3d3eff85f..2429b18477 100644 --- a/yt_dlp/extractor/flextv.py +++ b/yt_dlp/extractor/flextv.py @@ -3,15 +3,19 @@ from ..networking.exceptions import HTTPError from ..utils import ( ExtractorError, UserNotLive, + int_or_none, + join_nonempty, parse_iso8601, str_or_none, - traverse_obj, url_or_none, ) +from ..utils.traversal import traverse_obj class FlexTVIE(InfoExtractor): - _VALID_URL = r'https?://(?:www\.)?flextv\.co\.kr/channels/(?P\d+)/live' + IE_NAME = 'ttinglive' + IE_DESC = '띵라이브 (formerly FlexTV)' + _VALID_URL = r'https?://(?:www\.)?(?:ttinglive\.com|flextv\.co\.kr)/channels/(?P\d+)/live' _TESTS = [{ 'url': 'https://www.flextv.co.kr/channels/231638/live', 'info_dict': { @@ -36,21 +40,32 @@ class FlexTVIE(InfoExtractor): try: stream_data = self._download_json( - f'https://api.flextv.co.kr/api/channels/{channel_id}/stream', + f'https://api.ttinglive.com/api/channels/{channel_id}/stream', channel_id, query={'option': 'all'}) except ExtractorError as e: if isinstance(e.cause, HTTPError) and e.cause.status == 400: raise UserNotLive(video_id=channel_id) raise - playlist_url = stream_data['sources'][0]['url'] - formats, subtitles = self._extract_m3u8_formats_and_subtitles( - playlist_url, channel_id, 'mp4') + formats = [] + for stream in traverse_obj(stream_data, ('sources', ..., {dict})): + if stream.get('format') == 'ivs' and url_or_none(stream.get('url')): + formats.extend(self._extract_m3u8_formats( + stream['url'], channel_id, 'mp4', live=True, fatal=False, m3u8_id='ivs')) + for format_type in ['hls', 'flv']: + for data in traverse_obj(stream, ( + 'urlDetail', format_type, 'resolution', lambda _, v: url_or_none(v['url']))): + formats.append({ + 'format_id': join_nonempty(format_type, data.get('suffixName'), delim=''), + 'url': data['url'], + 'height': int_or_none(data.get('resolution')), + 'ext': 'mp4' if format_type == 'hls' else 'flv', + 'protocol': 'm3u8_native' if format_type == 'hls' else 'http', + }) return { 'id': channel_id, 'formats': formats, - 'subtitles': subtitles, 'is_live': True, **traverse_obj(stream_data, { 'title': ('stream', 'title', {str}),