|
1
|
|
|
import os |
|
|
|
|
|
|
2
|
|
|
import requests |
|
3
|
|
|
from . import exceptions |
|
4
|
|
|
|
|
5
|
|
|
class Result: |
|
6
|
|
|
""" Parse an API result into an object format. """ |
|
7
|
|
|
|
|
8
|
|
|
def __init__(self, item): |
|
9
|
|
|
""" Call the list parser. """ |
|
10
|
|
|
self.parse(item) |
|
11
|
|
|
|
|
12
|
|
|
def parse(self, item): |
|
13
|
|
|
""" Parse the given list into self variables. """ |
|
14
|
|
|
self.artworkThumb = item['artworkUrl100'] |
|
15
|
|
|
self.artist = item['artistName'] |
|
16
|
|
|
self.album = item['collectionName'] |
|
17
|
|
|
self.url = item['url'] |
|
18
|
|
|
|
|
19
|
|
|
# Take some measures to detect whether it is a song or album |
|
20
|
|
|
if 'kind' in item: |
|
21
|
|
|
self.type = item['kind'].lower() |
|
22
|
|
|
elif 'wrapperType' in item: |
|
23
|
|
|
if item['wrapperType'].lower() == 'track': |
|
24
|
|
|
self.type = 'song' |
|
25
|
|
|
elif item['wrapperType'].lower() == 'collection': |
|
26
|
|
|
self.type = 'album' |
|
27
|
|
|
elif 'collectionType' in item: |
|
28
|
|
|
self.type = 'album' |
|
29
|
|
|
else: |
|
30
|
|
|
# Assuming edge case of the API |
|
31
|
|
|
self.type = 'unknown' |
|
32
|
|
|
|
|
33
|
|
|
if self.type == 'song': |
|
34
|
|
|
self.name = item['trackName'] |
|
35
|
|
|
elif self.type == 'album': |
|
36
|
|
|
self.name = item['collectionName'] |
|
37
|
|
|
else: |
|
38
|
|
|
self.name = 'unknown' |
|
39
|
|
|
|
|
40
|
|
|
def artwork(self, size = 625): |
|
41
|
|
|
""" Return the artwork to the thumb URL contained. """ |
|
42
|
|
|
# Replace size because API doesn't hand links to full res. It only gives 60x60 and 100x100. |
|
43
|
|
|
# However, I found a way to circumvent it. |
|
44
|
|
|
return self.artworkThumb.replace('100x100bb', "%sx%s" % (size, size)) |
|
45
|
|
|
|
|
46
|
|
|
class CoverPy: |
|
|
|
|
|
|
47
|
|
|
def __init__(self): |
|
48
|
|
|
""" Initialize CoverPy. Set a base_url. """ |
|
49
|
|
|
self.base_url = "https://itunes.apple.com/search/" |
|
50
|
|
|
|
|
51
|
|
|
def _get(self, payload, override = False, entities = False): |
|
|
|
|
|
|
52
|
|
|
""" Get a payload using the base_url. General purpose GET interface """ |
|
53
|
|
|
if override: |
|
54
|
|
|
data = requests.get("%s%s" % (self.base_url, override)) |
|
55
|
|
|
else: |
|
56
|
|
|
payload['entity'] = "musicArtist,musicTrack,album,mix,song" |
|
57
|
|
|
payload['media'] = 'music' |
|
58
|
|
|
data = requests.get(self.base_url, params = payload) |
|
59
|
|
|
|
|
60
|
|
|
if data.status_code != 200: |
|
61
|
|
|
raise requests.HTTPError |
|
62
|
|
|
else: |
|
63
|
|
|
return data |
|
64
|
|
|
|
|
65
|
|
|
def _search(self, term, limit = 1): |
|
66
|
|
|
""" Expose a friendlier internal API for executing searches """ |
|
67
|
|
|
payload = { |
|
68
|
|
|
'term': term, |
|
69
|
|
|
'limit': limit |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
req = self._get(payload) |
|
73
|
|
|
return req |
|
74
|
|
|
|
|
75
|
|
|
def get_cover(self, term, limit = 1, debug = False): |
|
|
|
|
|
|
76
|
|
|
""" Get an album cover, return a Result object """ |
|
77
|
|
|
search = self._search(term, limit) |
|
78
|
|
|
parsed = search.json() |
|
79
|
|
|
|
|
80
|
|
|
if parsed['resultCount'] == 0: |
|
81
|
|
|
raise exceptions.NoResultsException |
|
82
|
|
|
|
|
83
|
|
|
result = parsed['results'][0] |
|
84
|
|
|
result['url'] = search.url |
|
85
|
|
|
|
|
86
|
|
|
return Result(result) |
|
87
|
|
|
|
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.