]> jfr.im git - yt-dlp.git/blame - yt_dlp/extractor/sovietscloset.py
[extractor] Deprecate `_sort_formats`
[yt-dlp.git] / yt_dlp / extractor / sovietscloset.py
CommitLineData
421ddcb8
C
1from .common import InfoExtractor
2from ..utils import (
421ddcb8
C
3 try_get,
4 unified_timestamp
5)
6
7
8class 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
42class 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
138class 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)