Skip to content
This repository has been archived by the owner on Feb 9, 2024. It is now read-only.

Commit

Permalink
Artist search feature implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
mayhem committed Dec 24, 2023
1 parent 264fbbf commit df92101
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
114 changes: 114 additions & 0 deletions lb_content_resolver/artist_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os
from collections import defaultdict
import datetime
import sys

import peewee
import requests

from lb_content_resolver.model.database import db
from lb_content_resolver.model.recording import Recording, RecordingMetadata
#from troi.recording_search_service import RecordingSearchByArtistService
from troi.splitter import plist


class LocalRecordingSearchByArtistService: #(RecordingSearchByArtistService):
'''
Given the local database, search for artists that meet given tag criteria
'''

def __init__(self, db):
# RecordingSearchByTagService.__init__(self)
self.db = db

def search(self, artist_mbids, begin_percent, end_percent, num_recordings):
"""
Perform an artist search. Parameters:
tags - a list of artist_mbids for which to search recordings
begin_percent - if many recordings match the above parameters, return only
recordings that have a minimum popularity percent score
of begin_percent.
end_percent - if many recordings match the above parameters, return only
recordings that have a maximum popularity percent score
of end_percent.
num_recordings - ideally return these many recordings
If only few recordings match, the begin_percent and end_percent are
ignored.
"""

print(artist_mbids)

query = """SELECT popularity
, recording_mbid
, artist_mbid
, subsonic_id
FROM recording
JOIN recording_metadata
ON recording.id = recording_metadata.recording_id
JOIN recording_subsonic
ON recording.id = recording_subsonic.recording_id
WHERE artist_mbid in (%s)
ORDER BY artist_mbid
, popularity"""

self.db.open_db()
placeholders = ",".join(("?", ) * len(artist_mbids))
cursor = db.execute_sql(query % placeholders, params=tuple(artist_mbids))

artists = defaultdict(list)
for rec in cursor.fetchall():
artists[rec[2]].append({"popularity": rec[0], "recording_mbid": rec[1], "artist_mbid": rec[2], "subsonic_id": rec[3]})

for artist in artists:
artists[artist] = self.fetch_and_select_on_popularity(artists[artist], begin_percent, end_percent, num_recordings)

return artists


# TODO: use this in both tag and artist search classes
def fetch_and_select_on_popularity(self, recordings, begin_percent, end_percent, num_recordings):
"""
Break the data into over, matching and under (percent) groups
"""

matching_recordings = []
over_recordings = []
under_recordings = []
for rec in recordings:
if rec["popularity"] >= begin_percent:
if rec["popularity"] < end_percent:
matching_recordings.append(rec)
else:
over_recordings.append(rec)
else:
under_recordings.append(rec)

# If we have enough recordings, we're done!
if len(matching_recordings) >= num_recordings:
return plist(matching_recordings)

# We don't have enough recordings, see if we can pick the ones outside
# of our desired range in a best effort to make a playlist.
# Keep adding the best matches until we (hopefully) get our desired number of recordings
while len(matching_recordings) < num_recordings:
if under_recordings:
under_diff = begin_percent - under_recordings[-1]["popularity"]
else:
under_diff = 1.0

if over_recordings:
over_diff = over_recordings[-1]["popularity"] - end_percent
else:
over_diff = 1.0

if over_diff == 1.0 and under_diff == 1.0:
break

if under_diff < over_diff:
matching_recordings.insert(0, under_recordings.pop(-1))
else:
matching_recordings.insert(len(matching_recordings), over_recordings.pop(0))

return plist(matching_recordings)
2 changes: 2 additions & 0 deletions lb_content_resolver/lb_radio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from troi.splitter import plist

from lb_content_resolver.tag_search import LocalRecordingSearchByTagService
from lb_content_resolver.artist_search import LocalRecordingSearchByArtistService
from lb_content_resolver.model.database import db
import config

Expand Down Expand Up @@ -51,6 +52,7 @@ def generate(self, mode, prompt):

patch = LBRadioPatch({"mode": mode, "prompt": prompt, "echo": True, "debug": True, "min_recordings": 1})
patch.register_service(LocalRecordingSearchByTagService(self.db))
patch.register_service(LocalRecordingSearchByArtistService(self.db))

# Now generate the playlist
try:
Expand Down
9 changes: 9 additions & 0 deletions resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from lb_content_resolver.lb_radio import ListenBrainzRadioLocal
from lb_content_resolver.utils import ask_yes_no_question
from lb_content_resolver.top_tags import TopTags
from lb_content_resolver.artist_search import LocalRecordingSearchByArtistService
import config


Expand Down Expand Up @@ -90,6 +91,13 @@ def top_tags(index_dir, count):
tt.print_top_tags_tightly(count)


@click.command()
@click.argument('index_dir')
def artist_test(index_dir):
db = Database(index_dir)
s = LocalRecordingSearchByArtistService(db)
s.search(["8f6bd1e4-fbe1-4f50-aa9b-94c450ec0f11", "067102ea-9519-4622-9077-57ca4164cfbb"], .9, .6, 20)

cli.add_command(create)
cli.add_command(scan)
cli.add_command(playlist)
Expand All @@ -98,6 +106,7 @@ def top_tags(index_dir, count):
cli.add_command(subsonic)
cli.add_command(lb_radio)
cli.add_command(top_tags)
cli.add_command(artist_test)


def usage(command):
Expand Down

0 comments on commit df92101

Please sign in to comment.