# Jellyfin SmartPlaylist Plugin Smart playlists with Lisp filter engine. This readme contains instructions for the most recent changes in the development branch (`main`). To view the file appropriate for your version select the tag corresponding to your version. The latest version is [v0.2.2.0](https://gitea.redxef.at/redxef/jellyfin-smart-playlist/src/tag/v0.2.2.0). ## How to use After [installing](#installation) the plugin and restarting Jellyfin create a empty file in `config/data/smartplaylists` like this, maybe you want to generate a playlist of your favourite rock songs: ``` $ touch config/data/smartplaylists/Rock.yaml ``` Afterwards run the Task `(re)generate Smart Playlists`, this will rename the `yaml` file and populate it with some default values. You can now adjust the file to your liking. [Go here](examples.md) to see more examples. ```yaml Id: Rock Playlists: - PlaylistId: 24f12e1e-3278-d6d6-0ca4-066e93296c95 UserId: 6eec632a-ff0d-4d09-aad0-bf9e90b14bc6 Name: Rock Program: (begin (invoke item "IsFavoriteOrLiked" (user))) SortProgram: (begin items) Filename: /config/data/smartplaylists/Rock.yaml Enabled: true ``` This is the default configuration and will always match all your favorite songs (and songs which are in favourited albums). To change the filter you can append a `|` (pipe) to the Program line and write multiline filters like this: ```yaml Porgram: | (begin (invoke item "IsFavoriteOrLiked" (list user))) ``` This is equivalent to the above example (not counting the other fields obviously). ### Id Arbitrary Id assigned to this playlist, can usually be left alone. ### Playlists A list of Playlist/User mappings. By default all users get an entry. The ids must have the dashes in them as of now. To convert a id from without dashes to the canonical form run this command: `echo '' | python3 -c 'import uuid; import sys; print(uuid.UUID(sys.stdin.read().strip()))'` To get your user id navigate to your user profile and copy the part after `userId` in the address bar. #### PlaylistId The id of the playlist that should be managed, must be owned by the corresponding user. #### UserId The user associated with this playlist. ### Name The name of the generated playlists, this is just a default value. If the user changes the name of their playlist the plugin will still work and remember the correct playlist. ### Program A lisp program to decide on a per item basis if it should be included in the playlist, return `nil` to not include items, return any other value to include them. Global variables `user` and `item` are predefined and contain a [User](https://github.com/jellyfin/jellyfin/blob/master/Jellyfin.Data/Entities/User.cs) and [BaseItem](https://github.com/jellyfin/jellyfin/blob/master/MediaBrowser.Controller/Entities/BaseItem.cs) respectively. **!!! The filter expression will include all items matching, if you do not specify the kind of item to include/exclude all of them will be added. Should you allow a playlist to be included all of it's items will be added to the generated playlist !!!** It's best to be explicit and always specify the item kinds you want to include: `(and (or (is-type "MusicAlbum") (is-type "Audio")) . rest of filter)`. The configuration page defines some useful functions to make it easier to create filters. The above filter for liked items could be simplified to: `(is-favourite)`. ### SortProgram This works exactly like [Program](#program), but the input is the user and a list of items (`items`) matched by [Program](#program). The default is `(begin items)`, which doesn't sort at all. To sort the items by name you could use the following program: ```lisp (qsort (lambda (a b) (string> (car (getitems a "Name")) (car (getitems b "Name")))) items) ``` #### Available definitions - **lower**: lowercases a string (`(eq (lower "SomeString") "somestring")`) - **is-genre**: check if the item is of this genre, partial matches allowed, the example filter would match the genre "Nu-Metal" (`(is-genre "metal" (genre-list))`) - **is-genre-exact**: the same as `is-genre`, but does not match paritally - **is-favorite**: matches a favorite item (`(is-favorite)`) - **is-type**: matches the type of item look at [BaseItemKind.cs](https://github.com/jellyfin/jellyfin/blob/master/Jellyfin.Data/Enums/BaseItemKind.cs) for a list of items. The plugin has enabled support for `Audio, MusicAlbum, Playlist` (`(is-type "Audio")`) ### Filename The path to this file, only used internally and updated by the program. ### Enabled Enable this playlist, currently ignored. ## Installation Add the [plugin repository](https://jellyfin.org/docs/general/server/plugins/#catalog) to Jellyfin: `https://gitea.redxef.at/redxef/jellyfin-smart-playlist/raw/branch/manifest/manifest.json` Go to `Dashboard>Catalog>(Gear)>(Plus)` and paste the provided link into the field labeled `Repository URL`, give the plugin a descriptive name too. ## Releasing a new version 1. Write the changelog: `git log --oneline $prev_version..` 2. Update the following files to include up-to-date version numbers and changelogs, if applicable: - `README.md` - `Jellyfin.Plugin.SmartPlaylist/build.yaml` - `Jellyfin.Plugin.SmartPlaylist/jellyfin-smart-playlist.csproj` Don't forget to also bump the ABI version of Jellyfin. 3. Push the changes 4. Create a new release with the changelog, mark as pre-release if applicable. 5. Done! The build pipeline will do the rest.