]>
Commit | Line | Data |
---|---|---|
67500bf9 | 1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | from .common import InfoExtractor | |
9e9bc793 | 5 | from .soundcloud import SoundcloudIE |
fdfefa1b | 6 | from ..utils import ExtractorError |
c9f08154 | 7 | |
67500bf9 | 8 | import time |
67500bf9 | 9 | |
10 | ||
11 | class AudiomackIE(InfoExtractor): | |
defaf19f | 12 | _VALID_URL = r'https?://(?:www\.)?audiomack\.com/(song)/(?P<id>[\w/-]+)' |
9e9bc793 | 13 | IE_NAME = 'audiomack' |
14 | _TESTS = [ | |
defaf19f | 15 | # audiomack |
9e9bc793 | 16 | { |
17 | 'url': 'http://www.audiomack.com/song/roosh-williams/extraordinary', | |
9e9bc793 | 18 | 'info_dict': |
19 | { | |
defaf19f YN |
20 | 'id': '310086', |
21 | "ext": "mp3", | |
22 | "artist": "Roosh Williams", | |
23 | 'title': 'Extraordinary' | |
9e9bc793 | 24 | } |
25 | }, | |
defaf19f | 26 | # audiomack through soundcloud |
9e9bc793 | 27 | { |
9095aa38 | 28 | 'add_ie': ['Soundcloud'], |
9e9bc793 | 29 | 'url': 'http://www.audiomack.com/song/xclusiveszone/take-kare', |
810fb84d PH |
30 | 'info_dict': { |
31 | 'id': '172419696', | |
32 | 'ext': 'mp3', | |
9095aa38 | 33 | 'description': 'md5:1fc3272ed7a635cce5be1568c2822997', |
9e9bc793 | 34 | 'title': 'Young Thug ft Lil Wayne - Take Kare', |
810fb84d PH |
35 | 'uploader': 'Young Thug World', |
36 | 'upload_date': '20141016', | |
9e9bc793 | 37 | } |
9095aa38 | 38 | }, |
9e9bc793 | 39 | ] |
67500bf9 | 40 | |
defaf19f YN |
41 | @staticmethod |
42 | def create_song_dictionary(api_response, album_url_tag, track_no=0): | |
43 | # All keys are the same in audiomack api and InfoExtractor format | |
44 | entry = {key: api_response[key] for key in ["title", "artist", "id", "url"] if key in api_response} | |
45 | # Fudge values in the face of missing metadata | |
46 | if "id" not in entry: | |
47 | entry["id"] = track_no | |
48 | if "title" not in entry: | |
49 | entry["title"] = album_url_tag | |
50 | return entry | |
51 | ||
67500bf9 | 52 | def _real_extract(self, url): |
defaf19f YN |
53 | # URLs end with [uploader name]/[uploader title] |
54 | # this title is whatever the user types in, and is rarely | |
55 | # the proper song title. Real metadata is in the api response | |
56 | album_url_tag = self._match_id(url) | |
67500bf9 | 57 | |
defaf19f | 58 | # Request the extended version of the api for extra fields like artist and title |
d3c72db8 | 59 | api_response = self._download_json( |
defaf19f YN |
60 | "http://www.audiomack.com/api/music/url/song/%s?extended=1&_=%d" % ( |
61 | album_url_tag, time.time()), | |
62 | album_url_tag) | |
fdfefa1b | 63 | |
defaf19f YN |
64 | # API is inconsistent with errors |
65 | if "url" not in api_response or not api_response["url"] or "error" in api_response: | |
66 | raise ExtractorError("Invalid url %s", url) | |
9e9bc793 | 67 | |
5f6a1245 | 68 | # Audiomack wraps a lot of soundcloud tracks in their branded wrapper |
defaf19f YN |
69 | # if so, pass the work off to the soundcloud extractor |
70 | if SoundcloudIE.suitable(api_response["url"]): | |
71 | return {'_type': 'url', 'url': api_response["url"], 'ie_key': 'Soundcloud'} | |
d3c72db8 | 72 | |
defaf19f | 73 | return self.create_song_dictionary(api_response, album_url_tag) |
d3c72db8 | 74 | |
defaf19f YN |
75 | |
76 | class AudiomackAlbumIE(InfoExtractor): | |
77 | _VALID_URL = r'https?://(?:www\.)?audiomack\.com/album/(?P<id>[\w/-]+)' | |
78 | IE_NAME = 'audiomack:album' | |
79 | _TESTS = [ | |
80 | # Standard album playlist | |
81 | { | |
82 | 'url': 'http://www.audiomack.com/album/flytunezcom/tha-tour-part-2-mixtape', | |
83 | "playlist_count": 15, | |
84 | 'info_dict': | |
85 | { | |
86 | 'id': "812251", | |
87 | 'title': "Tha Tour: Part 2 (Official Mixtape)" | |
88 | } | |
89 | }, | |
90 | # Album playlist ripped from fakeshoredrive with no metadata | |
91 | { | |
92 | "url": "http://www.audiomack.com/album/fakeshoredrive/ppp-pistol-p-project", | |
93 | "playlist_count": 10 | |
d3c72db8 | 94 | } |
defaf19f YN |
95 | ] |
96 | ||
97 | def _real_extract(self, url): | |
98 | # URLs end with [uploader name]/[uploader title] | |
99 | # this title is whatever the user types in, and is rarely | |
100 | # the proper song title. Real metadata is in the api response | |
101 | album_url_tag = self._match_id(url) | |
102 | result = {"_type": "playlist", "entries": []} | |
103 | # There is no one endpoint for album metadata - instead it is included/repeated in each song's metadata | |
104 | # Therefore we don't know how many songs the album has and must infi-loop until failure | |
105 | track_no = 0 | |
106 | while True: | |
107 | # Get song's metadata | |
108 | api_response = self._download_json("http://www.audiomack.com/api/music/url/album/%s/%d?extended=1&_=%d" | |
109 | % (album_url_tag, track_no, time.time()), album_url_tag) | |
110 | ||
111 | # Total failure, only occurs when url is totally wrong | |
112 | # Won't happen in middle of valid playlist (next case) | |
113 | if "url" not in api_response or "error" in api_response: | |
114 | raise ExtractorError("Invalid url for track %d of album url %s" % (track_no, url)) | |
115 | # URL is good but song id doesn't exist - usually means end of playlist | |
116 | elif not api_response["url"]: | |
117 | break | |
118 | else: | |
119 | # Pull out the album metadata and add to result (if it exists) | |
120 | for resultkey, apikey in [("id", "album_id"), ("title", "album_title")]: | |
121 | if apikey in api_response and resultkey not in result: | |
122 | result[resultkey] = api_response[apikey] | |
123 | result["entries"].append(AudiomackIE.create_song_dictionary(api_response, album_url_tag, track_no)) | |
124 | track_no += 1 | |
125 | return result |