[ie/dropout] Fix extraction (#12102)
[yt-dlp.git] / yt_dlp / extractor / epidemicsound.py
blob75b0f052b22808722ac125bf8c436e3887ca9069
1 from .common import InfoExtractor
2 from ..utils import (
3 float_or_none,
4 int_or_none,
5 join_nonempty,
6 orderedSet,
7 parse_iso8601,
8 parse_qs,
9 parse_resolution,
10 str_or_none,
11 traverse_obj,
12 url_or_none,
16 class EpidemicSoundIE(InfoExtractor):
17 _VALID_URL = r'https?://(?:www\.)?epidemicsound\.com/(?:(?P<sfx>sound-effects/tracks)|track)/(?P<id>[0-9a-zA-Z-]+)'
18 _TESTS = [{
19 'url': 'https://www.epidemicsound.com/track/yFfQVRpSPz/',
20 'md5': 'd98ff2ddb49e8acab9716541cbc9dfac',
21 'info_dict': {
22 'id': '45014',
23 'display_id': 'yFfQVRpSPz',
24 'ext': 'mp3',
25 'title': 'Door Knock Door 1',
26 'alt_title': 'Door Knock Door 1',
27 'tags': ['foley', 'door', 'knock', 'glass', 'window', 'glass door knock'],
28 'categories': ['Misc. Door'],
29 'duration': 1,
30 'thumbnail': 'https://cdn.epidemicsound.com/curation-assets/commercial-release-cover-images/default-sfx/3000x3000.jpg',
31 'timestamp': 1415320353,
32 'upload_date': '20141107',
34 }, {
35 'url': 'https://www.epidemicsound.com/track/mj8GTTwsZd/',
36 'md5': 'c82b745890f9baf18dc2f8d568ee3830',
37 'info_dict': {
38 'id': '148700',
39 'display_id': 'mj8GTTwsZd',
40 'ext': 'mp3',
41 'title': 'Noplace',
42 'tags': ['liquid drum n bass', 'energetic'],
43 'categories': ['drum and bass'],
44 'duration': 237,
45 'timestamp': 1694426482,
46 'thumbnail': 'https://cdn.epidemicsound.com/curation-assets/commercial-release-cover-images/11138/3000x3000.jpg',
47 'upload_date': '20230911',
48 'release_timestamp': 1700535606,
49 'release_date': '20231121',
51 }, {
52 'url': 'https://www.epidemicsound.com/sound-effects/tracks/2f02f54b-9faa-4daf-abac-1cfe9e9cef69/',
53 'md5': '35d7cf05bd8b614a84f0495a05de9388',
54 'info_dict': {
55 'id': '208931',
56 'ext': 'mp3',
57 'upload_date': '20240603',
58 'timestamp': 1717436529,
59 'categories': ['appliance'],
60 'display_id': '6b2NXLURPr',
61 'duration': 1.0,
62 'title': 'Oven, Grill, Door Open 01',
63 'thumbnail': 'https://cdn.epidemicsound.com/curation-assets/commercial-release-cover-images/default-sfx/3000x3000.jpg',
67 @staticmethod
68 def _epidemic_parse_thumbnail(url: str):
69 if not url_or_none(url):
70 return None
72 return {
73 'url': url,
74 **(traverse_obj(url, ({parse_qs}, {
75 'width': ('width', 0, {int_or_none}),
76 'height': ('height', 0, {int_or_none}),
77 })) or parse_resolution(url)),
80 @staticmethod
81 def _epidemic_fmt_or_none(f):
82 if not f.get('format'):
83 f['format'] = f.get('format_id')
84 elif not f.get('format_id'):
85 f['format_id'] = f['format']
86 if not f['url'] or not f['format']:
87 return None
88 if f.get('format_note'):
89 f['format_note'] = f'track ID {f["format_note"]}'
90 if f['format'] != 'full':
91 f['preference'] = -2
92 return f
94 def _real_extract(self, url):
95 video_id, is_sfx = self._match_valid_url(url).group('id', 'sfx')
96 json_data = self._download_json(join_nonempty(
97 'https://www.epidemicsound.com/json/track',
98 is_sfx and 'kosmos-id', video_id, delim='/'), video_id)
100 thumbnails = traverse_obj(json_data, [('imageUrl', 'cover')])
101 thumb_base_url = traverse_obj(json_data, ('coverArt', 'baseUrl', {url_or_none}))
102 if thumb_base_url:
103 thumbnails.extend(traverse_obj(json_data, (
104 'coverArt', 'sizes', ..., {thumb_base_url.__add__})))
106 return traverse_obj(json_data, {
107 'id': ('id', {str_or_none}),
108 'display_id': ('publicSlug', {str}),
109 'title': ('title', {str}),
110 'alt_title': ('oldTitle', {str}),
111 'duration': ('length', {float_or_none}),
112 'timestamp': ('added', {parse_iso8601}),
113 'release_timestamp': ('releaseDate', {parse_iso8601}),
114 'categories': ('genres', ..., 'tag', {str}),
115 'tags': ('metadataTags', ..., {str}),
116 'age_limit': ('isExplicit', {lambda b: 18 if b else None}),
117 'thumbnails': ({lambda _: thumbnails}, {orderedSet}, ..., {self._epidemic_parse_thumbnail}),
118 'formats': ('stems', {dict.items}, ..., {
119 'format': (0, {str_or_none}),
120 'format_note': (1, 's3TrackId', {str_or_none}),
121 'format_id': (1, 'stemType', {str}),
122 'url': (1, 'lqMp3Url', {url_or_none}),
123 }, {self._epidemic_fmt_or_none}),