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