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.