Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e32bfb63e0 | ||
|
|
4a14e48938 | ||
|
|
d03ce01cb3 | ||
|
|
42ed70df3b | ||
|
|
1c4030a4c6 | ||
|
|
31556fd207 | ||
|
|
42c92caef7 | ||
|
|
7f075fb490 | ||
|
|
53e4cf0a8d | ||
|
|
7a4ef7f312 | ||
|
|
ef34aaa7a7 | ||
|
|
313db2b71a | ||
|
|
84891ef548 | ||
|
|
7177581a4c | ||
|
|
f9993959ed | ||
|
|
6f56f25384 |
@@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.1.2
|
current_version = 0.1.5
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@@ -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
|
||||||
|
|||||||
6
.github/workflows/manual-build.yml
vendored
6
.github/workflows/manual-build.yml
vendored
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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']
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.1.2"
|
__version__ = "0.1.5"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
28
readme.md
28
readme.md
@@ -1,7 +1,7 @@
|
|||||||

|

|
||||||
|
|
||||||
> [!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
|
|
||||||

|

|
||||||
|
|
||||||
|
> [!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 ✌🏽
|
||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.1.2"
|
__version__ = "0.1.5"
|
||||||
|
|||||||
Reference in New Issue
Block a user