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