2 from __future__
import unicode_literals
6 from .common
import InfoExtractor
15 class TrovoBaseIE(InfoExtractor
):
16 _VALID_URL_BASE
= r
'https?://(?:www\.)?trovo\.live/'
17 _HEADERS
= {'Origin': 'https://trovo.live'}
19 def _extract_streamer_info(self
, data
):
20 streamer_info
= data
.get('streamerInfo') or {}
21 username
= streamer_info
.get('userName')
23 'uploader': streamer_info
.get('nickName'),
24 'uploader_id': str_or_none(streamer_info
.get('uid')),
25 'uploader_url': 'https://trovo.live/' + username
if username
else None,
29 class TrovoIE(TrovoBaseIE
):
30 _VALID_URL
= TrovoBaseIE
._VALID
_URL
_BASE
+ r
'(?!(?:clip|video)/)(?P<id>[^/?&#]+)'
32 def _real_extract(self
, url
):
33 username
= self
._match
_id
(url
)
34 live_info
= self
._download
_json
(
35 'https://gql.trovo.live/', username
, query
={
37 getLiveInfo(params: {userName: "%s"}) {
55 })['data']['getLiveInfo']
56 if live_info
.get('isLive') == 0:
57 raise ExtractorError('%s is offline' % username
, expected
=True)
58 program_info
= live_info
['programInfo']
59 program_id
= program_info
['id']
60 title
= self
._live
_title
(program_info
['title'])
63 for stream_info
in (program_info
.get('streamInfo') or []):
64 play_url
= stream_info
.get('playUrl')
67 format_id
= stream_info
.get('desc')
69 'format_id': format_id
,
70 'height': int_or_none(format_id
[:-1]) if format_id
else None,
72 'http_headers': self
._HEADERS
,
74 self
._sort
_formats
(formats
)
80 'thumbnail': program_info
.get('coverUrl'),
83 info
.update(self
._extract
_streamer
_info
(live_info
))
87 class TrovoVodIE(TrovoBaseIE
):
88 _VALID_URL
= TrovoBaseIE
._VALID
_URL
_BASE
+ r
'(?:clip|video)/(?P<id>[^/?&#]+)'
90 'url': 'https://trovo.live/video/ltv-100095501_100095501_1609596043',
92 'id': 'ltv-100095501_100095501_1609596043',
94 'title': 'Spontaner 12 Stunden Stream! - Ok Boomer!',
96 'timestamp': 1609640305,
97 'upload_date': '20210103',
98 'uploader_id': '100095501',
102 'comment_count': int,
103 'comments': 'mincount:8',
104 'categories': ['Grand Theft Auto V'],
107 'url': 'https://trovo.live/clip/lc-5285890810184026005',
108 'only_matching': True,
111 def _real_extract(self
, url
):
112 vid
= self
._match
_id
(url
)
113 resp
= self
._download
_json
(
114 'https://gql.trovo.live/', vid
, data
=json
.dumps([{
116 batchGetVodDetailInfo(params: {vids: ["%s"]}) {
122 getCommentList(params: {appInfo: {postID: "%s"}, pageSize: 1000000000, preview: {}}) {
135 }]).encode(), headers
={
136 'Content-Type': 'application/json',
138 vod_detail_info
= resp
[0]['data']['batchGetVodDetailInfo']['VodDetailInfos'][vid
]
139 vod_info
= vod_detail_info
['vodInfo']
140 title
= vod_info
['title']
142 language
= vod_info
.get('languageName')
144 for play_info
in (vod_info
.get('playInfos') or []):
145 play_url
= play_info
.get('playUrl')
148 format_id
= play_info
.get('desc')
151 'filesize': int_or_none(play_info
.get('fileSize')),
152 'format_id': format_id
,
153 'height': int_or_none(format_id
[:-1]) if format_id
else None,
154 'language': language
,
155 'protocol': 'm3u8_native',
156 'tbr': int_or_none(play_info
.get('bitrate')),
158 'http_headers': self
._HEADERS
,
160 self
._sort
_formats
(formats
)
162 category
= vod_info
.get('categoryName')
163 get_count
= lambda x
: int_or_none(vod_info
.get(x
+ 'Num'))
165 comment_list
= try_get(resp
, lambda x
: x
[1]['data']['getCommentList']['commentList'], list) or []
167 for comment
in comment_list
:
168 content
= comment
.get('content')
171 author
= comment
.get('author') or {}
172 parent
= comment
.get('parentID')
174 'author': author
.get('nickName'),
175 'author_id': str_or_none(author
.get('uid')),
176 'id': str_or_none(comment
.get('commentID')),
178 'timestamp': int_or_none(comment
.get('createdAt')),
179 'parent': 'root' if parent
== 0 else str_or_none(parent
),
186 'thumbnail': vod_info
.get('coverUrl'),
187 'timestamp': int_or_none(vod_info
.get('publishTs')),
188 'duration': int_or_none(vod_info
.get('duration')),
189 'view_count': get_count('watch'),
190 'like_count': get_count('like'),
191 'comment_count': get_count('comment'),
192 'comments': comments
,
193 'categories': [category
] if category
else None,
195 info
.update(self
._extract
_streamer
_info
(vod_detail_info
))