]>
Commit | Line | Data |
---|---|---|
1 | import hashlib | |
2 | import random | |
3 | ||
4 | from ..compat import compat_str | |
5 | from .common import InfoExtractor | |
6 | from ..utils import ( | |
7 | clean_html, | |
8 | int_or_none, | |
9 | try_get, | |
10 | ) | |
11 | ||
12 | ||
13 | class JamendoIE(InfoExtractor): | |
14 | _VALID_URL = r'''(?x) | |
15 | https?:// | |
16 | (?: | |
17 | licensing\.jamendo\.com/[^/]+| | |
18 | (?:www\.)?jamendo\.com | |
19 | ) | |
20 | /track/(?P<id>[0-9]+)(?:/(?P<display_id>[^/?#&]+))? | |
21 | ''' | |
22 | _TESTS = [{ | |
23 | 'url': 'https://www.jamendo.com/track/196219/stories-from-emona-i', | |
24 | 'md5': '6e9e82ed6db98678f171c25a8ed09ffd', | |
25 | 'info_dict': { | |
26 | 'id': '196219', | |
27 | 'display_id': 'stories-from-emona-i', | |
28 | 'ext': 'flac', | |
29 | # 'title': 'Maya Filipič - Stories from Emona I', | |
30 | 'title': 'Stories from Emona I', | |
31 | 'artist': 'Maya Filipič', | |
32 | 'album': 'Between two worlds', | |
33 | 'track': 'Stories from Emona I', | |
34 | 'duration': 210, | |
35 | 'thumbnail': 'https://usercontent.jamendo.com?type=album&id=29279&width=300&trackid=196219', | |
36 | 'timestamp': 1217438117, | |
37 | 'upload_date': '20080730', | |
38 | 'license': 'by-nc-nd', | |
39 | 'view_count': int, | |
40 | 'like_count': int, | |
41 | 'average_rating': int, | |
42 | 'tags': ['piano', 'peaceful', 'newage', 'strings', 'upbeat'], | |
43 | } | |
44 | }, { | |
45 | 'url': 'https://licensing.jamendo.com/en/track/1496667/energetic-rock', | |
46 | 'only_matching': True, | |
47 | }] | |
48 | ||
49 | def _call_api(self, resource, resource_id, fatal=True): | |
50 | path = '/api/%ss' % resource | |
51 | rand = compat_str(random.random()) | |
52 | return self._download_json( | |
53 | 'https://www.jamendo.com' + path, resource_id, fatal=fatal, query={ | |
54 | 'id[]': resource_id, | |
55 | }, headers={ | |
56 | 'X-Jam-Call': '$%s*%s~' % (hashlib.sha1((path + rand).encode()).hexdigest(), rand) | |
57 | })[0] | |
58 | ||
59 | def _real_extract(self, url): | |
60 | track_id, display_id = self._match_valid_url(url).groups() | |
61 | # webpage = self._download_webpage( | |
62 | # 'https://www.jamendo.com/track/' + track_id, track_id) | |
63 | # models = self._parse_json(self._html_search_regex( | |
64 | # r"data-bundled-models='([^']+)", | |
65 | # webpage, 'bundled models'), track_id) | |
66 | # track = models['track']['models'][0] | |
67 | track = self._call_api('track', track_id) | |
68 | title = track_name = track['name'] | |
69 | # get_model = lambda x: try_get(models, lambda y: y[x]['models'][0], dict) or {} | |
70 | # artist = get_model('artist') | |
71 | # artist_name = artist.get('name') | |
72 | # if artist_name: | |
73 | # title = '%s - %s' % (artist_name, title) | |
74 | # album = get_model('album') | |
75 | artist = self._call_api("artist", track.get('artistId'), fatal=False) | |
76 | album = self._call_api("album", track.get('albumId'), fatal=False) | |
77 | ||
78 | formats = [{ | |
79 | 'url': 'https://%s.jamendo.com/?trackid=%s&format=%s&from=app-97dab294' | |
80 | % (sub_domain, track_id, format_id), | |
81 | 'format_id': format_id, | |
82 | 'ext': ext, | |
83 | 'quality': quality, | |
84 | } for quality, (format_id, sub_domain, ext) in enumerate(( | |
85 | ('mp31', 'mp3l', 'mp3'), | |
86 | ('mp32', 'mp3d', 'mp3'), | |
87 | ('ogg1', 'ogg', 'ogg'), | |
88 | ('flac', 'flac', 'flac'), | |
89 | ))] | |
90 | ||
91 | urls = [] | |
92 | thumbnails = [] | |
93 | for covers in (track.get('cover') or {}).values(): | |
94 | for cover_id, cover_url in covers.items(): | |
95 | if not cover_url or cover_url in urls: | |
96 | continue | |
97 | urls.append(cover_url) | |
98 | size = int_or_none(cover_id.lstrip('size')) | |
99 | thumbnails.append({ | |
100 | 'id': cover_id, | |
101 | 'url': cover_url, | |
102 | 'width': size, | |
103 | 'height': size, | |
104 | }) | |
105 | ||
106 | tags = [] | |
107 | for tag in (track.get('tags') or []): | |
108 | tag_name = tag.get('name') | |
109 | if not tag_name: | |
110 | continue | |
111 | tags.append(tag_name) | |
112 | ||
113 | stats = track.get('stats') or {} | |
114 | license = track.get('licenseCC') or [] | |
115 | ||
116 | return { | |
117 | 'id': track_id, | |
118 | 'display_id': display_id, | |
119 | 'thumbnails': thumbnails, | |
120 | 'title': title, | |
121 | 'description': track.get('description'), | |
122 | 'duration': int_or_none(track.get('duration')), | |
123 | 'artist': artist.get('name'), | |
124 | 'track': track_name, | |
125 | 'album': album.get('name'), | |
126 | 'formats': formats, | |
127 | 'license': '-'.join(license) if license else None, | |
128 | 'timestamp': int_or_none(track.get('dateCreated')), | |
129 | 'view_count': int_or_none(stats.get('listenedAll')), | |
130 | 'like_count': int_or_none(stats.get('favorited')), | |
131 | 'average_rating': int_or_none(stats.get('averageNote')), | |
132 | 'tags': tags, | |
133 | } | |
134 | ||
135 | ||
136 | class JamendoAlbumIE(JamendoIE): # XXX: Do not subclass from concrete IE | |
137 | _VALID_URL = r'https?://(?:www\.)?jamendo\.com/album/(?P<id>[0-9]+)' | |
138 | _TESTS = [{ | |
139 | 'url': 'https://www.jamendo.com/album/121486/duck-on-cover', | |
140 | 'info_dict': { | |
141 | 'id': '121486', | |
142 | 'title': 'Duck On Cover', | |
143 | 'description': 'md5:c2920eaeef07d7af5b96d7c64daf1239', | |
144 | }, | |
145 | 'playlist': [{ | |
146 | 'md5': 'e1a2fcb42bda30dfac990212924149a8', | |
147 | 'info_dict': { | |
148 | 'id': '1032333', | |
149 | 'ext': 'flac', | |
150 | 'title': 'Warmachine', | |
151 | 'artist': 'Shearer', | |
152 | 'track': 'Warmachine', | |
153 | 'timestamp': 1368089771, | |
154 | 'upload_date': '20130509', | |
155 | 'view_count': int, | |
156 | 'thumbnail': 'https://usercontent.jamendo.com?type=album&id=121486&width=300&trackid=1032333', | |
157 | 'duration': 190, | |
158 | 'license': 'by', | |
159 | 'album': 'Duck On Cover', | |
160 | 'average_rating': 4, | |
161 | 'tags': ['rock', 'drums', 'bass', 'world', 'punk', 'neutral'], | |
162 | 'like_count': int, | |
163 | } | |
164 | }, { | |
165 | 'md5': '1f358d7b2f98edfe90fd55dac0799d50', | |
166 | 'info_dict': { | |
167 | 'id': '1032330', | |
168 | 'ext': 'flac', | |
169 | 'title': 'Without Your Ghost', | |
170 | 'artist': 'Shearer', | |
171 | 'track': 'Without Your Ghost', | |
172 | 'timestamp': 1368089771, | |
173 | 'upload_date': '20130509', | |
174 | 'duration': 192, | |
175 | 'tags': ['rock', 'drums', 'bass', 'world', 'punk'], | |
176 | 'album': 'Duck On Cover', | |
177 | 'thumbnail': 'https://usercontent.jamendo.com?type=album&id=121486&width=300&trackid=1032330', | |
178 | 'view_count': int, | |
179 | 'average_rating': 4, | |
180 | 'license': 'by', | |
181 | 'like_count': int, | |
182 | } | |
183 | }], | |
184 | 'params': { | |
185 | 'playlistend': 2 | |
186 | } | |
187 | }] | |
188 | ||
189 | def _real_extract(self, url): | |
190 | album_id = self._match_id(url) | |
191 | album = self._call_api('album', album_id) | |
192 | album_name = album.get('name') | |
193 | ||
194 | entries = [] | |
195 | for track in (album.get('tracks') or []): | |
196 | track_id = track.get('id') | |
197 | if not track_id: | |
198 | continue | |
199 | track_id = compat_str(track_id) | |
200 | entries.append({ | |
201 | '_type': 'url_transparent', | |
202 | 'url': 'https://www.jamendo.com/track/' + track_id, | |
203 | 'ie_key': JamendoIE.ie_key(), | |
204 | 'id': track_id, | |
205 | 'album': album_name, | |
206 | }) | |
207 | ||
208 | return self.playlist_result( | |
209 | entries, album_id, album_name, | |
210 | clean_html(try_get(album, lambda x: x['description']['en'], compat_str))) |