16 Commits
0.1.2 ... 0.1.5

Author SHA1 Message Date
Kamil Kosek
e32bfb63e0 Merge pull request #4 from kamilkosek/dev
Merge 0.1.5 to main
2024-11-23 11:02:13 +01:00
Kamil
4a14e48938 Bump version: 0.1.4 → 0.1.5 2024-11-23 09:52:40 +00:00
Kamil
d03ce01cb3 readme update 2024-11-23 09:52:33 +00:00
Kamil
42ed70df3b updated config key name 2024-11-23 09:52:26 +00:00
Kamil Kosek
1c4030a4c6 Merge pull request #3 from kamilkosek/dev
Merge 0.1.4 into main
2024-11-22 23:00:05 +01:00
Kamil
31556fd207 Merge branch 'dev' of https://github.com/kamilkosek/jellyplist into dev 2024-11-22 21:58:03 +00:00
Kamil
42c92caef7 Bump version: 0.1.3 → 0.1.4 2024-11-22 21:56:48 +00:00
Kamil
7f075fb490 fixed wrong function call 2024-11-22 21:56:29 +00:00
Kamil
53e4cf0a8d try some normalization on search query 2024-11-22 21:56:15 +00:00
Kamil Kosek
7a4ef7f312 Merge pull request #2 from kamilkosek/dev
Merge 0.1.3 into main
2024-11-22 22:10:39 +01:00
Kamil
ef34aaa7a7 Bump version: 0.1.2 → 0.1.3 2024-11-22 21:08:10 +00:00
Kamil
313db2b71a use get_cached_spotify_track 2024-11-22 21:07:06 +00:00
Kamil Kosek
84891ef548 Merge pull request #1 from kamilkosek/dev
Merge dev into main
2024-11-22 22:03:34 +01:00
Kamil
7177581a4c Publish "latest" on main branch 2024-11-22 21:02:33 +00:00
Kamil
f9993959ed publish with multiple tags 2024-11-22 20:48:20 +00:00
Kamil
6f56f25384 do not use clean query 2024-11-22 20:37:19 +00:00
11 changed files with 47 additions and 22 deletions

View File

@@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.1.2 current_version = 0.1.5
commit = True commit = True
tag = True tag = True

View File

@@ -38,7 +38,9 @@ jobs:
with: with:
context: . context: .
push: true push: true
tags: ghcr.io/${{ github.repository }}:${{ env.VERSION }} tags: |
ghcr.io/${{ github.repository }}:${{ env.VERSION }}
ghcr.io/${{ github.repository }}:latest
# Create a release on GitHub # Create a release on GitHub
- name: Create GitHub Release - name: Create GitHub Release

View File

@@ -37,4 +37,8 @@ jobs:
with: with:
context: . context: .
push: true push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }} tags: |
ghcr.io/${{ github.repository }}:${{ github.sha }}
ghcr.io/${{ github.repository }}:dev

View File

@@ -111,8 +111,8 @@ cache = Cache(app)
# Spotify, Jellyfin, and Spotdl setup # Spotify, Jellyfin, and Spotdl setup
app.logger.info(f"setting up spotipy") app.logger.info(f"setting up spotipy")
sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials( sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(
client_id=app.config['SPOTIPY_CLIENT_ID'], client_id=app.config['SPOTIFY_CLIENT_ID'],
client_secret=app.config['SPOTIPY_CLIENT_SECRET'] client_secret=app.config['SPOTIFY_CLIENT_SECRET']
)) ))
app.logger.info(f"setting up jellyfin client") app.logger.info(f"setting up jellyfin client")

View File

@@ -103,7 +103,7 @@ def add_playlist():
db.session.execute(stmt) db.session.execute(stmt)
db.session.commit() db.session.commit()
update_playlist_metadata(playlist,playlist_data) functions.update_playlist_metadata(playlist,playlist_data)
if playlist not in user.playlists: if playlist not in user.playlists:
user.playlists.append(playlist) user.playlists.append(playlist)

View File

@@ -78,8 +78,8 @@ def download_missing_tracks(self):
spotdl_config = app.config['SPOTDL_CONFIG'] spotdl_config = app.config['SPOTDL_CONFIG']
cookie_file = spotdl_config['cookie_file'] cookie_file = spotdl_config['cookie_file']
output_dir = spotdl_config['output'] output_dir = spotdl_config['output']
client_id = app.config['SPOTIPY_CLIENT_ID'] client_id = app.config['SPOTIFY_CLIENT_ID']
client_secret = app.config['SPOTIPY_CLIENT_SECRET'] client_secret = app.config['SPOTIFY_CLIENT_SECRET']
search_before_download = app.config['SEARCH_JELLYFIN_BEFORE_DOWNLOAD'] search_before_download = app.config['SEARCH_JELLYFIN_BEFORE_DOWNLOAD']
undownloaded_tracks = Track.query.filter_by(downloaded=False).all() undownloaded_tracks = Track.query.filter_by(downloaded=False).all()
@@ -108,7 +108,7 @@ def download_missing_tracks(self):
if search_before_download: if search_before_download:
app.logger.info(f"Searching for track in Jellyfin: {track.name}") app.logger.info(f"Searching for track in Jellyfin: {track.name}")
# Retrieve the Spotify track and preview URL # Retrieve the Spotify track and preview URL
spotify_track = sp.track(track.spotify_track_id) spotify_track = functions.get_cached_spotify_track(track.spotify_track_id)
preview_url = spotify_track.get('preview_url') preview_url = spotify_track.get('preview_url')
if not preview_url: if not preview_url:
app.logger.error(f"Preview URL not found for track {track.name}.") app.logger.error(f"Preview URL not found for track {track.name}.")
@@ -342,7 +342,7 @@ def update_jellyfin_id_for_downloaded_tracks(self):
break break
elif not spotify_track: elif not spotify_track:
try: try:
spotify_track = sp.track(track.spotify_track_id) spotify_track = functions.get_cached_spotify_track(track.spotify_track_id)
spotify_track_name = spotify_track['name'] spotify_track_name = spotify_track['name']
spotify_artists = [artist['name'] for artist in spotify_track['artists']] spotify_artists = [artist['name'] for artist in spotify_track['artists']]
spotify_album = spotify_track['album']['name'] spotify_album = spotify_track['album']['name']

View File

@@ -1 +1 @@
__version__ = "0.1.2" __version__ = "0.1.5"

View File

@@ -7,8 +7,8 @@ class Config:
JELLYFIN_SERVER_URL = os.getenv('JELLYFIN_SERVER_URL') JELLYFIN_SERVER_URL = os.getenv('JELLYFIN_SERVER_URL')
JELLYFIN_ADMIN_USER = os.getenv('JELLYFIN_ADMIN_USER') JELLYFIN_ADMIN_USER = os.getenv('JELLYFIN_ADMIN_USER')
JELLYFIN_ADMIN_PASSWORD = os.getenv('JELLYFIN_ADMIN_PASSWORD') JELLYFIN_ADMIN_PASSWORD = os.getenv('JELLYFIN_ADMIN_PASSWORD')
SPOTIPY_CLIENT_ID = os.getenv('SPOTIPY_CLIENT_ID') SPOTIFY_CLIENT_ID = os.getenv('SPOTIFY_CLIENT_ID')
SPOTIPY_CLIENT_SECRET = os.getenv('SPOTIPY_CLIENT_SECRET') SPOTIFY_CLIENT_SECRET = os.getenv('SPOTIFY_CLIENT_SECRET')
JELLYPLIST_DB_HOST = os.getenv('JELLYPLIST_DB_HOST') JELLYPLIST_DB_HOST = os.getenv('JELLYPLIST_DB_HOST')
JELLYPLIST_DB_USER = os.getenv('JELLYPLIST_DB_USER') JELLYPLIST_DB_USER = os.getenv('JELLYPLIST_DB_USER')
JELLYPLIST_DB_PASSWORD = os.getenv('JELLYPLIST_DB_PASSWORD') JELLYPLIST_DB_PASSWORD = os.getenv('JELLYPLIST_DB_PASSWORD')
@@ -36,8 +36,8 @@ class Config:
'JELLYFIN_SERVER_URL': cls.JELLYFIN_SERVER_URL, 'JELLYFIN_SERVER_URL': cls.JELLYFIN_SERVER_URL,
'JELLYFIN_ADMIN_USER': cls.JELLYFIN_ADMIN_USER, 'JELLYFIN_ADMIN_USER': cls.JELLYFIN_ADMIN_USER,
'JELLYFIN_ADMIN_PASSWORD': cls.JELLYFIN_ADMIN_PASSWORD, 'JELLYFIN_ADMIN_PASSWORD': cls.JELLYFIN_ADMIN_PASSWORD,
'SPOTIPY_CLIENT_ID': cls.SPOTIPY_CLIENT_ID, 'SPOTIFY_CLIENT_ID': cls.SPOTIFY_CLIENT_ID,
'SPOTIPY_CLIENT_SECRET': cls.SPOTIPY_CLIENT_SECRET, 'SPOTIFY_CLIENT_SECRET': cls.SPOTIFY_CLIENT_SECRET,
'JELLYPLIST_DB_HOST' : cls.JELLYPLIST_DB_HOST, 'JELLYPLIST_DB_HOST' : cls.JELLYPLIST_DB_HOST,
'JELLYPLIST_DB_USER' : cls.JELLYPLIST_DB_USER, 'JELLYPLIST_DB_USER' : cls.JELLYPLIST_DB_USER,
'JELLYPLIST_DB_PASSWORD' : cls.JELLYPLIST_DB_PASSWORD, 'JELLYPLIST_DB_PASSWORD' : cls.JELLYPLIST_DB_PASSWORD,

View File

@@ -182,7 +182,8 @@ class JellyfinClient:
""" """
search_url = f'{self.base_url}/Items' search_url = f'{self.base_url}/Items'
params = { params = {
'SearchTerm': _clean_query(search_query), 'SearchTerm': search_query.replace('\'',"´").replace('','´'),
'IncludeItemTypes': 'Audio', # Search only for audio items 'IncludeItemTypes': 'Audio', # Search only for audio items
'Recursive': 'true', # Search within all folders 'Recursive': 'true', # Search within all folders
'Fields': 'Name,Id,Album,Artists,Path' # Retrieve the name and ID of the song 'Fields': 'Name,Id,Album,Artists,Path' # Retrieve the name and ID of the song

View File

@@ -1,7 +1,7 @@
![Jellyplist Logo](./static/images/logo_large.png) ![Jellyplist Logo](./static/images/logo_large.png)
> [!WARNING] > [!WARNING]
> Jellyplist is still at a very early stage: expect Bugs and weird behaviour > Jellyplist is still at a very early stage: expect Bugs and weird behaviour. Especially the UI and UX are a bit clunky and unresponsive
## What is Jellyplist ? ## What is Jellyplist ?
Jellyplist aims to be a companion app for your self-hosted [Jellyfin](https://jellyfin.org/) Server. With Jellyplist you will be able to replicate/sync playlists from Spotify to your local Jellyfin account. Under the hood, it uses [SpotDL](https://spotdl.readthedocs.io/en/latest/) for downloading the corresponding tracks from the available sources if a track isn´t found in your local library. Jellyplist aims to be a companion app for your self-hosted [Jellyfin](https://jellyfin.org/) Server. With Jellyplist you will be able to replicate/sync playlists from Spotify to your local Jellyfin account. Under the hood, it uses [SpotDL](https://spotdl.readthedocs.io/en/latest/) for downloading the corresponding tracks from the available sources if a track isn´t found in your local library.
@@ -30,8 +30,8 @@ SECRET_KEY = Keykeykesykykesky # Secret key for session management
JELLYFIN_SERVER_URL = http://192.168.178.14:8096 # local Jellyfin server JELLYFIN_SERVER_URL = http://192.168.178.14:8096 # local Jellyfin server
JELLYFIN_ADMIN_USER = admin # due to api limitations jellyplist uses user authentication rather than api tokens JELLYFIN_ADMIN_USER = admin # due to api limitations jellyplist uses user authentication rather than api tokens
JELLYFIN_ADMIN_PASSWORD = admin_password_for_your_jellyifn_admin JELLYFIN_ADMIN_PASSWORD = admin_password_for_your_jellyifn_admin
SPOTIPY_CLIENT_ID = <Client ID from Step 1> SPOTIFY_CLIENT_ID = <Client ID from Step 1>
SPOTIPY_CLIENT_SECRET = <Secret from Step 1> SPOTIFY_CLIENT_SECRET = <Secret from Step 1>
JELLYPLIST_DB_HOST = postgres-jellyplist #Hostname of the db Container JELLYPLIST_DB_HOST = postgres-jellyplist #Hostname of the db Container
JELLYPLIST_DB_USER = jellyplist JELLYPLIST_DB_USER = jellyplist
JELLYPLIST_DB_PASSWORD = jellyplist JELLYPLIST_DB_PASSWORD = jellyplist
@@ -158,7 +158,25 @@ Jellyplist will cache requests where possible. Especially the `/tracks` endpoint
- When logged in as admin, you will see the admin section in the sidebar. From there you can some kind of `batch linking`. All unlinked tracks will be displayed at once. - When logged in as admin, you will see the admin section in the sidebar. From there you can some kind of `batch linking`. All unlinked tracks will be displayed at once.
> [!TIP]
> Linking of tracks had to be done only once. If a different playlist has the same track, Jellyplist will reuse the link
![Jellyplist batch link](./screenshots/batch_link.png) ![Jellyplist batch link](./screenshots/batch_link.png)
> [!TIP]
> Linking of tracks had to be done only once. If a different playlist has the same track, Jellyplist will reuse the link
#### After you added your first playlist´s, the worker and scheduler will take over from this point.
The default schedules are:
| **Schedule Name** | **Task** | **Schedule** |
|--------------------------------------------|----------------------------------------------|----------------------|
| `download-missing-tracks-schedule` | `app.tasks.download_missing_tracks` | Every day at minute 30 |
| `check-playlist-updates-schedule` | `app.tasks.check_for_playlist_updates` | Every day at minute 25 |
| `update_all_playlists_track_status-schedule`| `app.tasks.update_all_playlists_track_status`| Every 2 minutes |
| `update_jellyfin_id_for_downloaded_tracks-schedule` | `app.tasks.update_jellyfin_id_for_downloaded_tracks` | Every 10 minutes |
For now the schedules aren´t configurable, but this is subject to change.
> [!TIP]
> Please be patient after you added your first batch of playlists! Jellyplist currently processes one track at a time, and this means it can take some time for you to see the first results.
Then let Jellyplist do it´s work, after some time you should be able to see the playlist in Jellyfin.
Have Fun ✌🏽

View File

@@ -1 +1 @@
__version__ = "0.1.2" __version__ = "0.1.5"