diff options
| author | Brian Marks <bm1549@users.noreply.github.com> | 2023-02-02 11:58:21 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-02 16:58:21 +0000 | 
| commit | 37cbdfa0e7c9d00d450af32dc9cdaf93cbfc4576 (patch) | |
| tree | cc995be96039679bbea76f8c2c5400776df868c8 | |
| parent | 295736c9cba714fb5de7d1c3dd31d86e50091cf8 (diff) | |
[americastestkitchen] Add support for downloading entire series (#31493)
Also
* support new sites and URL patterns
* back-port from yt-dlp
Co-authored-by: dirkf <fieldhouse@gmx.net>
| -rw-r--r-- | youtube_dl/extractor/americastestkitchen.py | 115 | 
1 files changed, 88 insertions, 27 deletions
diff --git a/youtube_dl/extractor/americastestkitchen.py b/youtube_dl/extractor/americastestkitchen.py index be960c0f9..08d3604e9 100644 --- a/youtube_dl/extractor/americastestkitchen.py +++ b/youtube_dl/extractor/americastestkitchen.py @@ -15,7 +15,7 @@ from ..utils import (  class AmericasTestKitchenIE(InfoExtractor): -    _VALID_URL = r'https?://(?:www\.)?(?:americastestkitchen|cooks(?:country|illustrated))\.com/(?P<resource_type>episode|videos)/(?P<id>\d+)' +    _VALID_URL = r'https?://(?:www\.)?(?:americastestkitchen|cooks(?:country|illustrated))\.com/(?:cooks(?:country|illustrated)/)?(?P<resource_type>episode|videos)/(?P<id>\d+)'      _TESTS = [{          'url': 'https://www.americastestkitchen.com/episode/582-weeknight-japanese-suppers',          'md5': 'b861c3e365ac38ad319cfd509c30577f', @@ -23,15 +23,20 @@ class AmericasTestKitchenIE(InfoExtractor):              'id': '5b400b9ee338f922cb06450c',              'title': 'Japanese Suppers',              'ext': 'mp4', +            'display_id': 'weeknight-japanese-suppers',              'description': 'md5:64e606bfee910627efc4b5f050de92b3', -            'thumbnail': r're:^https?://', -            'timestamp': 1523318400, -            'upload_date': '20180410', -            'release_date': '20180410', +            'timestamp': 1523304000, +            'upload_date': '20180409', +            'release_date': '20180409',              'series': "America's Test Kitchen", +            'season': 'Season 18',              'season_number': 18,              'episode': 'Japanese Suppers',              'episode_number': 15, +            'duration': 1376, +            'thumbnail': r're:^https?://', +            'average_rating': 0, +            'view_count': int,          },          'params': {              'skip_download': True, @@ -44,15 +49,20 @@ class AmericasTestKitchenIE(InfoExtractor):              'id': '5fbe8c61bda2010001c6763b',              'title': 'Simple Chicken Dinner',              'ext': 'mp4', +            'display_id': 'atktv_2103_simple-chicken-dinner_full-episode_web-mp4',              'description': 'md5:eb68737cc2fd4c26ca7db30139d109e7', -            'thumbnail': r're:^https?://', -            'timestamp': 1610755200, -            'upload_date': '20210116', -            'release_date': '20210116', +            'timestamp': 1610737200, +            'upload_date': '20210115', +            'release_date': '20210115',              'series': "America's Test Kitchen", +            'season': 'Season 21',              'season_number': 21,              'episode': 'Simple Chicken Dinner',              'episode_number': 3, +            'duration': 1397, +            'thumbnail': r're:^https?://', +            'view_count': int, +            'average_rating': 0,          },          'params': {              'skip_download': True, @@ -61,6 +71,12 @@ class AmericasTestKitchenIE(InfoExtractor):          'url': 'https://www.americastestkitchen.com/videos/3420-pan-seared-salmon',          'only_matching': True,      }, { +        'url': 'https://www.americastestkitchen.com/cookscountry/episode/564-when-only-chocolate-will-do', +        'only_matching': True, +    }, { +        'url': 'https://www.americastestkitchen.com/cooksillustrated/videos/4478-beef-wellington', +        'only_matching': True, +    }, {          'url': 'https://www.cookscountry.com/episode/564-when-only-chocolate-will-do',          'only_matching': True,      }, { @@ -94,7 +110,7 @@ class AmericasTestKitchenIE(InfoExtractor):  class AmericasTestKitchenSeasonIE(InfoExtractor): -    _VALID_URL = r'https?://(?:www\.)?(?P<show>americastestkitchen|cookscountry)\.com/episodes/browse/season_(?P<id>\d+)' +    _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+)))'      _TESTS = [{          # ATK Season          'url': 'https://www.americastestkitchen.com/episodes/browse/season_1', @@ -105,48 +121,93 @@ class AmericasTestKitchenSeasonIE(InfoExtractor):          'playlist_count': 13,      }, {          # Cooks Country Season -        'url': 'https://www.cookscountry.com/episodes/browse/season_12', +        'url': 'https://www.americastestkitchen.com/cookscountry/episodes/browse/season_12',          'info_dict': {              'id': 'season_12',              'title': 'Season 12',          },          'playlist_count': 13, +    }, { +        # America's Test Kitchen Series +        'url': 'https://www.americastestkitchen.com/', +        'info_dict': { +            'id': 'americastestkitchen', +            'title': 'America\'s Test Kitchen', +        }, +        'playlist_count': 558, +    }, { +        # Cooks Country Series +        'url': 'https://www.americastestkitchen.com/cookscountry', +        'info_dict': { +            'id': 'cookscountry', +            'title': 'Cook\'s Country', +        }, +        'playlist_count': 199, +    }, { +        'url': 'https://www.americastestkitchen.com/cookscountry/', +        'only_matching': True, +    }, { +        'url': 'https://www.cookscountry.com/episodes/browse/season_12', +        'only_matching': True, +    }, { +        'url': 'https://www.cookscountry.com', +        'only_matching': True, +    }, { +        'url': 'https://www.americastestkitchen.com/cooksillustrated/', +        'only_matching': True, +    }, { +        'url': 'https://www.cooksillustrated.com', +        'only_matching': True,      }]      def _real_extract(self, url): -        show_name, season_number = re.match(self._VALID_URL, url).groups() -        season_number = int(season_number) +        match = re.match(self._VALID_URL, url).groupdict() +        show = match.get('show2') +        show_path = ('/' + show) if show else '' +        show = show or match['show'] +        season_number = int_or_none(match.get('season')) + +        slug, title = { +            'americastestkitchen': ('atk', 'America\'s Test Kitchen'), +            'cookscountry': ('cco', 'Cook\'s Country'), +            'cooksillustrated': ('cio', 'Cook\'s Illustrated'), +        }[show] -        slug = 'atk' if show_name == 'americastestkitchen' else 'cco' +        facet_filters = [ +            'search_document_klass:episode', +            'search_show_slug:' + slug, +        ] -        season = 'Season %d' % season_number +        if season_number: +            playlist_id = 'season_%d' % season_number +            playlist_title = 'Season %d' % season_number +            facet_filters.append('search_season_list:' + playlist_title) +        else: +            playlist_id = show +            playlist_title = title          season_search = self._download_json(              'https://y1fnzxui30-dsn.algolia.net/1/indexes/everest_search_%s_season_desc_production' % slug, -            season, headers={ -                'Origin': 'https://www.%s.com' % show_name, +            playlist_id, headers={ +                'Origin': 'https://www.americastestkitchen.com',                  'X-Algolia-API-Key': '8d504d0099ed27c1b73708d22871d805',                  'X-Algolia-Application-Id': 'Y1FNZXUI30',              }, query={ -                'facetFilters': json.dumps([ -                    'search_season_list:' + season, -                    'search_document_klass:episode', -                    'search_show_slug:' + slug, -                ]), -                'attributesToRetrieve': 'description,search_%s_episode_number,search_document_date,search_url,title' % slug, +                'facetFilters': json.dumps(facet_filters), +                'attributesToRetrieve': 'description,search_%s_episode_number,search_document_date,search_url,title,search_atk_episode_season' % slug,                  'attributesToHighlight': '',                  'hitsPerPage': 1000,              })          def entries():              for episode in (season_search.get('hits') or []): -                search_url = episode.get('search_url') +                search_url = episode.get('search_url')  # always formatted like '/episode/123-title-of-episode'                  if not search_url:                      continue                  yield {                      '_type': 'url', -                    'url': 'https://www.%s.com%s' % (show_name, search_url), -                    'id': try_get(episode, lambda e: e['objectID'].split('_')[-1]), +                    'url': 'https://www.americastestkitchen.com%s%s' % (show_path, search_url), +                    'id': try_get(episode, lambda e: e['objectID'].rsplit('_', 1)[-1]),                      'title': episode.get('title'),                      'description': episode.get('description'),                      'timestamp': unified_timestamp(episode.get('search_document_date')), @@ -156,4 +217,4 @@ class AmericasTestKitchenSeasonIE(InfoExtractor):                  }          return self.playlist_result( -            entries(), 'season_%d' % season_number, season) +            entries(), playlist_id, playlist_title)  | 
