From 19c5d7c53013440ec4f3f56ebbb067531b272f3f Mon Sep 17 00:00:00 2001 From: Nikolay Fedorov <40500428+swayll@users.noreply.github.com> Date: Mon, 10 Nov 2025 01:24:41 +0300 Subject: [PATCH] [ie/1tv:live] Add extractor (#14299) Authored by: swayll --- yt_dlp/extractor/_extractors.py | 5 ++++- yt_dlp/extractor/firsttv.py | 35 ++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/yt_dlp/extractor/_extractors.py b/yt_dlp/extractor/_extractors.py index fa378e51ce..640b756672 100644 --- a/yt_dlp/extractor/_extractors.py +++ b/yt_dlp/extractor/_extractors.py @@ -640,7 +640,10 @@ from .filmon import ( FilmOnIE, ) from .filmweb import FilmwebIE -from .firsttv import FirstTVIE +from .firsttv import ( + FirstTVIE, + FirstTVLiveIE, +) from .fivetv import FiveTVIE from .flextv import FlexTVIE from .flickr import FlickrIE diff --git a/yt_dlp/extractor/firsttv.py b/yt_dlp/extractor/firsttv.py index 878732c49e..86ad7d7a19 100644 --- a/yt_dlp/extractor/firsttv.py +++ b/yt_dlp/extractor/firsttv.py @@ -10,7 +10,7 @@ from ..utils import ( unified_strdate, url_or_none, ) -from ..utils.traversal import traverse_obj +from ..utils.traversal import require, traverse_obj class FirstTVIE(InfoExtractor): @@ -129,3 +129,36 @@ class FirstTVIE(InfoExtractor): return self.playlist_result( self._entries(items), display_id, self._og_search_title(webpage, default=None), thumbnail=self._og_search_thumbnail(webpage, default=None)) + + +class FirstTVLiveIE(InfoExtractor): + IE_NAME = '1tv:live' + IE_DESC = 'Первый канал (прямой эфир)' + _VALID_URL = r'https?://(?:www\.)?1tv\.ru/live' + + _TESTS = [{ + 'url': 'https://www.1tv.ru/live', + 'info_dict': { + 'id': 'live', + 'ext': 'mp4', + 'title': r're:ПЕРВЫЙ КАНАЛ ПРЯМОЙ ЭФИР СМОТРЕТЬ ОНЛАЙН \d{4}-\d{2}-\d{2} \d{2}:\d{2}$', + 'live_status': 'is_live', + }, + 'params': {'skip_download': 'livestream'}, + }] + + def _real_extract(self, url): + display_id = 'live' + webpage = self._download_webpage(url, display_id, fatal=False) + + streams_list = self._download_json('https://stream.1tv.ru/api/playlist/1tvch-v1_as_array.json', display_id) + mpd_url = traverse_obj(streams_list, ('mpd', ..., {url_or_none}, any, {require('mpd url')})) + # FFmpeg needs to be passed -re to not seek past live window. This is handled by core + formats, _ = self._extract_mpd_formats_and_subtitles(mpd_url, display_id, mpd_id='dash') + + return { + 'id': display_id, + 'title': self._html_extract_title(webpage), + 'formats': formats, + 'is_live': True, + }