1 from .common
import InfoExtractor
10 class MirrativBaseIE(InfoExtractor
):
11 def assert_error(self
, response
):
12 error_message
= traverse_obj(response
, ('status', 'error'))
14 raise ExtractorError(f
'Mirrativ says: {error_message}', expected
=True)
17 class MirrativIE(MirrativBaseIE
):
19 _VALID_URL
= r
'https?://(?:www\.)?mirrativ\.com/live/(?P<id>[^/?#&]+)'
22 'url': 'https://mirrativ.com/live/UQomuS7EMgHoxRHjEhNiHw',
24 'id': 'UQomuS7EMgHoxRHjEhNiHw',
25 'title': 'ねむいぃ、。『参加型』🔰jcが初めてやるCOD✨初見さん大歓迎💗',
27 'description': 'md5:bfcd8f77f2fab24c3c672e5620f3f16e',
28 'thumbnail': r
're:https?://.+',
29 'uploader': '# あ ち ゅ 。💡',
30 'uploader_id': '118572165',
33 'release_timestamp': 1646229192,
34 'timestamp': 1646229167,
39 'url': 'https://mirrativ.com/live/POxyuG1KmW2982lqlDTuPw',
40 'only_matching': True,
43 def _real_extract(self
, url
):
44 video_id
= self
._match
_id
(url
)
45 webpage
= self
._download
_webpage
(f
'https://www.mirrativ.com/live/{video_id}', video_id
)
46 live_response
= self
._download
_json
(f
'https://www.mirrativ.com/api/live/live?live_id={video_id}', video_id
)
47 self
.assert_error(live_response
)
49 hls_url
= dict_get(live_response
, ('archive_url_hls', 'streaming_url_hls'))
50 is_live
= bool(live_response
.get('is_live'))
52 raise ExtractorError('Neither archive nor live is available.', expected
=True)
54 formats
= self
._extract
_m
3u8_formats
(
56 ext
='mp4', entry_protocol
='m3u8_native',
57 m3u8_id
='hls', live
=is_live
)
61 'title': self
._og
_search
_title
(webpage
, default
=None) or self
._search
_regex
(
62 r
'<title>\s*(.+?) - Mirrativ\s*</title>', webpage
) or live_response
.get('title'),
64 'description': live_response
.get('description'),
66 'thumbnail': live_response
.get('image_url'),
67 'uploader': traverse_obj(live_response
, ('owner', 'name')),
68 'uploader_id': traverse_obj(live_response
, ('owner', 'user_id')),
69 'duration': try_get(live_response
, lambda x
: x
['ended_at'] - x
['started_at']) if not is_live
else None,
70 'view_count': live_response
.get('total_viewer_num'),
71 'release_timestamp': live_response
.get('started_at'),
72 'timestamp': live_response
.get('created_at'),
73 'was_live': bool(live_response
.get('is_archive')),
77 class MirrativUserIE(MirrativBaseIE
):
78 IE_NAME
= 'mirrativ:user'
79 _VALID_URL
= r
'https?://(?:www\.)?mirrativ\.com/user/(?P<id>\d+)'
82 # Live archive is available up to 3 days
83 # see: https://helpfeel.com/mirrativ/%E9%8C%B2%E7%94%BB-5e26d3ad7b59ef0017fb49ac (Japanese)
84 'url': 'https://www.mirrativ.com/user/110943130',
85 'note': 'multiple archives available',
86 'only_matching': True,
89 def _entries(self
, user_id
):
91 while page
is not None:
92 api_response
= self
._download
_json
(
93 f
'https://www.mirrativ.com/api/live/live_history?user_id={user_id}&page={page}', user_id
,
94 note
=f
'Downloading page {page}')
95 self
.assert_error(api_response
)
96 lives
= api_response
.get('lives')
100 if not live
.get('is_archive') and not live
.get('is_live'):
101 # neither archive nor live is available, so skip it
102 # or the service will ban your IP address for a while
104 live_id
= live
.get('live_id')
105 url
= f
'https://www.mirrativ.com/live/{live_id}'
106 yield self
.url_result(url
, video_id
=live_id
, video_title
=live
.get('title'))
107 page
= api_response
.get('next_page')
109 def _real_extract(self
, url
):
110 user_id
= self
._match
_id
(url
)
111 user_info
= self
._download
_json
(
112 f
'https://www.mirrativ.com/api/user/profile?user_id={user_id}', user_id
,
113 note
='Downloading user info', fatal
=False)
114 self
.assert_error(user_info
)
116 return self
.playlist_result(
117 self
._entries
(user_id
), user_id
,
118 user_info
.get('name'), user_info
.get('description'))