1# This file is part of the musicbrainzngs library
2# Copyright (C) Alastair Porter, Wieland Hoffmann, and others
3# This file is distributed under a BSD-2-Clause type license.
4# See the COPYING file for more information.
5
6__all__ = [
7    'set_caa_hostname', 'get_image_list', 'get_release_group_image_list',
8    'get_release_group_image_front', 'get_image_front', 'get_image_back',
9    'get_image'
10    ]
11
12import json
13
14from musicbrainzngs import compat
15from musicbrainzngs import musicbrainz
16from musicbrainzngs.util import _unicode
17
18hostname = "coverartarchive.org"
19https = True
20
21
22def set_caa_hostname(new_hostname, use_https=False):
23    """Set the base hostname for Cover Art Archive requests.
24    Defaults to 'coverartarchive.org', accessing over https.
25    For backwards compatibility, `use_https` is False by default.
26
27    :param str new_hostname: The hostname (and port) of the CAA server to connect to
28    :param bool use_https: `True` if the host should be accessed using https. Default is `False`
29"""
30    global hostname
31    global https
32    hostname = new_hostname
33    https = use_https
34
35
36def _caa_request(mbid, imageid=None, size=None, entitytype="release"):
37    """ Make a CAA request.
38
39    :param imageid: ``front``, ``back`` or a number from the listing obtained
40                    with :meth:`get_image_list`.
41    :type imageid: str
42
43    :param size: "250", "500", "1200"
44    :type size: str or None
45
46    :param entitytype: ``release`` or ``release-group``
47    :type entitytype: str
48    """
49    # Construct the full URL for the request, including hostname and
50    # query string.
51    path = [entitytype, mbid]
52    if imageid and size:
53        path.append("%s-%s" % (imageid, size))
54    elif imageid:
55        path.append(imageid)
56    url = compat.urlunparse((
57        'https' if https else 'http',
58        hostname,
59        '/%s' % '/'.join(path),
60        '',
61        '',
62        ''
63    ))
64    musicbrainz._log.debug("GET request for %s" % (url, ))
65
66    # Set up HTTP request handler and URL opener.
67    httpHandler = compat.HTTPHandler(debuglevel=0)
68    handlers = [httpHandler]
69
70    opener = compat.build_opener(*handlers)
71
72    # Make request.
73    req = musicbrainz._MusicbrainzHttpRequest("GET", url, None)
74    # Useragent isn't needed for CAA, but we'll add it if it exists
75    if musicbrainz._useragent != "":
76        req.add_header('User-Agent', musicbrainz._useragent)
77        musicbrainz._log.debug("requesting with UA %s" % musicbrainz._useragent)
78
79    resp = musicbrainz._safe_read(opener, req, None)
80
81    # TODO: The content type declared by the CAA for JSON files is
82    # 'applicaiton/octet-stream'. This is not useful to detect whether the
83    # content is JSON, so default to decoding JSON if no imageid was supplied.
84    # http://tickets.musicbrainz.org/browse/CAA-75
85    if imageid:
86        # If we asked for an image, return the image
87        return resp
88    else:
89        # Otherwise it's json
90        data = _unicode(resp)
91        return json.loads(data)
92
93
94def get_image_list(releaseid):
95    """Get the list of cover art associated with a release.
96
97    The return value is the deserialized response of the `JSON listing
98    <http://musicbrainz.org/doc/Cover_Art_Archive/API#.2Frelease.2F.7Bmbid.7D.2F>`_
99    returned by the Cover Art Archive API.
100
101    If an error occurs then a :class:`~musicbrainzngs.ResponseError` will
102    be raised with one of the following HTTP codes:
103
104    * 400: `Releaseid` is not a valid UUID
105    * 404: No release exists with an MBID of `releaseid`
106    * 503: Ratelimit exceeded
107    """
108    return _caa_request(releaseid)
109
110
111def get_release_group_image_list(releasegroupid):
112    """Get the list of cover art associated with a release group.
113
114    The return value is the deserialized response of the `JSON listing
115    <http://musicbrainz.org/doc/Cover_Art_Archive/API#.2Frelease-group.2F.7Bmbid.7D.2F>`_
116    returned by the Cover Art Archive API.
117
118    If an error occurs then a :class:`~musicbrainzngs.ResponseError` will
119    be raised with one of the following HTTP codes:
120
121    * 400: `Releaseid` is not a valid UUID
122    * 404: No release exists with an MBID of `releaseid`
123    * 503: Ratelimit exceeded
124    """
125    return _caa_request(releasegroupid, entitytype="release-group")
126
127
128def get_release_group_image_front(releasegroupid, size=None):
129    """Download the front cover art for a release group.
130    The `size` argument and the possible error conditions are the same as for
131    :meth:`get_image`.
132    """
133    return get_image(releasegroupid, "front", size=size,
134                     entitytype="release-group")
135
136
137def get_image_front(releaseid, size=None):
138    """Download the front cover art for a release.
139    The `size` argument and the possible error conditions are the same as for
140    :meth:`get_image`.
141    """
142    return get_image(releaseid, "front", size=size)
143
144
145def get_image_back(releaseid, size=None):
146    """Download the back cover art for a release.
147    The `size` argument and the possible error conditions are the same as for
148    :meth:`get_image`.
149    """
150    return get_image(releaseid, "back", size=size)
151
152
153def get_image(mbid, coverid, size=None, entitytype="release"):
154    """Download cover art for a release. The coverart file to download
155    is specified by the `coverid` argument.
156
157    If `size` is not specified, download the largest copy present, which can be
158    very large.
159
160    If an error occurs then a :class:`~musicbrainzngs.ResponseError`
161    will be raised with one of the following HTTP codes:
162
163    * 400: `Releaseid` is not a valid UUID or `coverid` is invalid
164    * 404: No release exists with an MBID of `releaseid`
165    * 503: Ratelimit exceeded
166
167    :param coverid: ``front``, ``back`` or a number from the listing obtained with
168                    :meth:`get_image_list`
169    :type coverid: int or str
170
171    :param size: "250", "500", "1200" or None. If it is None, the largest
172                 available picture will be downloaded. If the image originally
173                 uploaded to the Cover Art Archive was smaller than the
174                 requested size, only the original image will be returned.
175    :type size: str or None
176
177    :param entitytype: The type of entity for which to download the cover art.
178                       This is either ``release`` or ``release-group``.
179    :type entitytype: str
180    :return: The binary image data
181    :type: str
182    """
183    if isinstance(coverid, int):
184        coverid = "%d" % (coverid, )
185    if isinstance(size, int):
186        size = "%d" % (size, )
187    return _caa_request(mbid, coverid, size=size, entitytype=entitytype)
188