Silly fundamental search query question

I’m trying to create smart playlists for running.
I can’t seem to figure out how I can make a smart playlist that gives me tracks that conform to multiple bpm ranges and mutiple genres. E.g. like

bpm: 89..91 
OR 
bpm 178..182 
for 
genre: electronica 
OR 
genre: hip\ hop

I’ve tried this (among others) but it doesn’t work

    playlists:
        - name: 'running.m3u'
          query: 
            - genre:electronica, hip\ hop
            - bpm:89..91, 178..182

I’ve looked at readthedoc(s), @jakabadambalazs Github (for his wonderful plugin by the way but I don’t need to put my data on a media player, just need .3mu files) and experimented quite a lot but I always only got only part of the criterias returned in the m3u

I’d love to learn this. So my questions are.

  • How does one search multiple genre’s for multiple bpm ranges.
  • How is this search language called (so that I can research it further on the internet)?

Thanks!

Hi! Try this:

(genre:a, genre:b) (bpm:1..2, bpm:3..4)

Unfortunately or fortunately, this query language does not have a name. It is a whole-cloth beets invention, so the best name it has is “the beets query language,” and the canonical reference is the “Queries” page in the docs. It has grown organically over the years, and that page could certainly use more examples…

:+1::+1::+1: I knew there was a runner :running_man: around here and not just boring computer nerds :wink:

It is quite funny you ask this because I was thinking exactly about this the other day. As for the goingrunning plugin is concerned, I think you hit on one of the the most critical point: the song selection (this is really what the whole plugin is about). At the moment it uses flavours that you can mix to extend your query definition:

    trainings:
        10K:
            duration: 60
            use_flavours: [running, intensity_high, classic_rock]
            ordering:
                bpm: 100
                mood_aggressive: 50
    flavours:
        running:
            danceable: 0.3..
        intensity_high:
            bpm: 160..
            mood_aggressive: 0.7..
        classic_rock:
            genre: rock
            original_year: 1960..1990
        rebel:
            genre: ska

However when two flavours contain the same field like bpm ranges (your case) or if in the above example I add rebel to my 10K training so that it will use use_flavours: [running, intensity_high, classic_rock, rebel] - the one will override the other - and in the current state I will lose genre rock to ska. This is one of the next things I’d like to solve by creating a “merging strategy”. It’s “just” a matter of time.

The goingrunning plugin will at one point generate playlist files (and probably an option to skip copying music files to external player).

@adrian - uhhh, I didn’t know you could do that! So, it would look something like this?

    query:
        - (genre:electronica, genre:hip\ hop)
        - (bpm:89..9, bpm:178..182)

Thanks for this @adrian. I tried with square brackets but didn’t think of the round ones :confounded:
Respect for creating the query language. Could be useful for so many more open source projects I guess.

And yes another runner Adam (@jakabadambalazs)

Reading about your plugin made me really enthusiastic. I studied your page on Github page extensively and really liked the concept of being able to mix flavours and the fact that your plugin seems to be able to create lists of a specific duration.
I hope you’ll find the solution for the omitted criteria.

Great news that you have plans to make the plugin generate playlist files too. Can’t wait!

Hi @adrian,

I’ve been trying to get your suggestion to work like this:

query: (genre:electronica, genre:hip\ hop), (bpm:89..91, bpm:178..182)

and like this:

query: 
  - (genre:electronica, genre:hip\ hop)
  - (bpm:89..91, bpm:178..182)

But I’m getting the following error message:

smartplaylist: invalid query in playlist running.m3u: '182)' is not an int or a float

I have the following section in my config:

types:
    av_bitrate: int
    my_samplerate: int
    bitdepth: int
    album_bitdepth: int
    album_samplerate: int
    rating: int

And I’ve tried adding bpm: int to this list but to no avail.
Any idea what needs to be changed to get this query working?

Thanks!

You know what, it looks like I was totally wrong about the parentheses thing. I thought we had implemented that, but we had not. :man_facepalming:

First things first, I would recommend testing out queries with the list command. So try beet ls bpm:89..91, bpm:178..182 or similar to see if the query does what you want. And only once you have figured out a query that does what you’re expecting, then you can try configuring the smartplaylist plugin.

For your use case, in the absence of parentheses I might recommend using query negation and the inverse range for the BPM. For example, ^bpm:..88 ^bpm:92..177 ^bpm:183...

For the genre part, you could use regular expression queries. For example, genre::(electronica|hip hop). Of course, you will need to quote that query term in your shell to preserve the parens, space, and pipe.

Thanks @adrian for your suggestion to test with list command. I do it every once in a while, but also often forget it.

You suggestion for query negation works nicely. I ran a
beet ls -f "$(printf '$albumartist-$title $bpm')" ^bpm:..88 ^bpm:92..177 ^bpm:183..
and it output only tracks that fitted the criteria.

I discovered that the genre I was looking for was electronic and not electronica.
But even when doing a query with genre::(electronic|hip hop) like this:

beet ls "genre::(electronic|hip hop)"

I didn’t get any results. I tried many many variations. None of these did output any tracks.

Any idea why this wouldn’t result in a list with tracks that are either hip hop or electronic? I checked that I get results for each genre individually and that of course worked.

Maybe because the regexp is case sensitive? Try this:

beet ls genre::"(?i)(electronic|hip hop)"

it parses to :

AndQuery([RegexpQuery('genre', re.compile('(?i)(flamenco|ska)', re.IGNORECASE), True)])
1 Like

:rofl: :star_struck: :rofl: Thanks @adrian - that made me laugh a lot!

That did it @jakabadambalazs. Works like a charm when run in the terminal with beet ls

It ended up in my smartplaylist section like this

    playlists:
        - name: 'running.m3u'
          query: genre::"(?i)(electronic|hip hop)" ^bpm:..88 ^bpm:92..177 ^bpm:183..

But when I tried to format this like how you did in a previous post it didn’t.

It would be a nice and tidy way of keeping things organized. And I did it like this…

    playlists:
        - name: 'running.m3u'
          query: 
               - genre::"(?i)(electronic|hip hop)" 
               - ^bpm:..88 ^bpm:92..177 ^bpm:183..

It’s not a real problem because I can create long queries but would be handy.
Thanks!

2 Likes

Wait no more :wink: ! The new release (v1.2.1) can now generate playlists and has an option to suppress file copying (i.e. create playlist only). Also, it now supports list format for individual fields, so you can easily do something like this:

goingrunning:
  targets:
    my_target:
      device_root: ~/Music/tmp/
      device_path: 
      clean_target: no
      generate_playlist: yes
      copy_files: no
  trainings:
    10K:
      use_flavours: [intensity_low, intensity_high, electric]
      duration: 60
      target: my_target
  flavours:
    intensity_low:
      bpm: 89..91
    intensity_high:
      bpm: 178..182
    electric:
      genre: [electronic, hip hop]

to have a playlist generated with songs having attributes as you wrote in your initial question.
Now, all that remains to do is:

$ beet run 10K

and off you go… :running_man:

2 Likes

Hi Adam, that looks terrific.
Thanks for the update and the personalised example :smiley:!

1 Like