2 from __future__
import unicode_literals
4 from datetime
import datetime
9 from .common
import InfoExtractor
11 ExtractorError
, std_headers
,
16 from ..compat
import (
18 compat_urllib_parse_urlencode
,
23 class MildomBaseIE(InfoExtractor
):
25 _DISPATCHER_CONFIG
= None
27 def _call_api(self
, url
, video_id
, query
={}, note
='Downloading JSON metadata', init
=False):
28 url
= update_url_query(url
, self
._common
_queries
(query
, init
=init
))
29 return self
._download
_json
(url
, video_id
, note
=note
)['body']
31 def _common_queries(self
, query
={}, init
=False):
32 dc
= self
._fetch
_dispatcher
_config
()
34 'timestamp': self
.iso_timestamp(),
35 '__guest_id': '' if init
else self
.guest_id(),
36 '__location': dc
['location'],
37 '__country': dc
['country'],
38 '__cluster': dc
['cluster'],
40 '__la': self
.lang_code(),
48 def _fetch_dispatcher_config(self
):
49 if not self
._DISPATCHER
_CONFIG
:
51 tmp
= self
._download
_json
(
52 'https://disp.mildom.com/serverListV2', 'initialization',
53 note
='Downloading dispatcher_config', data
=json
.dumps({
55 'data': base64
.b64encode(json
.dumps({
64 'rtm': self
.iso_timestamp(),
65 'ua': std_headers
['User-Agent'],
66 }).encode('utf8')).decode('utf8').replace('\n', ''),
68 self
._DISPATCHER
_CONFIG
= self
._parse
_json
(base64
.b64decode(tmp
['data']), 'initialization')
69 except ExtractorError
:
70 self
._DISPATCHER
_CONFIG
= self
._download
_json
(
71 'https://bookish-octo-barnacle.vercel.app/api/dispatcher_config', 'initialization',
72 note
='Downloading dispatcher_config fallback')
73 return self
._DISPATCHER
_CONFIG
77 'new Date().toISOString()'
78 return datetime
.utcnow().isoformat()[0:-3] + 'Z'
84 self
._GUEST
_ID
= try_get(
86 lambda x
: x
._call
_api
(
87 'https://cloudac.mildom.com/nonolive/gappserv/guest/h5init', 'initialization',
88 note
='Downloading guest token', init
=True)['guest_id'] or None,
89 lambda x
: x
._get
_cookies
('https://www.mildom.com').get('gid').value
,
90 lambda x
: x
._get
_cookies
('https://m.mildom.com').get('gid').value
,
99 class MildomIE(MildomBaseIE
):
101 IE_DESC
= 'Record ongoing live by specific user in Mildom'
102 _VALID_URL
= r
'https?://(?:(?:www|m)\.)mildom\.com/(?P<id>\d+)'
104 def _real_extract(self
, url
):
105 video_id
= self
._match
_id
(url
)
106 url
= 'https://www.mildom.com/%s' % video_id
108 webpage
= self
._download
_webpage
(url
, video_id
)
110 enterstudio
= self
._call
_api
(
111 'https://cloudac.mildom.com/nonolive/gappserv/live/enterstudio', video_id
,
112 note
='Downloading live metadata', query
={'user_id': video_id}
)
116 lambda x
: self
._html
_search
_meta
('twitter:description', webpage
),
117 lambda x
: x
['anchor_intro'],
119 description
= try_get(
121 lambda x
: x
['intro'],
122 lambda x
: x
['live_intro'],
126 lambda x
: self
._html
_search
_meta
('twitter:title', webpage
),
127 lambda x
: x
['loginname'],
130 servers
= self
._call
_api
(
131 'https://cloudac.mildom.com/nonolive/gappserv/live/liveserver', video_id
,
132 note
='Downloading live server list', query
={
134 'live_server_type': 'hls',
137 stream_query
= self
._common
_queries
({
138 'streamReqId': random_uuidv4(),
141 m3u8_url
= update_url_query(servers
['stream_server'] + '/%s_master.m3u8' % video_id
, stream_query
)
142 formats
= self
._extract
_m
3u8_formats
(m3u8_url
, video_id
, 'mp4', headers
={
143 'Referer': 'https://www.mildom.com/',
144 'Origin': 'https://www.mildom.com',
145 }, note
='Downloading m3u8 information')
146 del stream_query
['streamReqId'], stream_query
['timestamp']
148 # Uses https://github.com/nao20010128nao/bookish-octo-barnacle by @nao20010128nao as a proxy
149 parsed
= compat_urlparse
.urlparse(fmt
['url'])
150 parsed
= parsed
._replace
(
151 netloc
='bookish-octo-barnacle.vercel.app',
152 query
=compat_urllib_parse_urlencode(stream_query
, True),
153 path
='/api' + parsed
.path
)
154 fmt
['url'] = compat_urlparse
.urlunparse(parsed
)
156 self
._sort
_formats
(formats
)
161 'description': description
,
162 'uploader': uploader
,
163 'uploader_id': video_id
,
169 class MildomVodIE(MildomBaseIE
):
170 IE_NAME
= 'mildom:vod'
171 IE_DESC
= 'Download a VOD in Mildom'
172 _VALID_URL
= r
'https?://(?:(?:www|m)\.)mildom\.com/playback/(?P<user_id>\d+)/(?P<id>(?P=user_id)-[a-zA-Z0-9]+)'
174 def _real_extract(self
, url
):
175 video_id
= self
._match
_id
(url
)
176 m
= self
._VALID
_URL
_RE
.match(url
)
177 user_id
= m
.group('user_id')
178 url
= 'https://www.mildom.com/playback/%s/%s' % (user_id
, video_id
)
180 webpage
= self
._download
_webpage
(url
, video_id
)
182 autoplay
= self
._call
_api
(
183 'https://cloudac.mildom.com/nonolive/videocontent/playback/getPlaybackDetail', video_id
,
184 note
='Downloading playback metadata', query
={
190 lambda x
: self
._html
_search
_meta
('og:description', webpage
),
191 lambda x
: x
['title'],
193 description
= try_get(
195 lambda x
: x
['video_intro'],
199 lambda x
: x
['author_info']['login_name'],
203 'url': autoplay
['audio_url'],
204 'format_id': 'audio',
205 'protocol': 'm3u8_native',
210 for fmt
in autoplay
['video_link']:
211 video_formats
.append({
212 'format_id': 'video-%s' % fmt
['name'],
214 'protocol': 'm3u8_native',
215 'width': fmt
['level'] * autoplay
['video_width'] // autoplay
['video_height'],
216 'height': fmt
['level'],
221 stream_query
= self
._common
_queries
({
224 del stream_query
['timestamp']
225 formats
= audio_formats
+ video_formats
228 parsed
= compat_urlparse
.urlparse(fmt
['url'])
229 stream_query
['path'] = parsed
.path
[5:]
230 parsed
= parsed
._replace
(
231 netloc
='bookish-octo-barnacle.vercel.app',
232 query
=compat_urllib_parse_urlencode(stream_query
, True),
233 path
='/api/vod2/proxy')
234 fmt
['url'] = compat_urlparse
.urlunparse(parsed
)
236 self
._sort
_formats
(formats
)
241 'description': description
,
242 'uploader': uploader
,
243 'uploader_id': user_id
,
248 class MildomUserVodIE(MildomBaseIE
):
249 IE_NAME
= 'mildom:user:vod'
250 IE_DESC
= 'Download all VODs from specific user in Mildom'
251 _VALID_URL
= r
'https?://(?:(?:www|m)\.)mildom\.com/profile/(?P<id>\d+)'
253 'url': 'https://www.mildom.com/profile/10093333',
256 'title': 'Uploads from ねこばたけ',
258 'playlist_mincount': 351,
261 def _real_extract(self
, url
):
262 user_id
= self
._match
_id
(url
)
264 self
._downloader
.report_warning('To download ongoing live, please use "https://www.mildom.com/%s" instead. This will list up VODs belonging to user.' % user_id
)
266 profile
= self
._call
_api
(
267 'https://cloudac.mildom.com/nonolive/gappserv/user/profileV2', user_id
,
268 query
={'user_id': user_id}
, note
='Downloading user profile')['user_info']
271 for page
in itertools
.count(1):
272 reply
= self
._call
_api
(
273 'https://cloudac.mildom.com/nonolive/videocontent/profile/playbackList',
274 user_id
, note
='Downloading page %d' % page
, query
={
281 results
.extend('https://www.mildom.com/playback/%s/%s' % (user_id
, x
['v_id']) for x
in reply
)
282 return self
.playlist_result([
283 self
.url_result(u
, ie
=MildomVodIE
.ie_key()) for u
in results
284 ], user_id
, 'Uploads from %s' % profile
['loginname'])