]>
Commit | Line | Data |
---|---|---|
eb4b5818 | 1 | import itertools |
47a85879 AU |
2 | |
3 | from .common import InfoExtractor | |
eb4b5818 S |
4 | from ..utils import ( |
5 | ExtractorError, | |
e0ddbd02 | 6 | format_field, |
eb4b5818 | 7 | int_or_none, |
f4f9f6d0 | 8 | str_or_none, |
eb4b5818 S |
9 | try_get, |
10 | ) | |
47a85879 | 11 | |
eb4b5818 | 12 | CDN_API_BASE = 'https://cdn.younow.com/php/api' |
add96eb9 | 13 | MOMENT_URL_FORMAT = f'{CDN_API_BASE}/moment/fetch/id=%s' |
47a85879 AU |
14 | |
15 | ||
eb4b5818 S |
16 | class YouNowLiveIE(InfoExtractor): |
17 | _VALID_URL = r'https?://(?:www\.)?younow\.com/(?P<id>[^/?#&]+)' | |
47a85879 AU |
18 | _TEST = { |
19 | 'url': 'https://www.younow.com/AmandaPadeezy', | |
20 | 'info_dict': { | |
21 | 'id': 'AmandaPadeezy', | |
22 | 'ext': 'mp4', | |
23 | 'is_live': True, | |
24 | 'title': 'March 26, 2017', | |
eb4b5818 | 25 | 'thumbnail': r're:^https?://.*\.jpg$', |
47a85879 AU |
26 | 'tags': ['girls'], |
27 | 'categories': ['girls'], | |
28 | 'uploader': 'AmandaPadeezy', | |
29 | 'uploader_id': '6716501', | |
30 | 'uploader_url': 'https://www.younow.com/AmandaPadeezy', | |
31 | 'creator': 'AmandaPadeezy', | |
eb4b5818 S |
32 | }, |
33 | 'skip': True, | |
47a85879 AU |
34 | } |
35 | ||
eb4b5818 S |
36 | @classmethod |
37 | def suitable(cls, url): | |
38 | return (False | |
39 | if YouNowChannelIE.suitable(url) or YouNowMomentIE.suitable(url) | |
add96eb9 | 40 | else super().suitable(url)) |
eb4b5818 | 41 | |
47a85879 AU |
42 | def _real_extract(self, url): |
43 | username = self._match_id(url) | |
eb4b5818 S |
44 | |
45 | data = self._download_json( | |
add96eb9 | 46 | f'https://api.younow.com/php/api/broadcast/info/curId=0/user={username}', username) |
eb4b5818 S |
47 | |
48 | if data.get('errorCode') != 0: | |
49 | raise ExtractorError(data['errorMsg'], expected=True) | |
50 | ||
51 | uploader = try_get( | |
52 | data, lambda x: x['user']['profileUrlString'], | |
add96eb9 | 53 | str) or username |
47a85879 AU |
54 | |
55 | return { | |
56 | 'id': uploader, | |
57 | 'is_live': True, | |
39ca3b5c | 58 | 'title': uploader, |
47a85879 AU |
59 | 'thumbnail': data.get('awsUrl'), |
60 | 'tags': data.get('tags'), | |
61 | 'categories': data.get('tags'), | |
62 | 'uploader': uploader, | |
63 | 'uploader_id': data.get('userId'), | |
add96eb9 | 64 | 'uploader_url': f'https://www.younow.com/{username}', |
47a85879 AU |
65 | 'creator': uploader, |
66 | 'view_count': int_or_none(data.get('viewers')), | |
67 | 'like_count': int_or_none(data.get('likes')), | |
68 | 'formats': [{ | |
add96eb9 | 69 | 'url': '{}/broadcast/videoPath/hls=1/broadcastId={}/channelId={}'.format(CDN_API_BASE, data['broadcastId'], data['userId']), |
47a85879 AU |
70 | 'ext': 'mp4', |
71 | 'protocol': 'm3u8', | |
72 | }], | |
73 | } | |
74 | ||
75 | ||
eb4b5818 S |
76 | def _extract_moment(item, fatal=True): |
77 | moment_id = item.get('momentId') | |
78 | if not moment_id: | |
79 | if not fatal: | |
80 | return | |
81 | raise ExtractorError('Unable to extract moment id') | |
82 | ||
add96eb9 | 83 | moment_id = str(moment_id) |
eb4b5818 | 84 | |
47a85879 | 85 | title = item.get('text') |
47a85879 | 86 | if not title: |
eb4b5818 S |
87 | title = 'YouNow %s' % ( |
88 | item.get('momentType') or item.get('titleType') or 'moment') | |
89 | ||
add96eb9 | 90 | uploader = try_get(item, lambda x: x['owner']['name'], str) |
eb4b5818 | 91 | uploader_id = try_get(item, lambda x: x['owner']['userId']) |
a70635b8 | 92 | uploader_url = format_field(uploader, None, 'https://www.younow.com/%s') |
47a85879 | 93 | |
add96eb9 | 94 | return { |
eb4b5818 S |
95 | 'extractor_key': 'YouNowMoment', |
96 | 'id': moment_id, | |
47a85879 AU |
97 | 'title': title, |
98 | 'view_count': int_or_none(item.get('views')), | |
99 | 'like_count': int_or_none(item.get('likes')), | |
100 | 'timestamp': int_or_none(item.get('created')), | |
eb4b5818 S |
101 | 'creator': uploader, |
102 | 'uploader': uploader, | |
f4f9f6d0 | 103 | 'uploader_id': str_or_none(uploader_id), |
eb4b5818 | 104 | 'uploader_url': uploader_url, |
47a85879 | 105 | 'formats': [{ |
add96eb9 | 106 | 'url': f'https://hls.younow.com/momentsplaylists/live/{moment_id}/{moment_id}.m3u8', |
47a85879 | 107 | 'ext': 'mp4', |
eb4b5818 | 108 | 'protocol': 'm3u8_native', |
47a85879 AU |
109 | }], |
110 | } | |
111 | ||
47a85879 AU |
112 | |
113 | class YouNowChannelIE(InfoExtractor): | |
114 | _VALID_URL = r'https?://(?:www\.)?younow\.com/(?P<id>[^/]+)/channel' | |
115 | _TEST = { | |
eb4b5818 | 116 | 'url': 'https://www.younow.com/its_Kateee_/channel', |
47a85879 | 117 | 'info_dict': { |
eb4b5818 | 118 | 'id': '14629760', |
add96eb9 | 119 | 'title': 'its_Kateee_ moments', |
47a85879 | 120 | }, |
eb4b5818 | 121 | 'playlist_mincount': 8, |
47a85879 AU |
122 | } |
123 | ||
eb4b5818 | 124 | def _entries(self, username, channel_id): |
47a85879 | 125 | created_before = 0 |
eb4b5818 S |
126 | for page_num in itertools.count(1): |
127 | if created_before is None: | |
47a85879 | 128 | break |
eb4b5818 | 129 | info = self._download_json( |
add96eb9 | 130 | f'{CDN_API_BASE}/moment/profile/channelId={channel_id}/createdBefore={created_before}/records=20', |
131 | username, note=f'Downloading moments page {page_num}') | |
eb4b5818 S |
132 | items = info.get('items') |
133 | if not items or not isinstance(items, list): | |
134 | break | |
135 | for item in items: | |
136 | if not isinstance(item, dict): | |
137 | continue | |
138 | item_type = item.get('type') | |
139 | if item_type == 'moment': | |
140 | entry = _extract_moment(item, fatal=False) | |
141 | if entry: | |
142 | yield entry | |
143 | elif item_type == 'collection': | |
144 | moments = item.get('momentsIds') | |
145 | if isinstance(moments, list): | |
146 | for moment_id in moments: | |
147 | m = self._download_json( | |
148 | MOMENT_URL_FORMAT % moment_id, username, | |
add96eb9 | 149 | note=f'Downloading {moment_id} moment JSON', |
eb4b5818 S |
150 | fatal=False) |
151 | if m and isinstance(m, dict) and m.get('item'): | |
152 | entry = _extract_moment(m['item']) | |
153 | if entry: | |
154 | yield entry | |
155 | created_before = int_or_none(item.get('created')) | |
47a85879 | 156 | |
eb4b5818 S |
157 | def _real_extract(self, url): |
158 | username = self._match_id(url) | |
add96eb9 | 159 | channel_id = str(self._download_json( |
160 | f'https://api.younow.com/php/api/broadcast/info/curId=0/user={username}', | |
161 | username, note='Downloading user information')['userId']) | |
eb4b5818 S |
162 | return self.playlist_result( |
163 | self._entries(username, channel_id), channel_id, | |
add96eb9 | 164 | f'{username} moments') |
47a85879 AU |
165 | |
166 | ||
167 | class YouNowMomentIE(InfoExtractor): | |
eb4b5818 | 168 | _VALID_URL = r'https?://(?:www\.)?younow\.com/[^/]+/(?P<id>[^/?#&]+)' |
47a85879 AU |
169 | _TEST = { |
170 | 'url': 'https://www.younow.com/GABO.../20712117/36319236/3b316doc/m', | |
eb4b5818 | 171 | 'md5': 'a30c70eadb9fb39a1aa3c8c0d22a0807', |
47a85879 AU |
172 | 'info_dict': { |
173 | 'id': '20712117', | |
174 | 'ext': 'mp4', | |
175 | 'title': 'YouNow capture', | |
eb4b5818 S |
176 | 'view_count': int, |
177 | 'like_count': int, | |
47a85879 | 178 | 'timestamp': 1490432040, |
47a85879 AU |
179 | 'upload_date': '20170325', |
180 | 'uploader': 'GABO...', | |
f4f9f6d0 | 181 | 'uploader_id': '35917228', |
47a85879 AU |
182 | }, |
183 | } | |
184 | ||
eb4b5818 S |
185 | @classmethod |
186 | def suitable(cls, url): | |
187 | return (False | |
188 | if YouNowChannelIE.suitable(url) | |
add96eb9 | 189 | else super().suitable(url)) |
eb4b5818 | 190 | |
47a85879 | 191 | def _real_extract(self, url): |
eb4b5818 S |
192 | video_id = self._match_id(url) |
193 | item = self._download_json(MOMENT_URL_FORMAT % video_id, video_id) | |
194 | return _extract_moment(item['item']) |