]>
Commit | Line | Data |
---|---|---|
421ddcb8 C |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | from .common import InfoExtractor | |
5 | from ..utils import ( | |
421ddcb8 C |
6 | try_get, |
7 | unified_timestamp | |
8 | ) | |
9 | ||
10 | ||
11 | class SovietsClosetBaseIE(InfoExtractor): | |
12 | MEDIADELIVERY_REFERER = {'Referer': 'https://iframe.mediadelivery.net/'} | |
13 | ||
14 | def parse_nuxt_jsonp(self, nuxt_jsonp_url, video_id, name): | |
15 | nuxt_jsonp = self._download_webpage(nuxt_jsonp_url, video_id, note=f'Downloading {name} __NUXT_JSONP__') | |
66f4c04e | 16 | return self._search_nuxt_data(nuxt_jsonp, video_id, '__NUXT_JSONP__') |
421ddcb8 C |
17 | |
18 | def video_meta(self, video_id, game_name, category_name, episode_number, stream_date): | |
19 | title = game_name | |
20 | if category_name and category_name != 'Misc': | |
21 | title += f' - {category_name}' | |
22 | if episode_number: | |
23 | title += f' #{episode_number}' | |
24 | ||
25 | timestamp = unified_timestamp(stream_date) | |
26 | ||
27 | return { | |
28 | 'id': video_id, | |
29 | 'title': title, | |
30 | 'http_headers': self.MEDIADELIVERY_REFERER, | |
31 | 'uploader': 'SovietWomble', | |
32 | 'creator': 'SovietWomble', | |
33 | 'release_timestamp': timestamp, | |
34 | 'timestamp': timestamp, | |
35 | 'uploader_id': 'SovietWomble', | |
36 | 'uploader_url': 'https://www.twitch.tv/SovietWomble', | |
37 | 'was_live': True, | |
38 | 'availability': 'public', | |
39 | 'series': game_name, | |
40 | 'season': category_name, | |
41 | 'episode_number': episode_number, | |
42 | } | |
43 | ||
44 | ||
45 | class SovietsClosetIE(SovietsClosetBaseIE): | |
46 | _VALID_URL = r'https?://(?:www\.)?sovietscloset\.com/video/(?P<id>[0-9]+)/?' | |
47 | _TESTS = [ | |
48 | { | |
49 | 'url': 'https://sovietscloset.com/video/1337', | |
50 | 'md5': '11e58781c4ca5b283307aa54db5b3f93', | |
51 | 'info_dict': { | |
52 | 'id': '1337', | |
53 | 'ext': 'mp4', | |
54 | 'title': 'The Witcher #13', | |
55 | 'thumbnail': r're:^https?://.*\.b-cdn\.net/2f0cfbf4-3588-43a9-a7d6-7c9ea3755e67/thumbnail\.jpg$', | |
56 | 'uploader': 'SovietWomble', | |
57 | 'creator': 'SovietWomble', | |
58 | 'release_timestamp': 1492091580, | |
59 | 'release_date': '20170413', | |
60 | 'timestamp': 1492091580, | |
61 | 'upload_date': '20170413', | |
62 | 'uploader_id': 'SovietWomble', | |
63 | 'uploader_url': 'https://www.twitch.tv/SovietWomble', | |
3cf4b91d | 64 | 'duration': 7007, |
421ddcb8 C |
65 | 'was_live': True, |
66 | 'availability': 'public', | |
67 | 'series': 'The Witcher', | |
68 | 'season': 'Misc', | |
69 | 'episode_number': 13, | |
08d30158 | 70 | 'episode': 'Episode 13', |
421ddcb8 C |
71 | }, |
72 | }, | |
73 | { | |
74 | 'url': 'https://sovietscloset.com/video/1105', | |
75 | 'md5': '578b1958a379e7110ba38697042e9efb', | |
76 | 'info_dict': { | |
77 | 'id': '1105', | |
78 | 'ext': 'mp4', | |
79 | 'title': 'Arma 3 - Zeus Games #3', | |
80 | 'uploader': 'SovietWomble', | |
81 | 'thumbnail': r're:^https?://.*\.b-cdn\.net/c0e5e76f-3a93-40b4-bf01-12343c2eec5d/thumbnail\.jpg$', | |
82 | 'uploader': 'SovietWomble', | |
83 | 'creator': 'SovietWomble', | |
84 | 'release_timestamp': 1461157200, | |
85 | 'release_date': '20160420', | |
86 | 'timestamp': 1461157200, | |
87 | 'upload_date': '20160420', | |
88 | 'uploader_id': 'SovietWomble', | |
89 | 'uploader_url': 'https://www.twitch.tv/SovietWomble', | |
3cf4b91d | 90 | 'duration': 8804, |
421ddcb8 C |
91 | 'was_live': True, |
92 | 'availability': 'public', | |
93 | 'series': 'Arma 3', | |
94 | 'season': 'Zeus Games', | |
95 | 'episode_number': 3, | |
08d30158 | 96 | 'episode': 'Episode 3', |
421ddcb8 C |
97 | }, |
98 | }, | |
99 | ] | |
100 | ||
101 | def _extract_bunnycdn_iframe(self, video_id, bunnycdn_id): | |
102 | iframe = self._download_webpage( | |
103 | f'https://iframe.mediadelivery.net/embed/5105/{bunnycdn_id}', | |
104 | video_id, note='Downloading BunnyCDN iframe', headers=self.MEDIADELIVERY_REFERER) | |
105 | ||
106 | m3u8_url = self._search_regex(r'(https?://.*?\.m3u8)', iframe, 'm3u8 url') | |
107 | thumbnail_url = self._search_regex(r'(https?://.*?thumbnail\.jpg)', iframe, 'thumbnail url') | |
108 | ||
109 | m3u8_formats = self._extract_m3u8_formats(m3u8_url, video_id, headers=self.MEDIADELIVERY_REFERER) | |
110 | self._sort_formats(m3u8_formats) | |
111 | ||
3cf4b91d C |
112 | if not m3u8_formats: |
113 | duration = None | |
114 | else: | |
115 | duration = self._extract_m3u8_vod_duration( | |
116 | m3u8_formats[0]['url'], video_id, headers=self.MEDIADELIVERY_REFERER) | |
117 | ||
421ddcb8 C |
118 | return { |
119 | 'formats': m3u8_formats, | |
120 | 'thumbnail': thumbnail_url, | |
3cf4b91d | 121 | 'duration': duration, |
421ddcb8 C |
122 | } |
123 | ||
124 | def _real_extract(self, url): | |
125 | video_id = self._match_id(url) | |
126 | webpage = self._download_webpage(url, video_id) | |
127 | ||
128 | static_assets_base = self._search_regex(r'staticAssetsBase:\"(.*?)\"', webpage, 'staticAssetsBase') | |
129 | static_assets_base = f'https://sovietscloset.com{static_assets_base}' | |
130 | ||
131 | stream = self.parse_nuxt_jsonp(f'{static_assets_base}/video/{video_id}/payload.js', video_id, 'video')['stream'] | |
132 | ||
133 | return { | |
134 | **self.video_meta( | |
135 | video_id=video_id, game_name=stream['game']['name'], | |
136 | category_name=try_get(stream, lambda x: x['subcategory']['name'], str), | |
137 | episode_number=stream.get('number'), stream_date=stream.get('date')), | |
138 | **self._extract_bunnycdn_iframe(video_id, stream['bunnyId']), | |
139 | } | |
140 | ||
141 | ||
142 | class SovietsClosetPlaylistIE(SovietsClosetBaseIE): | |
143 | _VALID_URL = r'https?://(?:www\.)?sovietscloset\.com/(?!video)(?P<id>[^#?]+)' | |
144 | _TESTS = [ | |
145 | ||
146 | { | |
147 | 'url': 'https://sovietscloset.com/The-Witcher', | |
148 | 'info_dict': { | |
149 | 'id': 'The-Witcher', | |
150 | 'title': 'The Witcher', | |
151 | }, | |
152 | 'playlist_mincount': 31, | |
153 | }, | |
154 | { | |
155 | 'url': 'https://sovietscloset.com/Arma-3/Zeus-Games', | |
156 | 'info_dict': { | |
157 | 'id': 'Arma-3/Zeus-Games', | |
158 | 'title': 'Arma 3 - Zeus Games', | |
159 | }, | |
160 | 'playlist_mincount': 3, | |
161 | }, | |
162 | { | |
163 | 'url': 'https://sovietscloset.com/arma-3/zeus-games/', | |
164 | 'info_dict': { | |
165 | 'id': 'arma-3/zeus-games', | |
166 | 'title': 'Arma 3 - Zeus Games', | |
167 | }, | |
168 | 'playlist_mincount': 3, | |
169 | }, | |
f6d8776d C |
170 | { |
171 | 'url': 'https://sovietscloset.com/Total-War-Warhammer', | |
172 | 'info_dict': { | |
173 | 'id': 'Total-War-Warhammer', | |
174 | 'title': 'Total War: Warhammer - Greenskins', | |
175 | }, | |
176 | 'playlist_mincount': 33, | |
177 | }, | |
421ddcb8 C |
178 | ] |
179 | ||
180 | def _real_extract(self, url): | |
181 | playlist_id = self._match_id(url) | |
182 | if playlist_id.endswith('/'): | |
183 | playlist_id = playlist_id[:-1] | |
184 | ||
185 | webpage = self._download_webpage(url, playlist_id) | |
186 | ||
187 | static_assets_base = self._search_regex(r'staticAssetsBase:\"(.*?)\"', webpage, 'staticAssetsBase') | |
188 | static_assets_base = f'https://sovietscloset.com{static_assets_base}' | |
189 | ||
190 | sovietscloset = self.parse_nuxt_jsonp(f'{static_assets_base}/payload.js', playlist_id, 'global')['games'] | |
191 | ||
192 | if '/' in playlist_id: | |
193 | game_slug, category_slug = playlist_id.lower().split('/') | |
194 | else: | |
195 | game_slug = playlist_id.lower() | |
196 | category_slug = 'misc' | |
197 | ||
198 | game = next(game for game in sovietscloset if game['slug'].lower() == game_slug) | |
f6d8776d C |
199 | category = next((cat for cat in game['subcategories'] if cat.get('slug', '').lower() == category_slug), |
200 | game['subcategories'][0]) | |
201 | category_slug = category.get('slug', '').lower() or category_slug | |
421ddcb8 C |
202 | playlist_title = game.get('name') or game_slug |
203 | if category_slug != 'misc': | |
204 | playlist_title += f' - {category.get("name") or category_slug}' | |
205 | entries = [{ | |
206 | **self.url_result(f'https://sovietscloset.com/video/{stream["id"]}', ie=SovietsClosetIE.ie_key()), | |
207 | **self.video_meta( | |
208 | video_id=stream['id'], game_name=game['name'], category_name=category.get('name'), | |
209 | episode_number=i + 1, stream_date=stream.get('date')), | |
210 | } for i, stream in enumerate(category['streams'])] | |
211 | ||
212 | return self.playlist_result(entries, playlist_id, playlist_title) |