diff options
author | JC-Chung <52159296+JC-Chung@users.noreply.github.com> | 2023-01-05 19:23:34 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-05 11:23:34 +0000 |
commit | 933ed882e94ebfacc5e407dbd74fa25e672092c4 (patch) | |
tree | 5ae909e4d6ebee15fbc3be840a9f030a50339153 | |
parent | a1d9aca3382a83e61d5069a140664a112e6c54e4 (diff) | |
download | hypervideo-pre-933ed882e94ebfacc5e407dbd74fa25e672092c4.tar.lz hypervideo-pre-933ed882e94ebfacc5e407dbd74fa25e672092c4.tar.xz hypervideo-pre-933ed882e94ebfacc5e407dbd74fa25e672092c4.zip |
[extractor/tiktok] Add `TikTokLive` extractor (#5637)
Closes #3698
Authored by: JC-Chung
-rw-r--r-- | yt_dlp/extractor/_extractors.py | 1 | ||||
-rw-r--r-- | yt_dlp/extractor/tiktok.py | 40 |
2 files changed, 41 insertions, 0 deletions
diff --git a/yt_dlp/extractor/_extractors.py b/yt_dlp/extractor/_extractors.py index 53ec29364..7a390a8d2 100644 --- a/yt_dlp/extractor/_extractors.py +++ b/yt_dlp/extractor/_extractors.py @@ -1890,6 +1890,7 @@ from .tiktok import ( TikTokEffectIE, TikTokTagIE, TikTokVMIE, + TikTokLiveIE, DouyinIE, ) from .tinypic import TinyPicIE diff --git a/yt_dlp/extractor/tiktok.py b/yt_dlp/extractor/tiktok.py index 709d944dc..cc96de364 100644 --- a/yt_dlp/extractor/tiktok.py +++ b/yt_dlp/extractor/tiktok.py @@ -11,6 +11,7 @@ from ..utils import ( HEADRequest, LazyList, UnsupportedError, + UserNotLive, get_element_by_id, get_first, int_or_none, @@ -980,3 +981,42 @@ class TikTokVMIE(InfoExtractor): if self.suitable(new_url): # Prevent infinite loop in case redirect fails raise UnsupportedError(new_url) return self.url_result(new_url) + + +class TikTokLiveIE(InfoExtractor): + _VALID_URL = r'https?://(?:www\.)?tiktok\.com/@(?P<id>[\w\.-]+)/live' + IE_NAME = 'tiktok:live' + + _TESTS = [{ + 'url': 'https://www.tiktok.com/@iris04201/live', + 'only_matching': True, + }] + + def _real_extract(self, url): + uploader = self._match_id(url) + webpage = self._download_webpage(url, uploader, headers={'User-Agent': 'User-Agent:Mozilla/5.0'}) + room_id = self._html_search_regex(r'snssdk\d*://live\?room_id=(\d+)', webpage, 'room ID', default=None) + if not room_id: + raise UserNotLive(video_id=uploader) + live_info = traverse_obj(self._download_json( + 'https://www.tiktok.com/api/live/detail/', room_id, query={ + 'aid': '1988', + 'roomID': room_id, + }), 'LiveRoomInfo', expected_type=dict, default={}) + + if 'status' not in live_info: + raise ExtractorError('Unexpected response from TikTok API') + # status = 2 if live else 4 + if not int_or_none(live_info['status']) == 2: + raise UserNotLive(video_id=uploader) + + return { + 'id': room_id, + 'title': live_info.get('title') or self._html_search_meta(['og:title', 'twitter:title'], webpage, default=''), + 'uploader': uploader, + 'uploader_id': traverse_obj(live_info, ('ownerInfo', 'id')), + 'creator': traverse_obj(live_info, ('ownerInfo', 'nickname')), + 'concurrent_view_count': traverse_obj(live_info, ('liveRoomStats', 'userCount'), expected_type=int), + 'formats': self._extract_m3u8_formats(live_info['liveUrl'], room_id, 'mp4', live=True), + 'is_live': True, + } |