Skip to content

Commit

Permalink
Add browse_collections method
Browse files Browse the repository at this point in the history
According to the API page, it's possible to find collections
 that are linked to a bunch of other entities:
 https://musicbrainz.org/doc/MusicBrainz_API#Linked_entities
  • Loading branch information
LoveIsGrief committed Dec 30, 2021
1 parent 8ed0187 commit c6a814b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 8 deletions.
34 changes: 34 additions & 0 deletions examples/browse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env python
"""
Browse entities on musicbrainz
"""
import json
import sys
from argparse import ArgumentParser

import musicbrainzngs

musicbrainzngs.set_useragent(
"python-musicbrainzngs-example",
"0.1",
"https://github.com/alastair/python-musicbrainzngs/",
)

if __name__ == '__main__':
parser = ArgumentParser()
parser.add_argument(
"entity_type",
choices=["collection"],
help="The type of entity we're trying to get"
)
parser.add_argument("linked_entity_type", help="The entity type it's linked to")
parser.add_argument("mbid", help="The ID of the linked entity")
args = parser.parse_args()

result = {}
if args.entity_type == "collection":
result = musicbrainzngs.browse_collections(args.linked_entity_type, args.mbid)
else:
print("Invalid entity type passed", file=sys.stderr)
exit(1)
print(json.dumps(result, indent=2))
42 changes: 34 additions & 8 deletions musicbrainzngs/musicbrainz.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
}
VALID_BROWSE_INCLUDES = {
'artist': ["aliases"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,
'collection': [],
'event': ["aliases"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,
'label': ["aliases"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,
'recording': ["artist-credits", "isrcs"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,
Expand All @@ -94,6 +95,11 @@
'work': ["aliases", "annotation"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,
}

VALID_BROWSE_LINK_ENTITIES = {
'collection': ["area", "artist", "editor", "event", "label", "place", "recording", "release", "release-group",
"work"]
}

#: These can be used to filter whenever releases are includes or browsed
VALID_RELEASE_TYPES = [
"nat",
Expand Down Expand Up @@ -284,6 +290,10 @@ def _docstring_browse(entity):
includes = list(VALID_BROWSE_INCLUDES.get(entity, []))
return _docstring_impl("includes", includes)

def _docstring_browse_links(entity):
includes = list(VALID_BROWSE_LINK_ENTITIES.get(entity, []))
return _docstring_impl("link_entities", includes)

def _docstring_search(entity):
search_fields = list(VALID_SEARCH_FIELDS.get(entity, []))
return _docstring_impl("fields", search_fields)
Expand Down Expand Up @@ -710,7 +720,7 @@ def _get_auth_type(entity, id, includes):
return AUTH_NO


def _do_mb_query(entity, id, includes=[], params={}):
def _do_mb_query(entity, id, includes=[], params={}, auth_type=None):
"""Make a single GET call to the MusicBrainz XML API. `entity` is a
string indicated the type of object to be retrieved. The id may be
empty, in which case the query is a search. `includes` is a list
Expand All @@ -722,7 +732,7 @@ def _do_mb_query(entity, id, includes=[], params={}):
if not isinstance(includes, list):
includes = [includes]
_check_includes(entity, includes)
auth_required = _get_auth_type(entity, id, includes)
auth_required = auth_type or _get_auth_type(entity, id, includes)
args = dict(params)
if len(includes) > 0:
inc = " ".join(includes)
Expand Down Expand Up @@ -1064,7 +1074,7 @@ def get_works_by_iswc(iswc, includes=[]):
return _do_mb_query("iswc", iswc, includes)


def _browse_impl(entity, includes, limit, offset, params, release_status=[], release_type=[]):
def _browse_impl(entity, includes, limit, offset, params, release_status=[], release_type=[], auth_type=None):
includes = includes if isinstance(includes, list) else [includes]
valid_includes = VALID_BROWSE_INCLUDES[entity]
_check_includes_impl(includes, valid_includes)
Expand All @@ -1078,7 +1088,7 @@ def _browse_impl(entity, includes, limit, offset, params, release_status=[], rel
if offset: p["offset"] = offset
filterp = _check_filter_and_make_params(entity, includes, release_status, release_type)
p.update(filterp)
return _do_mb_query(entity, "", includes, p)
return _do_mb_query(entity, "", includes, p, auth_type=auth_type)

# Browse methods
# Browse include are a subset of regular get includes, so we check them here
Expand All @@ -1096,15 +1106,31 @@ def browse_artists(recording=None, release=None, release_group=None,
"work": work}
return _browse_impl("artist", includes, limit, offset, params)

@_docstring_browse_links("collection")
def browse_collections(entity_type, entity_mbid, limit=None, offset=None):
"""Get all collections linked to a given entity.
You need to give one MusicBrainz ID.
*Available entity_types*: {link_entities}"""
valid_linked_entities = VALID_BROWSE_LINK_ENTITIES["collection"]
if entity_type not in valid_linked_entities:
raise ValueError("Not a valid linked entity type", valid_linked_entities)

params = dict([(entity_type, entity_mbid)])
return _browse_impl("collection", [], limit, offset, params, auth_type=AUTH_IFSET)

@_docstring_browse("event")
def browse_events(area=None, artist=None, place=None,
includes=[], limit=None, offset=None):
def browse_events(
area=None, artist=None, place=None,
includes=[], limit=None, offset=None
):
"""Get all events linked to a area, a artist or a place.
You need to give one MusicBrainz ID.
*Available includes*: {includes}"""
params = {"area": area,
"artist": artist,
params = {
"area": area,
"artist": artist,
"place": place}
return _browse_impl("event", includes, limit, offset, params)

Expand Down
7 changes: 7 additions & 0 deletions test/test_browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ def test_browse_artist(self):
musicbrainzngs.browse_artists(work=work)
self.assertEqual("https://musicbrainz.org/ws/2/artist/?work=deb27b88-cf41-4f7c-b3aa-bc3268bc3c02", self.opener.get_url())

def test_browse_collection(self):
musicbrainzngs.browse_collections("release", "5fa83c79-ef7d-42ad-8a09-30a1d4c35f63")
self.assertEqual("https://musicbrainz.org/ws/2/collection/?release=5fa83c79-ef7d-42ad-8a09-30a1d4c35f63", self.opener.get_url())

with self.assertRaises(ValueError):
musicbrainzngs.browse_collections("I don't exist", "just whatever")

def test_browse_event(self):
area = "f03d09b3-39dc-4083-afd6-159e3f0d462f"
musicbrainzngs.browse_events(area=area)
Expand Down

0 comments on commit c6a814b

Please sign in to comment.