]>
Commit | Line | Data |
---|---|---|
1 | import json | |
2 | ||
3 | from .common import InfoExtractor | |
4 | from ..utils import ( | |
5 | clean_html, | |
6 | int_or_none, | |
7 | try_get, | |
8 | unified_strdate, | |
9 | unified_timestamp, | |
10 | ) | |
11 | ||
12 | ||
13 | class AmericasTestKitchenIE(InfoExtractor): | |
14 | _VALID_URL = r'https?://(?:www\.)?(?:americastestkitchen|cooks(?:country|illustrated))\.com/(?:cooks(?:country|illustrated)/)?(?P<resource_type>episode|videos)/(?P<id>\d+)' | |
15 | _TESTS = [{ | |
16 | 'url': 'https://www.americastestkitchen.com/episode/582-weeknight-japanese-suppers', | |
17 | 'md5': 'b861c3e365ac38ad319cfd509c30577f', | |
18 | 'info_dict': { | |
19 | 'id': '5b400b9ee338f922cb06450c', | |
20 | 'title': 'Japanese Suppers', | |
21 | 'ext': 'mp4', | |
22 | 'display_id': 'weeknight-japanese-suppers', | |
23 | 'description': 'md5:64e606bfee910627efc4b5f050de92b3', | |
24 | 'timestamp': 1523304000, | |
25 | 'upload_date': '20180409', | |
26 | 'release_date': '20180409', | |
27 | 'series': 'America\'s Test Kitchen', | |
28 | 'season': 'Season 18', | |
29 | 'episode': 'Japanese Suppers', | |
30 | 'season_number': 18, | |
31 | 'episode_number': 15, | |
32 | 'duration': 1376, | |
33 | 'thumbnail': r're:^https?://', | |
34 | 'average_rating': 0, | |
35 | 'view_count': int, | |
36 | }, | |
37 | 'params': { | |
38 | 'skip_download': True, | |
39 | }, | |
40 | }, { | |
41 | # Metadata parsing behaves differently for newer episodes (705) as opposed to older episodes (582 above) | |
42 | 'url': 'https://www.americastestkitchen.com/episode/705-simple-chicken-dinner', | |
43 | 'md5': '06451608c57651e985a498e69cec17e5', | |
44 | 'info_dict': { | |
45 | 'id': '5fbe8c61bda2010001c6763b', | |
46 | 'title': 'Simple Chicken Dinner', | |
47 | 'ext': 'mp4', | |
48 | 'display_id': 'atktv_2103_simple-chicken-dinner_full-episode_web-mp4', | |
49 | 'description': 'md5:eb68737cc2fd4c26ca7db30139d109e7', | |
50 | 'timestamp': 1610737200, | |
51 | 'upload_date': '20210115', | |
52 | 'release_date': '20210115', | |
53 | 'series': 'America\'s Test Kitchen', | |
54 | 'season': 'Season 21', | |
55 | 'episode': 'Simple Chicken Dinner', | |
56 | 'season_number': 21, | |
57 | 'episode_number': 3, | |
58 | 'duration': 1397, | |
59 | 'thumbnail': r're:^https?://', | |
60 | 'view_count': int, | |
61 | 'average_rating': 0, | |
62 | }, | |
63 | 'params': { | |
64 | 'skip_download': True, | |
65 | }, | |
66 | }, { | |
67 | 'url': 'https://www.americastestkitchen.com/videos/3420-pan-seared-salmon', | |
68 | 'only_matching': True, | |
69 | }, { | |
70 | 'url': 'https://www.americastestkitchen.com/cookscountry/episode/564-when-only-chocolate-will-do', | |
71 | 'only_matching': True, | |
72 | }, { | |
73 | 'url': 'https://www.americastestkitchen.com/cooksillustrated/videos/4478-beef-wellington', | |
74 | 'only_matching': True, | |
75 | }, { | |
76 | 'url': 'https://www.cookscountry.com/episode/564-when-only-chocolate-will-do', | |
77 | 'only_matching': True, | |
78 | }, { | |
79 | 'url': 'https://www.cooksillustrated.com/videos/4478-beef-wellington', | |
80 | 'only_matching': True, | |
81 | }] | |
82 | ||
83 | def _real_extract(self, url): | |
84 | resource_type, video_id = self._match_valid_url(url).groups() | |
85 | is_episode = resource_type == 'episode' | |
86 | if is_episode: | |
87 | resource_type = 'episodes' | |
88 | ||
89 | resource = self._download_json( | |
90 | f'https://www.americastestkitchen.com/api/v6/{resource_type}/{video_id}', video_id) | |
91 | video = resource['video'] if is_episode else resource | |
92 | episode = resource if is_episode else resource.get('episode') or {} | |
93 | ||
94 | return { | |
95 | '_type': 'url_transparent', | |
96 | 'url': 'https://player.zype.com/embed/{}.js?api_key=jZ9GUhRmxcPvX7M3SlfejB6Hle9jyHTdk2jVxG7wOHPLODgncEKVdPYBhuz9iWXQ'.format(video['zypeId']), | |
97 | 'ie_key': 'Zype', | |
98 | 'description': clean_html(video.get('description')), | |
99 | 'timestamp': unified_timestamp(video.get('publishDate')), | |
100 | 'release_date': unified_strdate(video.get('publishDate')), | |
101 | 'episode_number': int_or_none(episode.get('number')), | |
102 | 'season_number': int_or_none(episode.get('season')), | |
103 | 'series': try_get(episode, lambda x: x['show']['title']), | |
104 | 'episode': episode.get('title'), | |
105 | } | |
106 | ||
107 | ||
108 | class AmericasTestKitchenSeasonIE(InfoExtractor): | |
109 | _VALID_URL = r'https?://(?:www\.)?(?P<show>americastestkitchen|(?P<cooks>cooks(?:country|illustrated)))\.com(?:(?:/(?P<show2>cooks(?:country|illustrated)))?(?:/?$|(?<!ated)(?<!ated\.com)/episodes/browse/season_(?P<season>\d+)))' | |
110 | _TESTS = [{ | |
111 | # ATK Season | |
112 | 'url': 'https://www.americastestkitchen.com/episodes/browse/season_1', | |
113 | 'info_dict': { | |
114 | 'id': 'season_1', | |
115 | 'title': 'Season 1', | |
116 | }, | |
117 | 'playlist_count': 13, | |
118 | }, { | |
119 | # Cooks Country Season | |
120 | 'url': 'https://www.americastestkitchen.com/cookscountry/episodes/browse/season_12', | |
121 | 'info_dict': { | |
122 | 'id': 'season_12', | |
123 | 'title': 'Season 12', | |
124 | }, | |
125 | 'playlist_count': 13, | |
126 | }, { | |
127 | # America's Test Kitchen Series | |
128 | 'url': 'https://www.americastestkitchen.com/', | |
129 | 'info_dict': { | |
130 | 'id': 'americastestkitchen', | |
131 | 'title': 'America\'s Test Kitchen', | |
132 | }, | |
133 | 'playlist_count': 558, | |
134 | }, { | |
135 | # Cooks Country Series | |
136 | 'url': 'https://www.americastestkitchen.com/cookscountry', | |
137 | 'info_dict': { | |
138 | 'id': 'cookscountry', | |
139 | 'title': 'Cook\'s Country', | |
140 | }, | |
141 | 'playlist_count': 199, | |
142 | }, { | |
143 | 'url': 'https://www.americastestkitchen.com/cookscountry/', | |
144 | 'only_matching': True, | |
145 | }, { | |
146 | 'url': 'https://www.cookscountry.com/episodes/browse/season_12', | |
147 | 'only_matching': True, | |
148 | }, { | |
149 | 'url': 'https://www.cookscountry.com', | |
150 | 'only_matching': True, | |
151 | }, { | |
152 | 'url': 'https://www.americastestkitchen.com/cooksillustrated/', | |
153 | 'only_matching': True, | |
154 | }, { | |
155 | 'url': 'https://www.cooksillustrated.com', | |
156 | 'only_matching': True, | |
157 | }] | |
158 | ||
159 | def _real_extract(self, url): | |
160 | season_number, show1, show = self._match_valid_url(url).group('season', 'show', 'show2') | |
161 | show_path = ('/' + show) if show else '' | |
162 | show = show or show1 | |
163 | season_number = int_or_none(season_number) | |
164 | ||
165 | slug, title = { | |
166 | 'americastestkitchen': ('atk', 'America\'s Test Kitchen'), | |
167 | 'cookscountry': ('cco', 'Cook\'s Country'), | |
168 | 'cooksillustrated': ('cio', 'Cook\'s Illustrated'), | |
169 | }[show] | |
170 | ||
171 | facet_filters = [ | |
172 | 'search_document_klass:episode', | |
173 | 'search_show_slug:' + slug, | |
174 | ] | |
175 | ||
176 | if season_number: | |
177 | playlist_id = f'season_{season_number}' | |
178 | playlist_title = f'Season {season_number}' | |
179 | facet_filters.append('search_season_list:' + playlist_title) | |
180 | else: | |
181 | playlist_id = show | |
182 | playlist_title = title | |
183 | ||
184 | season_search = self._download_json( | |
185 | f'https://y1fnzxui30-dsn.algolia.net/1/indexes/everest_search_{slug}_season_desc_production', | |
186 | playlist_id, headers={ | |
187 | 'Origin': 'https://www.americastestkitchen.com', | |
188 | 'X-Algolia-API-Key': '8d504d0099ed27c1b73708d22871d805', | |
189 | 'X-Algolia-Application-Id': 'Y1FNZXUI30', | |
190 | }, query={ | |
191 | 'facetFilters': json.dumps(facet_filters), | |
192 | 'attributesToRetrieve': f'description,search_{slug}_episode_number,search_document_date,search_url,title,search_atk_episode_season', | |
193 | 'attributesToHighlight': '', | |
194 | 'hitsPerPage': 1000, | |
195 | }) | |
196 | ||
197 | def entries(): | |
198 | for episode in (season_search.get('hits') or []): | |
199 | search_url = episode.get('search_url') # always formatted like '/episode/123-title-of-episode' | |
200 | if not search_url: | |
201 | continue | |
202 | yield { | |
203 | '_type': 'url', | |
204 | 'url': f'https://www.americastestkitchen.com{show_path or ""}{search_url}', | |
205 | 'id': try_get(episode, lambda e: e['objectID'].split('_')[-1]), | |
206 | 'title': episode.get('title'), | |
207 | 'description': episode.get('description'), | |
208 | 'timestamp': unified_timestamp(episode.get('search_document_date')), | |
209 | 'season_number': season_number, | |
210 | 'episode_number': int_or_none(episode.get(f'search_{slug}_episode_number')), | |
211 | 'ie_key': AmericasTestKitchenIE.ie_key(), | |
212 | } | |
213 | ||
214 | return self.playlist_result( | |
215 | entries(), playlist_id, playlist_title) |