Skip to content

Commit

Permalink
Add missing files, fix tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
mayhem committed Jan 25, 2024
1 parent d859c64 commit 9ffecf6
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 2 deletions.
2 changes: 0 additions & 2 deletions troi/listenbrainz/recs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ class UserRecordingRecommendationsElement(Element):
def __init__(self, user_name, artist_type, count=25, offset=0):
super().__init__()
self.client = liblistenbrainz.ListenBrainz()
if auth_token:
self.client.set_auth_token(auth_token)
self.user_name = user_name
self.count = count
self.offset = offset
Expand Down
88 changes: 88 additions & 0 deletions troi/recording_search_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from abc import abstractmethod

import requests

from troi import Recording, Artist
from troi.service import Service
from troi.splitter import plist

# NOTES FOR LB API improvements:
# Tags:
# - flatten tag data for simplicity
# - use series of tighter random spots to speed up or searches for popular tags
# Artist:
# - Support percent based popular track lookups and move logic to server


class RecordingSearchByTagService(Service):

SLUG = "recording-search-by-tag"

def __init__(self):
super().__init__(self.SLUG)

def search(self, tags, operator, begin_percent, end_percent, num_recordings):
"""
Fetch the tag data from the LB API and return it as a dict.
"""

data = {
"condition": operator,
"count": num_recordings,
"begin_percent": begin_percent,
"end_percent": end_percent,
"tag": tags,
"min_tag_count": 1
}
r = requests.get("https://api.listenbrainz.org/1/lb-radio/tags", params=data)
if r.status_code != 200:
raise RuntimeError(f"Cannot fetch recordings for tags. {r.text}")

recordings = []
for rec in self.flatten_tag_data(dict(r.json())):
recordings.append(Recording(mbid=rec["recording_mbid"]))

return plist(recordings)

def flatten_tag_data(self, tag_data):

flat_data = list(tag_data["recording"])
flat_data.extend(list(tag_data["release-group"]))
flat_data.extend(list(tag_data["artist"]))

return sorted(flat_data, key=lambda f: f["percent"], reverse=True)


class RecordingSearchByArtistService(Service):

SLUG = "recording-search-by-artist"

def __init__(self):
super().__init__(self.SLUG)

def search(self, artists, begin_percent, end_percent, num_recordings):
"""
Fetch the artist data from the LB API and return it as a dict.
NOTE: This search is poor -- it should span all recordings by an artist not, just the top ones!
"""

artists_recordings = {}
for artist_mbid in artists:
params={"artist_mbid": artist_mbid}
r = requests.get("https://api.listenbrainz.org/1/popularity/top-recordings-for-artist", params={"artist_mbid": artist_mbid})
if r.status_code != 200:
raise RuntimeError(f"Cannot fetch top artist recordings: {r.status_code} ({r.text})")

recordings = plist()
for recording in r.json():
artist = Artist(mbids=recording["artist_mbids"], name=recording["artist_name"])
recordings.append(
Recording(mbid=recording["recording_mbid"],
name=recording["recording_name"],
duration=recording["length"],
artist=artist))

artists_recordings[artist_mbid] = recordings.random_item(begin_percent, end_percent, num_recordings)

return artists_recordings
18 changes: 18 additions & 0 deletions troi/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Service:
"""
Services allow troi users to provide local versions of key search functions
so that both global (e.g. MusicBrainz) and local search contexts can be used.
Downstream users will be able to provide localized version of search functions
to provide lists of Recordings that meet certain requirements for playlist inclusion.
Only one service can be registered for any given service slug at a time. The most
recently registered service will be use for the next playlist generation.
"""

def __init__(self, slug):
self._slug = slug

@property
def slug(self):
return self._slug

0 comments on commit 9ffecf6

Please sign in to comment.