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