navidrome / navidrome

🎧☁️ Modern Music Server and Streamer compatible with Subsonic/Airsonic
https://www.navidrome.org
GNU General Public License v3.0
10.16k stars 783 forks source link

Smart Playlists #1417

Open deluan opened 2 years ago

deluan commented 2 years ago

Smart playlists can be created as a json object into a file with .nsp extension and Navidrome will create a dynamic/query based playlist and keep it updated. These .nsp files will be imported the same way as normal playlists, i.e. at scan time. See comment below for a complete list of fields and operators available.

Some examples:

TODO

Eidansoft commented 1 year ago

Hi Is there any way to share an URL to directly start playing a smart list ?? My idea is to create a shortcut that will call that url every time my phone connects to car's bluethooth, so it should starts playing the smartlist automatically.

Regards.

0bmay commented 1 year ago

@Eidansoft that would be up to your player of choice. I know play:Sub for iOS has this ability and I have done almost exactly what you have described. I used a shortcut to play a specific playlist, shuffled, when connected to CarPlay.

Eidansoft commented 1 year ago

@0bmay thanks for comment, I was trying to avoid install specific apps into my device and that feature is present into several apps (like https://github.com/BLeeEZ/amperfy that is even better because it is free software).

But I would like to use the Navidrome web interface that in my opinion is great, and on IOs I can add the web page to the desktop like if it were another app.

IMG_9A7823CE09C6-1

burjuyz commented 1 year ago

Is it possible to add to the list of fields: group its very convininent to create playlists cointaing group in metadata ID3

Jucgshu commented 1 year ago

Hi guys,

I'm trying to build a playlist that is wife compatible, aka without metal, but I can't seem to do it:

{
  "all": [
    {"is": {"loved": true}},
    { "any": [
      {"notContains": {"genre": "Hard Rock"}},
      {"notContains": {"genre": "Alternative Rock"}},
      {"notContains": {"genre": "Metal"}}
    ]}
  ],
  "sort": "dateLoved",
  "order": "desc"
}

All my music has been tagged with beets with the lastgenre plugin set to 3 genres with a "," separator. But no matter what I try, I end up finding "Hard Rock" or "Heavy Metal" songs.

Any clue of what I'm missing?

Thanks for any help.

0bmay commented 1 year ago

I know it doesn't help, but any song/album that has multiple genres associated with it bypasses filters.

Take Adam Sandler albums, which have rocks songs and comedy, the genres are "Comedy; Rock" In the back end the genres are split out in to Comedy and Rock. Filtering FOR something is great.. Filtering on NOT, not so much. Having the filter being {"notContains": { "genre": "Comedy"}} will not match and song that are Comedy.. but will let the Rock genre and anything else go thought. Here's the snag, the Adam Sandler songs also hit on Rock and pass through the genre filters.

So if you want to match on notContains and Genre, the best course of action is to only use a single genre to tag your music.

I haven't found a better solution other than also use notContains with a listing of artist names. Not ideal, but I have very few Comedy artists that also have Rock songs.

Jucgshu commented 1 year ago

Hey @0bmay, thanks for your answer. This is what I suspected. I have all my songs tagged with multiple genres, so it would feel like a massive regression if I would only keep one.

Hope multiple genres will be supported one day.

djjudas21 commented 1 year ago

@Jucgshu I think you need to change your genre operator from any to all. You want to find songs that are not hard rock AND are not metal. An OR doesn't make sense here.

Jucgshu commented 1 year ago

Van Halen is tagged as Hard Rock, Classic Rock and Rock. Machine Head is tagged Heavy Metal, Thrash Metal and Rock. I'm not sure how an AND operator would help here.

burjuyz commented 1 year ago

Im trying to create a playlist from two folders, but it doesnt work.

{ "all": [ {"contains": {"filepath": "/=DEEP=/Prog"}}, {"contains": {"filepath": "/=DEEP=/Tech"}} ], "sort": "datemodified", "order": "desc" }

djjudas21 commented 1 year ago

@burjuyz you need your change your all to any. Otherwise you are requiring that all of those conditions must be true, and they obviously can't be 🙂

djjudas21 commented 1 year ago

@deluan do you have a wiki page etc where we can keep a record of working examples of these smart playlists? I reckon once a few people have contributed, there would be enough content that it would be easy for most people to tweak them to suit

burjuyz commented 1 year ago

Thanks so easy the sulutions was. You have a nice idea with wiki page +1

lelus78 commented 1 year ago

hello all, i was trying to make a christmas compilation, but i need to insert more than one album name as in example, I have tried different way without succes it alwais use only the first album specification.

{
  "all": [
    {"contains": {"album": "christmas"} or {"album": "xmas"}}
  ],
  "sort": "lastPlayed",
  "order": "desc",
  "limit": 200
}   
{
  "all": [
    {"contains": {"album": "christmas"}
    {"contains":  {"album": "xmas"}}
  ],
  "sort": "lastPlayed",
  "order": "desc",
  "limit": 200
}   
deluan commented 1 year ago

Hey folks, sorry for the delay, here are the answers for the unanswered questions:

is it possible to filter songs, which were added to specific playlist recently?

@sintpon Not yet, but it is planned. Maybe in the next release?


Is there any way to share an URL to directly start playing a smart list ??

@Eidansoft Unfortunately now, there is no way to start playing when ND UI opens.


Is it possible to add to the list of fields: group

@Jucgshu We don't import the grouping tag yet, but when we do, it will be available for smart playlists.


do you have a wiki page etc where we can keep a record of working examples of these smart playlists?

@djjudas21 This is the page :P But yeah, a page in the Website would be great! A very welcome contribution... :)


Hope multiple genres will be supported one day.

@Jucgshu Yeah, I need to revisit the support for multiple values for Smart Playlists. I'll take a look and see if I can fix this.


hello all, i was trying to make a christmas compilation, but i need to insert more than one album name as in example

@lelus78 you need your change all to any. Otherwise, you are requiring that all of those conditions must be true, and they obviously can't be. all means ALL conditions must match (a logical AND operator) any means ANY condition must match (a logical OR operator)

lelus78 commented 1 year ago

@lelus78 you need your change all to any. Otherwise, you are requiring that all of those conditions must be true, and they obviously can't be. all means ALL conditions must match (a logical AND operator) any means ANY condition must match (a logical OR operator)

Thenks for the replay I have tried to use the any condition but still I cant see any difference.

{
  "any": [
    {"contains": {"album": "Santa Claus"}}
    {"contains": {"album": "christmas"}}
    {"contains": {"album": "xmas"}}   
  ],
  "sort": "lastPlayed",
  "order": "desc",
  "limit": 200
}
0bmay commented 1 year ago

@lelus78

Try the following:

''' { "any": [ {"contains": {"album": "Santa Claus"}}, {"contains": {"album": "christmas"}}, {"contains": {"album": "xmas"}}
], "sort": "lastPlayed", "order": "desc", "limit": 200 } '''

lelus78 commented 1 year ago

@0bmay Thenks for your help have worked perfectly :) The problem whas the comma.

lelus78 commented 1 year ago

Ok I'm back to ask some help from the python espert, I'm making a auto updater playlist with the top 100 from bilboard the update is working fine my problem is on appending at the end of the json file the "sort" "order" and "limit" the playlist is working also without tis part but I prefear to add it :)

# Convert csv to json 
import json
import csv

with open ("../data/week_chart_list.csv", "r") as f:
    reader = csv.reader(f)
    next(reader)
    data = {"any": []}
    data2 = {"sort": []}
    data3 = {"order": [] }
    data4 = {"limit": []}
    for row in reader:
        data["any"].append({"contains": {"title":
        row[0]}})  
        data2["sort"].append({"lastplayed"})
        data3["order"].append({"desc"})
        data4["limit"].append({300})

with open ("M:/Organizzata/Smart Playlist/Generali/Top100 Della settimana.nsp", "w") as f:
    json.dump(data, f, indent=1)

The result from the above script is more or less this one


{
 "any": [
  {
   "contains": {
    "title": "Anti-Hero"
   }
  },
{
   "contains": {
    "title": "Forget Me"
   }
  },
  {
   "contains": {
    "title": "Going, Going, Gone"
   }
  },
  {
   "contains": {
    "title": "Bigger Than The Whole Sky"
   }
  }
 ]
}

I hope some one more expert than me can figure out my mistake.

deluan commented 1 year ago

@lelus78 , please refrain from posting off-topic discussions here. This issue is to track progress of Navidrome's Smart Playlists feature.

If you have Python questions, please look for a proper forum. Or if you want to discuss these kind of scripts with other members of the ND community, please use our Discord or Reddit.

lelus78 commented 1 year ago

@deluan, I'm sorry I whas thinking that this kind of script integration was of some interest, I wil ask some were, no problem :)

extrange commented 1 year ago

Is Navidrome mapping the field comments to comment internally?

I have a .flac file, output of beet info:

(truncated)
         catalognums: 
            channels: 2
            comments: loved
                comp: False
            composer: 
       composer_sort: 
(truncated)

favourites.nsp: (note the field is comments)

{
  "all": [
    {"contains": {"comment": "loved"}}
  ]
}

In Navidrome, this song is in the favourites playlist.

deluan commented 1 year ago

@extrange The field is returned by both ffmpeg and taglib as comment, and that is what Navidrome uses internally

extrange commented 1 year ago

Thanks. I just did a check and it appears the issue is with beets - it's using comments internally but writing the field as comment. Checking metadata with other tools shows this to be the case.

FabioC4 commented 1 year ago

Hi @deluan!

Is it possible to use a field to sort by "updated_at", as i filter on browser via url? (song?order=DESC&sort=updated_at)

Thanks!

deluan commented 1 year ago

Yes, but the name is different: dateModified, see the complete list here: https://github.com/navidrome/navidrome/issues/1417#issuecomment-973407644

FabioC4 commented 1 year ago

That was quick :)

I tried before but had another wrong variable, now working good, thanks!

{
  "all": [
    {"gt": {"playCount":-1}}
  ],
  "sort": "datemodified",
  "order": "desc",
  "limit": 500
}
SickProdigy commented 1 year ago

Wanted to share my hip hop smart playlist I finally got working. Apparently I'm having issues with tagging and tried to run lidarr edit tags last night. Didn't quite work like I hoped but more are showing up.

Filename: "-Top Hip Hop ;).NSP" # The dash makes these show at the top. Different characters produce differently.

{
  "all": [
    { "any": [
      {"contains": {"genre": "hip-hop"}},
      {"contains": {"genre": "hip hop"}}
    ]},
    {"gt": {"rating": 2}}
  ],
  "sort": "random",
  "limit": 500
}

So all = must have "hip hop"/"hip-hop" and at least a 3 rating. Any = songs containing "hip hop" or "hip-hop", but I'm not sure what happens if there is both. (If this was in the all statement, the song would have to have both genres)

I use something similar for country, metal, metalcore, etc. I consider a 3 rating I've given pretty good, anything below I don't really want to hear. So all I have to do is go through the songs rate, love and auto sorted into these playlists. That's love.

MarcSN311 commented 1 year ago

Hi! is it possible to create playlists using the TOWN id3 Frame?

deluan commented 1 year ago

Hi! is it possible to create playlists using the TOWN id3 Frame?

Not really, as this tag is not imported by Navidrome. The only tags that currently can be used are listed in the first comment of this issue

Bowl2much commented 1 year ago

I understand favorites, ratings, etc are stored per user. Is it possible to add the username into the search for the favorites? Something like:

{
  "all": [
    {"username": "abc123"},
    {"is": {"loved": true}}
  ],
  "sort": "dateLoved",
  "order": "desc",
  "limit": 500
}

The idea is we only get this users favorites instead of any favorites marked on the server. Thanks

deluan commented 1 year ago

The username is already implicitly the owner of the playlist. Only the owner's favorites are selected, not all favorites. If the playlist is public and any other user besides the owner opens it, it will display the favorites of the owner as well.

If you want a generic favourites playlist, that shows the favourites for the current user, that is not currently possible with the .NSP syntax. The only solution is to create one favourites .NSP for each user, then as admin change the ownerships of each copy to each user, and preferable make them private. This way each user would have their own favourites smart playlist.

Hope this helps.

Bowl2much commented 1 year ago

Ahh. This is what was getting me:

If the playlist is public and any other user besides the owner opens it, it will display the favorites of the owner as well.

I did not think to change the selected owner to the user I was trying to narrow it down to. Thank you so much!

TheLux83 commented 1 year ago

Sorry, if the question was already asked, or defined somewhere here. Then I was too dumb to find it ^^ I want to create a playlist, of tracks, that were added in the last 30 days. But I also want them to be sorted "by album" and then "by tracknumber", so that I can hear the album in the defined track order.

At the moment I have this:

{
  "all": [
    {"inTheLast": {"dateadded": "30"}}
  ],  
  "sort": "album"
}

This sorts the list by album, but it doesn't sort it by tracknumbers. The titles within the album aren't sorted correctly. Is my idea of a smart playlist even possible in the current state?

Thanks in advance for the answers :-)

deluan commented 1 year ago

@TheLux83, currently the sort attribute needs to be a single field, so there's currently no way to sort by album and then by trackNumber. I may change this in the future, but it is not possible ATM.

TheLux83 commented 1 year ago

Hey @deluan thanks for the fast reply. :-) Then I will wait until this is possible and use all the other stuff, that navidrome offers :-)

Teloshav commented 1 year ago

Hello, I have not uesd github properly before, so you will have to excuse me if I do something wrong as I don't understand how any of this works.

I really like this project and hope to be able to work on improving on some of the documentation where possible with my admittedly limited knowledge.

To my question now:

My personal instance of navidrome running from a docker container on my home network. I have some smart playlists that I made.

I moved the .nsp files outside my Navidrome folder. I moved them outside the folder as I wanted to be able to add songs to those playlists, but they're not recognised whatsoever.

My idea was to get my music to be sorted into playlists from my individual folders using the smart playlists feature, which worked great, but since I got rid of them, I thought I'd be able to start modifying them.

Could anyone please explain why this is happening? I assume this is because I'm trying approach this problem in a weird way.

I did manage to 'get past' this issue by exporting one of the playlists and importing that on its own, but I hope to get rid of the folder structre so then I can remove duplicate songs (which is another insidious problem I'm trying to fix, I've got 3-4 copies of some songs!! 😱).

Thanks!

SubZeroPL commented 12 months ago

I'm not sure if it's the right place to ask this, but it's also related to smart playlists so anyway: is it possible to somehow trigger playlist import without full scan? Quick scan don't import playlists from what I can see.

deluan commented 11 months ago

I'm not sure if it's the right place to ask this, but it's also related to smart playlists so anyway

It would've been better to post in our Q&A section, but anyway:

Quick Scan only picks up files (music files, artwork and playlists) that had their timestamp updated since last scan. So if you edit a playlist, or "touch" it from the command line, Quick Scan should reimport it.

SubZeroPL commented 11 months ago

It would've been better to post in our Q&A section, but anyway:

Sorry, didn't see that section

Quick Scan only picks up files (music files, artwork and playlists) that had their timestamp updated since last scan. So if you edit a playlist, or "touch" it from the command line, Quick Scan should reimport it.

Okay, thank you for clarification

metalheim commented 11 months ago

With #2162 merged, will it be possible to use releaseDate in smart playlists? This would help me so much in creating some "freshly released" playlists.

deluan commented 11 months ago

With #2162 merged, will it be possible to use releaseDate in smart playlists? This would help me so much in creating some "freshly released" playlists.

Yes, all date fields are available for smart playlists: year, date, originalyear, originaldate, releaseyear, releasedate

SickProdigy commented 11 months ago

Can you use contains with not contains? This is my setup

{
  "all": [
    {"contains": {"genre": "Dubstep"}},
    {"notContains": {"genre": "Death Metal"}},
    {"gt": {"rating": 2}}
  ],
  "sort": "dateModified",
  "limit": 500
}

I want things that contain dubstep but not certain other things also.

cedvan commented 10 months ago

Hi,

What is the progress of phase 2 and phase 3?

certuna commented 10 months ago

I believe all big new UI features are on hold for now until the current UI is migrated from v3 to React Admin v4 - this is pretty major work, but will enable features like infinite pagination.

pjadeslandes commented 10 months ago

Navidrome newbie, loving the smart playlist function. Any chance we could have the mixartist and composer tags added? I've tried them randomly but they don't seem to work.

certuna commented 10 months ago

Composer is not yet added, I'm now testing with Remixer. We cannot do separate composer or remixer fields yet (that would require a bit bigger rework of the internals), but the idea is that the user can set a server option to add the remixer of a song to the list of song artists, like with Spotify/Tidal/Deezer. Then you'd be able to do a {"contains": {"artist": "David Guetta"}} and you'll get a playlist of all songs and remixes by him.

So for example, the song Bob Sinclar feat. Steve Edwards - World, Hold On (David Guetta & Joachim Garraud Remix) would be shown in Navidrome: artist = Bob Sinclar · Steve Edwards · David Guetta · Joachim Garraud title = World, Hold On (David Guetta & Joachim Garraud Remix)

I could do the same with composer but I'm not sure if that's really what users want/expect. Often the composers are individual members of the band ("H. Johnson, R. Smith"), we probably do not want to just append those names to the artist name.

pjadeslandes commented 10 months ago

Thanks as ever @certuna, it will be great to have this capability for remixer.

Now you describe it, I totally agree re composer. Thinking about it, I was probably muddling my thinking with the concept of producer, but that also probably functions best as a standalone field rather than something to combine with artist, so not something to treat like remixer either.

Scrath1 commented 10 months ago

Hi, is there an option to create a smart playlist which additionally includes songs from a manually managed playlist? I see that flingOwl has added such an operator on his fork and I wondered if this was a feature that is also available here by now?

flemmingss commented 9 months ago

I have tried some smart playlist, but can't get them to work.

time="2023-07-28T12:08:06Z" level=error msg="Error parsing SmartPlaylist" error="invalid character ']' looking for beginning of value" playlist=playlist_new_tracks requestId=edc0c38d8dbe/dcUwE442Fa-000127 username=admin
time="2023-07-28T12:08:06Z" level=error msg="Error parsing playlist" error="invalid character ']' looking for beginning of value" path=/music/playlist_new_tracks.nsp requestId=edc0c38d8dbe/dcUwE442Fa-000127 username=admin
time="2023-07-28T12:08:06Z" level=error msg="Error parsing SmartPlaylist" error="invalid character 'a' looking for beginning of object key string" playlist=recently_played requestId=edc0c38d8dbe/dcUwE442Fa-000127 username=admin
time="2023-07-28T12:08:06Z" level=error msg="Error parsing playlist" error="invalid character 'a' looking for beginning of object key string" path=/music/recently_played.nsp requestId=edc0c38d8dbe/dcUwE442Fa-000127 username=admin
time="2023-07-28T12:08:06Z" level=info msg="Finished processing Music Folder" added=5568 deleted=0 elapsed=3m30s folder=/music playlistsImported=0 updated=0

recently_played.nsp:

{
  all [
    {inTheLast {lastPlayed 30}}
  ],
  sort lastPlayed,
  order desc,
  limit 100
}