Skip to content

Releases: kamilkosek/jellyplist

Release v0.1.9

13 Dec 23:20
69c5f70
Compare
Choose a tag to compare

Whats up in Jellyplist v0.1.9?

⚠️ BREAKING CHANGE: docker-compose.yml

Warning

In this release I´ve done some rework so now the setup is a bit easier, because you don´t have to spin up the -worker -beat container, these are now all in the default container and managed via supervisor. This means you have to update your docker-compose.yml when updating!

So now your compose file should look more or less like this

services:
  redis:
    image: redis:7-alpine
    container_name: redis
    volumes:
      - redis_data:/data
    networks:
      - jellyplist-network
  postgres:
    container_name: postgres-jellyplist
    image: postgres:17.2
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      PGDATA: /data/postgres
    volumes:
       - /jellyplist_pgdata/postgres:/data/postgres
    networks:
      - jellyplist-network
    restart: unless-stopped
  
  jellyplist:
    container_name: jellyplist
    image: ${IMAGE}
    depends_on: 
      - postgres
      - redis
    ports:
      - "5055:5055"
    networks:
      - jellyplist-network
    volumes:
      - /jellyplist/cookies.txt:/jellyplist/cookies.txt
      - /jellyplist/open.spotify.com_cookies.txt:/jellyplist/spotify-cookie.txt
      - ${MUSIC_STORAGE_BASE_PATH}:${MUSIC_STORAGE_BASE_PATH}
      - /my/super/cool/storage/jellyplist/settings.yaml:/jellyplist/settings.yaml
    env_file:
      - .env

networks:
  jellyplist-network:
    driver: bridge

volumes:
    postgres:
    redis_data:

And the .env File

IMAGE = ghcr.io/kamilkosek/jellyplist:latest
POSTGRES_USER = jellyplist
POSTGRES_PASSWORD = jellyplist
SECRET_KEY = supersecretkey  # Secret key for session management
JELLYFIN_SERVER_URL = http://<jellyfin_server>:8096  # Default to local Jellyfin server
JELLYFIN_ACCESS_TOKEN = <jellyfin access token>
JELLYFIN_ADMIN_USER = <jellyfin admin username>
JELLYFIN_ADMIN_PASSWORD = <jellyfin admin password>
SPOTIFY_CLIENT_ID = <spotify client id>
SPOTIFY_CLIENT_SECRET = <spotify client secret>
JELLYPLIST_DB_HOST = postgres-jellyplist
JELLYPLIST_DB_USER = jellyplist
JELLYPLIST_DB_PASSWORD = jellyplist
LOG_LEVEL = INFO
LIDARR_API_KEY = <lidarr api key>
LIDARR_URL = http://<lidarr server>:8686
LIDARR_MONITOR_ARTISTS = false
SPOTIFY_COOKIE_FILE = '/jellyplist/spotify-cookie.txt'
MUSIC_STORAGE_BASE_PATH = '/storage/media/music'

🆕 Log Viewer

Under the Admin Page there is now a tab called Logs from where you can view the current logs, change the log-level on demand and copy a prepared markdown snippet ready to be pasted into a GitHub issue.

🆕 New env var´s, a bit more control over spotDL

SPOTDL_PROXY

Set a Proxy for spotDL. See https://spotdl.readthedocs.io/en/latest/usage/#command-line-options

SPOTDL_OUTPUT_FORMAT

Set the output folder and file name format for downloaded tracks via spotDL. Not all variables, which are supported by spotDL are supported by Jellyplist.

  • {title}
  • {artist}
  • {artists}
  • {album}

This way you will have a bit more controler over how the files are stored.
The complete output path is joined from MUSIC_STORAGE_BASE_PATH and SPOTDL_OUTPUT_FORMAT

Example:

MUSIC_STORAGE_BASE_PATH = /storage/media/music

and

SPOTDL_OUTPUT_FORMAT = /{artist}/{album}/{title}

The Track is All I Want for Christmas Is You by Mariah Carey this will result in the following folder structure:

/storage/media/music/Mariah Carey/Merry Christmas/All I Want for Christmas Is You.mp3

🆕 Admin Users can now add Playlists to multiple Users

Sometimes I want to add a playlist to several users at once, because it´s either a generic one or because my wife doesn´t want to bother with the technical stuff 😬
So now, when logged in as an admin user, when adding a playlist you can select users from your Jellyfin server which will also receive it.
Under Admin you can also select users which will be preselected by default. These will be stored in the file settings.yaml.
You can or should map this file to a file outside the container, so it will persist accross image updates (see compose sample above)

🆕 New env var QUALITY_SCORE_THRESHOLD

Get a better control over the update_jellyfin_id_for_downloaded_tracks() behaviour.
Until now this tasks performed a full update every 24h: This means, every track from every playlist was searched through the Jellyfin API with the hope of finding the same track but with a better quality. While this is ok and works fine for small libraries, this tasks eats a lot of power on large libraries and also takes time.
So there is now the new env variable QUALITY_SCORE_THRESHOLD (default: 1000.0). When a track was once found with a quality score above 1000.0, Jellyplist wont try to perform another quality update anymore on this track.
In order to be able to classify it a little better, here are a few common quality scores:

  • spotDL downloaded track without yt-music premium: < 300
  • spotDL downloaded track with yt-music premium: < 450
  • flac > 1000

Tip

Want to know what quality score (and many other details) a track has ? Just double-click the table row in the playlist details view to get all the info´s!

Other changes, improvements and fixes

  • Fix for #38 and #22 , where the manual task starting was missing a return value
  • Fixed an issue where the content-type of a playlist cover image, would cause the Jellyfin API Client to fail. Thanks @artyorsh
  • Fixed missing lock keys to task manager and task status rendering
  • Pinned postgres version to 17.2
  • Enhanced error logging in tasks
  • several fixes and improvements for the Jellyfin API Client

What's Changed

Full Changelog: 0.1.8...v0.1.9

dev Release v0.1.9

13 Dec 08:35
Compare
Choose a tag to compare

Whats up in Jellyplist v0.1.9?

⚠️ BREAKING CHANGE: docker-compose.yml

Warning

In this release I´ve done some rework so now the setup is a bit easier, because you don´t have to spin up the -worker -beat container, these are now all in the default container and managed via supervisor. This means you have to update your docker-compose.yml when updating!

So now your compose file should look more or less like this

services:
  redis:
    image: redis:7-alpine
    container_name: redis
    volumes:
      - redis_data:/data
    networks:
      - jellyplist-network
  postgres:
    container_name: postgres-jellyplist
    image: postgres:17.2
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      PGDATA: /data/postgres
    volumes:
       - /jellyplist_pgdata/postgres:/data/postgres
    networks:
      - jellyplist-network
    restart: unless-stopped
  
  jellyplist:
    container_name: jellyplist
    image: ${IMAGE}
    depends_on: 
      - postgres
      - redis
    ports:
      - "5055:5055"
    networks:
      - jellyplist-network
    volumes:
      - /jellyplist/cookies.txt:/jellyplist/cookies.txt
      - /jellyplist/open.spotify.com_cookies.txt:/jellyplist/spotify-cookie.txt
      - ${MUSIC_STORAGE_BASE_PATH}:${MUSIC_STORAGE_BASE_PATH}
    env_file:
      - .env

networks:
  jellyplist-network:
    driver: bridge

volumes:
    postgres:
    redis_data:

And the .env File

IMAGE = ghcr.io/kamilkosek/jellyplist:latest
POSTGRES_USER = jellyplist
POSTGRES_PASSWORD = jellyplist
SECRET_KEY = supersecretkey  # Secret key for session management
JELLYFIN_SERVER_URL = http://<jellyfin_server>:8096  # Default to local Jellyfin server
JELLYFIN_ACCESS_TOKEN = <jellyfin access token>
JELLYFIN_ADMIN_USER = <jellyfin admin username>
JELLYFIN_ADMIN_PASSWORD = <jellyfin admin password>
SPOTIFY_CLIENT_ID = <spotify client id>
SPOTIFY_CLIENT_SECRET = <spotify client secret>
JELLYPLIST_DB_HOST = postgres-jellyplist
JELLYPLIST_DB_USER = jellyplist
JELLYPLIST_DB_PASSWORD = jellyplist
LOG_LEVEL = INFO
LIDARR_API_KEY = <lidarr api key>
LIDARR_URL = http://<lidarr server>:8686
LIDARR_MONITOR_ARTISTS = false
SPOTIFY_COOKIE_FILE = '/jellyplist/spotify-cookie.txt'
MUSIC_STORAGE_BASE_PATH = '/storage/media/music'

🆕 Log Viewer

Under the Admin Page there is now a tab called Logs from where you can view the current logs, change the log-level on demand and copy a prepared markdown snippet ready to be pasted into a GitHub issue.

🆕 New env var´s, a bit more control over spotDL

SPOTDL_PROXY

Set a Proxy for spotDL. See https://spotdl.readthedocs.io/en/latest/usage/#command-line-options

SPOTDL_OUTPUT_FORMAT

Set the output folder and file name format for downloaded tracks via spotDL. Not all variables, which are supported by spotDL are supported by Jellyplist.

  • {title}
  • {artist}
  • {artists}
  • {album}

This way you will have a bit more controler over how the files are stored.
The complete output path is joined from MUSIC_STORAGE_BASE_PATH and SPOTDL_OUTPUT_FORMAT

Other changes, improvements and fixes

  • Fix for #38 and #22 , where the manual task starting was missing a return value
  • Fixed an issue where the content-type of a playlist cover image, would cause the Jellyfin API Client to fail. Thanks @artyorsh
  • Fixed missing lock keys to task manager and task status rendering
  • Pinned postgres version to 17.2

Full Changelog: 0.1.8...v0.1.9-dev-1b95f20

Release 0.1.8

06 Dec 00:50
804b2bf
Compare
Choose a tag to compare

Whats up in Jellyplist 0.1.8?

Not much this time, just some small fixes and one enhancement.

🆕Jellyplist now checks for updates

Jellyplist now checks the GitHub releases for new version.
If a new version is available, you will notice the small badge on the lower left will pulsate slighty, so you don´t miss any new release 😄

If you don´t like that Jellyplist is doing this, you can opt out by setting this env var in your .env file

CHECK_FOR_UPDATES = false

Other changes, improvements and fixes

  • Fix for #30 , where the output path for spotDL wasn´t created correctly

Release 0.1.7

05 Dec 00:01
14a8fdc
Compare
Choose a tag to compare

Whats up in Jellyplist 0.1.7?

Major overhaul

I´ve been working the past week to make this project work again, after Spotify announced to deprecate the playlist discover API´s , which were a crucial part of this project.
I also took this opportunity at the same time to do a major overhaul, on how Jellyplist gathers data from a music provider. Music provider API implementations must now implement defined abstract classes to work with Jellyplist, think of it like plugins. Jellyplist now, in theory, can gather data from any music provider - just the plugins must be written. It also doesn´t matter, if it have 1,2 or 10 Music Providers to playlists. So stay tuned for more to come.
The next ones will be Deezer and YTM

After the providers will be implemented, I will at some point do the same with the media backend - so Jellyplist will be able to support other media backends like Navidrome, Plex, Emby and so on...

🆕New API Implementation for Spotify

As mentioned above, I needed a new way to get playlists.
Now, to get them , you don´t need an API Key to authenticate, you even don´t need to be authenticated at all. If you like to have Playlists recommended or created for you, you can use authentication via a cookie.
To do this, add a env var to you .env file:

SPOTIFY_COOKIE_FILE = '/jellyplist/spotify-cookie.txt'

And map the cookie from your local filesystem to the container path you´ve set in the .envfile

...
...
 volumes:
      - /your/local/path/open.spotify.com_cookies.txt:${SPOTIFY_COOKIE_FILE}
...
...

🆕Lidarr integration is here

To enable the Lidarr integration add these to your .env file

LIDARR_API_KEY = aabbccddeeffgghh11223344 # self explaining
LIDARR_URL = http://<your_lidarr_ip>:8686 # too
LIDARR_MONITOR_ARTISTS = false # If false, only the corresponding
# album will be set to monitored in lidarr, if true the whole artist 
# will be set as monitored. Be careful in the beginning as you might 
# hammer your lidarr instance and you indexers. Defaults to false

After you enabled Lidarr integration, make sure to go to "Admin -> Lidarr" and set the default quality profile and music root folder.

With the Lidarr integration you get a nice workflow:

  1. Add Playlist
  2. Playlist gets downloaded via SpotDL and is available after some time
  3. At some point (every hour on x:50) the requests to Lidarr are made.
  4. Lidarr gets all files.
  5. Once a day Jellyplist is doing a full update on all tracks, and searches for the same track but with a better quality profile.

⚠️ New required env var

Ensure to add MUSIC_STORAGE_BASE_PATH to your .env file.

MUSIC_STORAGE_BASE_PATH = '/storage/media/music' # The base path where
# your music library is located. 
# Must be the same value as your music library in jellyfin

Other changes, improvements and fixes

  • UI/UX: The index page now has content. From there you can directly drop a playlist link
  • UI/UX: The Search bar now works with the new API implementation
  • UI/UX: A new Browse All (per Music Provider) Page from where you can discover playlists
  • UI/UX: Check technical details on a track. Just doubleclick a row in the details view of a playlist.
  • UI/UX: Allow to link a track even it´s not marked as downloaded.
  • UI/UX: Reworked celery task management and the /admin/tasks UI

Release 0.1.6

26 Nov 15:54
6ec7e22
Compare
Choose a tag to compare

Whats up in Jellyplist 0.1.6?

🆕Better Linking (in preparation for Lidarr integration)

During the link-task (update_jellyfin_id_for_downloaded_tracks), where Jellyplist tries to link a Spotify-Track-Id to a Jellyfin-Track-Id it performs now a search and tries to find a best match from the results also considering quality aspects of a file.
You can also make use of ffprobe, so jellyplist get´s more detailed information about the quality profile of a file.
To use ffprobe set the environment variable FIND_BEST_MATCH_USE_FFPROBE to true otherwise jellyplist will use quality information provided by the Jellyfin API.
Fixes #14

In the Debug logs it will look like this:

find_best_match_from_jellyfin() ]   DEBUG - Quality score for track Smalltown Boy: 4410.866669999999 [/storage/media/music/Bronski Beat/The Age of Reason (2017)/CD 01/Bronski Beat - The Age of Reason - 05 - Smalltown Boy.flac]
find_best_match_from_jellyfin() ]   DEBUG - Quality score for track Smalltown Boy: 4100.6 [/storage/media/music/Bronski Beat/The Age of Consent (1984)/CD 01/Bronski Beat - The Age of Consent - 06 - Smalltown Boy.flac]
find_best_match_from_jellyfin() ]   DEBUG - Quality score for track Smalltown Boy: 3240.48 [/storage/media/music/__jellyplist/5vmRQ3zELMLUQPo2FLQ76x.mp3]

What´s the benefit?

Once a day, the task update_jellyfin_id_for_downloaded_tracks will do a full update on all tracks. This way you can listen to tracks and make use of the playlists until Lidarr provides you the same track but with better audio quality.

🆕Added REFRESH_LIBRARIES_AFTER_DOWNLOAD_TASK

When setting the new environment variable REFRESH_LIBRARIES_AFTER_DOWNLOAD_TASK to true , jellyplist will trigger a music library update on your Jellyfin server, in case you dont have Realtime Monitoring enabled on your Jellyfin library.
Fixes #10

🆕Removed cookies.txt requirement

No need to use cookies.txt file to download tracks via spotDL

Important

Not using a cookies.txt file will limit the bitrate of downloaded tracks to 128kbit/s 📻

🆕Added LOG_LEVEL

Via the environment variable LOG_LEVEL you can control the log output now. The default python log levels are available:

  • CRITICAL
  • FATAL
  • ERROR
  • WARNING
  • INFO
  • DEBUG
  • NOTSET

🆕Added the possibility for admins to release task lock´s

When a task will crash or whatsoever , the lock won´t be released and you have to wait for it to expire until you can run it manually. Now you can release it manually, in case you need it.

Important

You must be logged in as an admin

🆕Added the possibility for admins to remove playlists completely

This way the playlist will be removed from "monitoring" and also be removed from jellyfin.

Important

You must be logged in as an admin

🆕Allow manual track re-linking

In case something went wrong and you want to assign another Jellyfin track to a Spotify-Track-Id you can do it now manually.
Just go to "View Playlist Details", in the table where the tracks are listed, hold the CTRL Key while clicking on the Play from Jellyfin button. You will be presented with the search modal and can choose whatever track you like.
Fixex #13

🆕Added a badge on the lower left corner indicating the current version

⚒️Overall improvements in logging

Changed log format and also added debug logging where (I think) it´s appropriate.

🐛 Bugfixes

  • Fixed a bug where playlists weren´t updated until the snapshot-id of a playlist changed. Fixes #9
  • Fixed a dependency error, which caused chromaprint fingerprinting to error out. Fixes #12
  • Fixed a paging error, which caused that only the first 100 elements of a playlists were added

Release 0.1.5

23 Nov 10:03
e32bfb6
Compare
Choose a tag to compare

What's Changed

Full Changelog: 0.1.4...0.1.5

Release 0.1.4

22 Nov 22:02
1c4030a
Compare
Choose a tag to compare

What's Changed

Full Changelog: 0.1.3...0.1.4

Release 0.1.3

22 Nov 21:12
7a4ef7f
Compare
Choose a tag to compare

What's Changed

New Contributors

Full Changelog: 0.1.2...0.1.3

Release 0.1.2

22 Nov 20:30
Compare
Choose a tag to compare