2 from __future__
import unicode_literals
4 from datetime
import datetime
10 from .common
import InfoExtractor
12 ExtractorError
, std_headers
,
17 from ..compat
import (
19 compat_urllib_parse_urlencode
,
24 class MildomBaseIE(InfoExtractor
):
26 _DISPATCHER_CONFIG
= None
28 def _call_api(self
, url
, video_id
, query
={}, note
='Downloading JSON metadata', init
=False):
29 url
= update_url_query(url
, self
._common
_queries
(query
, init
=init
))
30 return self
._download
_json
(url
, video_id
, note
=note
)['body']
32 def _common_queries(self
, query
={}, init
=False):
33 dc
= self
._fetch
_dispatcher
_config
()
35 'timestamp': self
.iso_timestamp(),
36 '__guest_id': '' if init
else self
.guest_id(),
37 '__location': dc
['location'],
38 '__country': dc
['country'],
39 '__cluster': dc
['cluster'],
41 '__la': self
.lang_code(),
49 def _fetch_dispatcher_config(self
):
50 if not self
._DISPATCHER
_CONFIG
:
52 tmp
= self
._download
_json
(
53 'https://disp.mildom.com/serverListV2', 'initialization',
54 note
='Downloading dispatcher_config', data
=json
.dumps({
56 'data': base64
.b64encode(json
.dumps({
65 'rtm': self
.iso_timestamp(),
66 'ua': std_headers
['User-Agent'],
67 }).encode('utf8')).decode('utf8').replace('\n', ''),
69 self
._DISPATCHER
_CONFIG
= self
._parse
_json
(base64
.b64decode(tmp
['data']), 'initialization')
70 except ExtractorError
:
71 self
._DISPATCHER
_CONFIG
= self
._download
_json
(
72 'https://bookish-octo-barnacle.vercel.app/api/mildom/dispatcher_config', 'initialization',
73 note
='Downloading dispatcher_config fallback')
74 return self
._DISPATCHER
_CONFIG
78 'new Date().toISOString()'
79 return datetime
.utcnow().isoformat()[0:-3] + 'Z'
85 self
._GUEST
_ID
= try_get(
87 lambda x
: x
._call
_api
(
88 'https://cloudac.mildom.com/nonolive/gappserv/guest/h5init', 'initialization',
89 note
='Downloading guest token', init
=True)['guest_id'] or None,
90 lambda x
: x
._get
_cookies
('https://www.mildom.com').get('gid').value
,
91 lambda x
: x
._get
_cookies
('https://m.mildom.com').get('gid').value
,
100 class MildomIE(MildomBaseIE
):
102 IE_DESC
= 'Record ongoing live by specific user in Mildom'
103 _VALID_URL
= r
'https?://(?:(?:www|m)\.)mildom\.com/(?P<id>\d+)'
105 def _real_extract(self
, url
):
106 video_id
= self
._match
_id
(url
)
107 url
= 'https://www.mildom.com/%s' % video_id
109 webpage
= self
._download
_webpage
(url
, video_id
)
111 enterstudio
= self
._call
_api
(
112 'https://cloudac.mildom.com/nonolive/gappserv/live/enterstudio', video_id
,
113 note
='Downloading live metadata', query
={'user_id': video_id}
)
114 result_video_id
= enterstudio
.get('log_id', video_id
)
118 lambda x
: self
._html
_search
_meta
('twitter:description', webpage
),
119 lambda x
: x
['anchor_intro'],
121 description
= try_get(
123 lambda x
: x
['intro'],
124 lambda x
: x
['live_intro'],
128 lambda x
: self
._html
_search
_meta
('twitter:title', webpage
),
129 lambda x
: x
['loginname'],
132 servers
= self
._call
_api
(
133 'https://cloudac.mildom.com/nonolive/gappserv/live/liveserver', result_video_id
,
134 note
='Downloading live server list', query
={
136 'live_server_type': 'hls',
139 stream_query
= self
._common
_queries
({
140 'streamReqId': random_uuidv4(),
143 m3u8_url
= update_url_query(servers
['stream_server'] + '/%s_master.m3u8' % video_id
, stream_query
)
144 formats
= self
._extract
_m
3u8_formats
(m3u8_url
, result_video_id
, 'mp4', headers
={
145 'Referer': 'https://www.mildom.com/',
146 'Origin': 'https://www.mildom.com',
147 }, note
='Downloading m3u8 information')
148 del stream_query
['streamReqId'], stream_query
['timestamp']
150 # Uses https://github.com/nao20010128nao/bookish-octo-barnacle by @nao20010128nao as a proxy
151 parsed
= compat_urlparse
.urlparse(fmt
['url'])
152 parsed
= parsed
._replace
(
153 netloc
='bookish-octo-barnacle.vercel.app',
154 query
=compat_urllib_parse_urlencode(stream_query
, True),
155 path
='/api/mildom' + parsed
.path
)
156 fmt
['url'] = compat_urlparse
.urlunparse(parsed
)
158 self
._sort
_formats
(formats
)
161 'id': result_video_id
,
163 'description': description
,
164 'uploader': uploader
,
165 'uploader_id': video_id
,
171 class MildomVodIE(MildomBaseIE
):
172 IE_NAME
= 'mildom:vod'
173 IE_DESC
= 'Download a VOD in Mildom'
174 _VALID_URL
= r
'https?://(?:(?:www|m)\.)mildom\.com/playback/(?P<user_id>\d+)/(?P<id>(?P=user_id)-[a-zA-Z0-9]+)'
176 def _real_extract(self
, url
):
177 m
= re
.match(self
._VALID
_URL
, url
)
178 user_id
, video_id
= m
.group('user_id'), m
.group('id')
179 url
= 'https://www.mildom.com/playback/%s/%s' % (user_id
, video_id
)
181 webpage
= self
._download
_webpage
(url
, video_id
)
183 autoplay
= self
._call
_api
(
184 'https://cloudac.mildom.com/nonolive/videocontent/playback/getPlaybackDetail', video_id
,
185 note
='Downloading playback metadata', query
={
191 lambda x
: self
._html
_search
_meta
('og:description', webpage
),
192 lambda x
: x
['title'],
194 description
= try_get(
196 lambda x
: x
['video_intro'],
200 lambda x
: x
['author_info']['login_name'],
204 'url': autoplay
['audio_url'],
205 'format_id': 'audio',
206 'protocol': 'm3u8_native',
211 for fmt
in autoplay
['video_link']:
212 video_formats
.append({
213 'format_id': 'video-%s' % fmt
['name'],
215 'protocol': 'm3u8_native',
216 'width': fmt
['level'] * autoplay
['video_width'] // autoplay
['video_height'],
217 'height': fmt
['level'],
222 stream_query
= self
._common
_queries
({
225 del stream_query
['timestamp']
226 formats
= audio_formats
+ video_formats
229 parsed
= compat_urlparse
.urlparse(fmt
['url'])
230 stream_query
['path'] = parsed
.path
[5:]
231 parsed
= parsed
._replace
(
232 netloc
='bookish-octo-barnacle.vercel.app',
233 query
=compat_urllib_parse_urlencode(stream_query
, True),
234 path
='/api/mildom/vod2/proxy')
235 fmt
['url'] = compat_urlparse
.urlunparse(parsed
)
237 self
._sort
_formats
(formats
)
242 'description': description
,
243 'uploader': uploader
,
244 'uploader_id': user_id
,
249 class MildomUserVodIE(MildomBaseIE
):
250 IE_NAME
= 'mildom:user:vod'
251 IE_DESC
= 'Download all VODs from specific user in Mildom'
252 _VALID_URL
= r
'https?://(?:(?:www|m)\.)mildom\.com/profile/(?P<id>\d+)'
254 'url': 'https://www.mildom.com/profile/10093333',
257 'title': 'Uploads from ねこばたけ',
259 'playlist_mincount': 351,
262 def _real_extract(self
, url
):
263 user_id
= self
._match
_id
(url
)
265 self
.report_warning('To download ongoing live, please use "https://www.mildom.com/%s" instead. This will list up VODs belonging to user.' % user_id
)
267 profile
= self
._call
_api
(
268 'https://cloudac.mildom.com/nonolive/gappserv/user/profileV2', user_id
,
269 query
={'user_id': user_id}
, note
='Downloading user profile')['user_info']
272 for page
in itertools
.count(1):
273 reply
= self
._call
_api
(
274 'https://cloudac.mildom.com/nonolive/videocontent/profile/playbackList',
275 user_id
, note
='Downloading page %d' % page
, query
={
282 results
.extend('https://www.mildom.com/playback/%s/%s' % (user_id
, x
['v_id']) for x
in reply
)
283 return self
.playlist_result([
284 self
.url_result(u
, ie
=MildomVodIE
.ie_key()) for u
in results
285 ], user_id
, 'Uploads from %s' % profile
['loginname'])