I’m trying to get my feet wet with “all beets albums, ordered by $added”. I think beets/plugins can do this already but my idea is to build more functionality on top of it. I got this far:
beet ls --format '$added-$album-$track-$title'
Should I be looking in constraints.py ? calliope/select/constraints.py · main · Sam Thursfield / calliope · GitLab
beets? calliope/beets/__init__.py · main · Sam Thursfield / calliope · GitLab
This looks promising: examples/special-mix/special_mix.py · main · Sam Thursfield / calliope · GitLab
Is this something cpe can do now or do I have to edit the code? Perhaps the keys that are requested from beets?
Right now I miss a sql-like query functionality.
A metaphor like this might make sense:
- select columns/information that an algorithm will use
- the algorithm sorts the rows (deterministic) or semi-randomly picks rows (ai/linear solver) based on column values
- cpe resolves the rows to music files
- cpe pipes the result to a playlist, music file etc.
example:
query.sql
select
genre, artist, year, album, disc, track, plays, rating, days_since_last_play
from
beets
where
genre = 'jazz'
Then moving beyond the sql metaphor:
- I want 4 albums with rating >= 9/10
- 10 albums with no artist duplicated, and score them higher (make them more likely to be chosen by the solver) based on days_since_last_play.
It could look like this:
cpe select query.sql picklist.py
picklist_helpers.py:
def prefer(candidates, criterion):
# see also: https://gitlab.com/samthursfield/calliope/-/blob/main/calliope/select/localsearch.py#L157
'''do some non-deterministic magic to rank higher by `criterion` but don't just do a simple sort.
for example, 2 is not always greater than 1 in this paradigm. (If I'm understanding the calliope docs.)'''
picklist.py (custom per ‘picklist’, I may have one for jazz and one for running and one for parties, etc.)
def picker(table):
'''Choose tracks from table based on below constraints.'''
# each line in picklist is its own distinct set of constraints, unrelated to other lines
# each line is attempted to be solved until that line is fulfilled or the overall constraint (total runtime) is met
picklist = '''n=4;rating>=9;runtime<20minutes;shuffle_albums;
n=10;n_albumartists=1;last_played>7;prefer(last_played+);shuffle_albums''' # only 1 album per artist on this line
output_playlist = []
while sum(output_playlist['runtime']) < '60minutes':
for list_item in picklist:
new_items = parse_list_item(list_item)
# allow for the while-loop to break partway through, if constraint is met
for item in new_items:
output_playlist.append(new_items)
Or maybe the picklist line format could be something like count, sort, select.
n=10; sort=shuffle(albums); select= rating>=9, runtime<20minutes