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

Commit

Permalink
Or tag search is finally working!
Browse files Browse the repository at this point in the history
  • Loading branch information
mayhem committed Dec 14, 2023
1 parent aa6512d commit 0e7d6fc
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 76 deletions.
78 changes: 23 additions & 55 deletions lb_content_resolver/query.txt
Original file line number Diff line number Diff line change
@@ -1,57 +1,25 @@
OR

WITH recording_ids AS (
SELECT DISTINCT(recording_id)
FROM tag
JOIN recording_tag
ON recording_tag.tag_id = tag.id
JOIN recording
ON recording.id = recording_tag.recording_id
WHERE name in ('trip hop', 'downtempo')
)
SELECT recording.id
, recording_name
, popularity
FROM recording
JOIN recording_ids
ON recording.id = recording_ids.recording_id
JOIN recording_metadata
ON recording.id = recording_metadata.recording_id
WHERE popularity >= .5
AND popularity < .8
ORDER BY popularity DESC
;

AND

WITH recording_tags AS (
SELECT DISTINCT recording.id AS recording_id
, tag.name AS tag_name
FROM tag
JOIN recording_tag
ON recording_tag.tag_id = tag.id
JOIN recording
ON recording.id = recording_tag.recording_id
WHERE name in ('downtempo', 'trip hop')
ORDER BY recording.id
), recording_ids AS (
SELECT recording_tags.recording_id
FROM recording_tags
JOIN recording_metadata
ON recording_tags.recording_id = recording_metadata.recording_id
GROUP BY recording_tags.recording_id
HAVING count(recording_tags.tag_name) = 2
)
SELECT recording.id
, recording_name
, popularity
FROM recording
JOIN recording_ids
ON recording.id = recording_ids.recording_id
JOIN recording_metadata
ON recording.id = recording_metadata.recording_id
WHERE popularity >= .5
AND popularity < .8
ORDER BY popularity DESC
;

WITH recording_ids AS (
SELECT DISTINCT(recording_id)
FROM tag
JOIN recording_tag
ON recording_tag.tag_id = tag.id
JOIN recording
ON recording.id = recording_tag.recording_id
WHERE name in ('hindi', '4ad')
)
SELECT recording_mbid
, popularity AS percent
, subsonic_id
, recording_name
, artist_name
FROM recording
JOIN recording_ids
ON recording.id = recording_ids.recording_id
JOIN recording_metadata
ON recording.id = recording_metadata.recording_id
JOIN recording_subsonic
ON recording.id = recording_subsonic.recording_id
ORDER BY popularity DESC
;
107 changes: 90 additions & 17 deletions lb_content_resolver/tag_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from troi.splitter import plist

# TODO: Right now this only works for subsonic tracks!
# TODO: OR TAG SEARCH: ['4ad', 'hindi'] -- hindi has one result, but that does not appear in the output.


class LocalRecordingSearchByTagService(RecordingSearchByTagService):
Expand All @@ -23,29 +24,84 @@ def __init__(self, db):
RecordingSearchByTagService.__init__(self)
self.db = db

def search(self, tags, operator, begin_percent, end_percent):
def search(self, tags, operator, begin_percent, end_percent, num_recordings):
"""
"""

print(operator)
if operator == "or":
query, params = self.or_search(tags, begin_percent / 100, end_percent / 100)
query, params, pop_clause = self.or_search(tags)
else:
query, params = self.and_search(tags, begin_percent / 100, end_percent / 100)
query, params, pop_clause = self.and_search(tags)

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

recordings = plist()
# Break the data into over, matching and under (percent) groups
matching_recordings = []
over_recordings = []
under_recordings = []
for rec in cursor.fetchall():
print(f"{rec[0]} {rec[1]}")
recordings.append({ "recording_mbid": rec[0], "percent": rec[1], "subsonic_id": rec[2] })
recording = { "recording_mbid": rec[0],
"percent": rec[1],
"subsonic_id": rec[2],
"recording_name": rec[3],
"artist_name": rec[4] }

return recordings
if rec[1] >= begin_percent:
if rec[1] < end_percent:
matching_recordings.append(recording)
else:
over_recordings.append(recording)
else:
under_recordings.append(recording)

if len(matching_recordings) >= num_recordings:
return plist(matching_recordings)

def or_search(self, tags, min_popularity, max_popularity):
def print_result(items):
for i in items:
print("%-30s %-30s %d%%" % (i["recording_name"][:29],
i["artist_name"][:29],
i["percent"] * 100))
print()

# print("begin %d%% end %d%%" % (begin_percent * 100, end_percent * 100))
# print("under")
# print_result(under_recordings)
# print("matches")
# print_result(matching_recordings)
# print("over")
# print_result(over_recordings)

# 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]["percent"]
else:
under_diff = 1.0

if over_recordings:
over_diff = over_recordings[-1]["percent"] - 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))

# print("final matches")
# print_result(matching_recordings)


return plist(matching_recordings)


def or_search(self, tags, min_popularity=None, max_popularity=None):
query = """WITH recording_ids AS (
SELECT DISTINCT(recording_id)
FROM tag
Expand All @@ -58,19 +114,28 @@ def or_search(self, tags, min_popularity, max_popularity):
SELECT recording_mbid
, popularity AS percent
, subsonic_id
, recording_name
, artist_name
FROM recording
JOIN recording_ids
ON recording.id = recording_ids.recording_id
JOIN recording_metadata
ON recording.id = recording_metadata.recording_id
JOIN recording_subsonic
ON recording.id = recording_subsonic.recording_id
WHERE popularity >= ?
AND popularity < ?
%s
ORDER BY popularity DESC"""
return query, (*tags, min_popularity, max_popularity)

def and_search(self, tags, min_popularity, max_popularity):
if min_popularity is not None and max_popularity is not None:
pop_clause = """WHERE popularity >= %.4f AND popularity < %.4f""" % \
(min_popularity, max_popularity)
else:
pop_clause = ""

return query, [*tags], pop_clause

def and_search(self, tags, min_popularity=None, max_popularity=None):
# todo: remove fetch name and artist
query = """WITH recording_tags AS (
SELECT DISTINCT recording.id AS recording_id
, tag.name AS tag_name
Expand All @@ -92,14 +157,22 @@ def and_search(self, tags, min_popularity, max_popularity):
SELECT recording_mbid
, popularity AS percent
, subsonic_id
, recording_name
, artist_name
FROM recording
JOIN recording_ids
ON recording.id = recording_ids.recording_id
JOIN recording_metadata
ON recording.id = recording_metadata.recording_id
JOIN recording_subsonic
ON recording.id = recording_subsonic.recording_id
WHERE popularity >= ?
AND popularity < ?
%s
ORDER BY popularity DESC"""
return query, (*tags, len(tags), min_popularity, max_popularity)

if min_popularity is not None and max_popularity is not None:
pop_clause = """WHERE popularity >= %.4f AND popularity < %.4f""" % \
(min_popularity, max_popularity)
else:
pop_clause = ""

return query, (*tags, len(tags)), pop_clause
8 changes: 4 additions & 4 deletions resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ def lb_radio(index_dir, mode, prompt):
r = ListenBrainzRadioLocal(db)
jspf = r.generate(mode, prompt)

if len(jspf["playlist"]["track"]) > 0 and config.SUBSONIC_HOST != "":
if ask_yes_no_question("Upload via subsonic? (Y/n)"):
print("uploading playlist")
db.upload_playlist(jspf)
# if len(jspf["playlist"]["track"]) > 0 and config.SUBSONIC_HOST != "":
# if ask_yes_no_question("Upload via subsonic? (Y/n)"):
# print("uploading playlist")
# db.upload_playlist(jspf)

@click.command()
@click.argument('index_dir')
Expand Down

0 comments on commit 0e7d6fc

Please sign in to comment.