From 8c9fb43f010a12b4a9b54153a2c6ea4da0dfb15c Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 17 Dec 2024 17:43:31 +0000 Subject: [PATCH 01/22] fix: update track order in playlist when moving tracks Fixes #53 --- app/tasks.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/tasks.py b/app/tasks.py index c4506dc..44b1ed6 100644 --- a/app/tasks.py +++ b/app/tasks.py @@ -344,6 +344,13 @@ def check_for_playlist_updates(self): db.session.commit() app.logger.info(f'Added new track: {track.name}') tracks_to_add.append((track, idx)) + # else check if the track is already in the playlist and change the track_order in the playlist_tracks table + else: + app.logger.debug(f"track {track_info.track.name} moved to position {idx}") + track = existing_tracks[track_id] + stmt = playlist_tracks.update().where(playlist_tracks.c.playlist_id == playlist.id).where(playlist_tracks.c.track_id == track.id).values(track_order=idx) + db.session.execute(stmt) + db.session.commit() tracks_to_remove = [ existing_tracks[track_id] @@ -385,6 +392,7 @@ def check_for_playlist_updates(self): ).all() tracks = [track.jellyfin_id for track, idx in ordered_tracks if track.jellyfin_id is not None] + #jellyfin.remove_songs_from_playlist(session_token=jellyfin_admin_token, playlist_id=playlist.jellyfin_id, song_ids=tracks) jellyfin.add_songs_to_playlist(session_token=jellyfin_admin_token, user_id=jellyfin_admin_id, playlist_id=playlist.jellyfin_id, song_ids=tracks) #endregion except Exception as e: From 4d06b257cbc1d4a3f602da439dacd4c2a45b02ac Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 17 Dec 2024 17:45:06 +0000 Subject: [PATCH 02/22] feat: add refresh playlist functionality --- app/routes/jellyfin_routes.py | 31 ++++++++++++++++++++++++++ jellyfin/client.py | 17 ++++++++++++++ templates/partials/_playlist_info.html | 23 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/app/routes/jellyfin_routes.py b/app/routes/jellyfin_routes.py index a74cd5c..c1e0d57 100644 --- a/app/routes/jellyfin_routes.py +++ b/app/routes/jellyfin_routes.py @@ -170,6 +170,37 @@ def delete_playlist(playlist_id): except Exception as e: flash(f'Failed to remove item: {str(e)}') +@app.route('/refresh_playlist/', methods=['GET']) +@functions.jellyfin_admin_required +def refresh_playlist(playlist_id): + # get the playlist from the database using the playlist_id + playlist = Playlist.query.filter_by(jellyfin_id=playlist_id).first() + # if the playlist has a jellyfin_id, then fetch the playlist from Jellyfin + if playlist.jellyfin_id: + try: + app.logger.debug(f"removing all tracks from playlist {playlist.jellyfin_id}") + jellyfin_playlist = jellyfin.get_music_playlist(session_token=functions._get_api_token(), playlist_id=playlist.jellyfin_id) + jellyfin.remove_songs_from_playlist(session_token=functions._get_token_from_sessioncookie(), playlist_id=playlist.jellyfin_id, song_ids=[track for track in jellyfin_playlist['ItemIds']]) + ordered_tracks = db.session.execute( + db.select(Track, playlist_tracks.c.track_order) + .join(playlist_tracks, playlist_tracks.c.track_id == Track.id) + .where(playlist_tracks.c.playlist_id == playlist.id) + .order_by(playlist_tracks.c.track_order) + ).all() + + tracks = [track.jellyfin_id for track, idx in ordered_tracks if track.jellyfin_id is not None] + #jellyfin.remove_songs_from_playlist(session_token=jellyfin_admin_token, playlist_id=playlist.jellyfin_id, song_ids=tracks) + jellyfin.add_songs_to_playlist(session_token=functions._get_api_token(), user_id=functions._get_admin_id(), playlist_id=playlist.jellyfin_id, song_ids=tracks) + # if the playlist is found, then update the playlist metadata + provider_playlist = MusicProviderRegistry.get_provider(playlist.provider_id).get_playlist(playlist.provider_playlist_id) + functions.update_playlist_metadata(playlist, provider_playlist) + flash('Playlist refreshed') + return jsonify({'success': True}) + + except Exception as e: + flash(f'Failed to refresh playlist: {str(e)}') + return jsonify({'success': False}) + @app.route('/wipe_playlist/', methods=['DELETE']) @functions.jellyfin_admin_required diff --git a/jellyfin/client.py b/jellyfin/client.py index 0b6749b..a6cca1f 100644 --- a/jellyfin/client.py +++ b/jellyfin/client.py @@ -118,6 +118,23 @@ class JellyfinClient: return {"status": "success", "message": "Playlist updated successfully"} else: raise Exception(f"Failed to update playlist: {response.content}") + + def get_music_playlist(self, session_token : str, playlist_id: str): + """ + Get a music playlist by its ID. + :param playlist_id: The ID of the playlist to fetch. + :return: The playlist object + """ + url = f'{self.base_url}/Playlists/{playlist_id}' + self.logger.debug(f"Url={url}") + + response = requests.get(url, headers=self._get_headers(session_token=session_token), timeout = self.timeout) + self.logger.debug(f"Response = {response.status_code}") + + if response.status_code == 200: + return response.json() + else: + raise Exception(f"Failed to get playlist: {response.content}") def get_playlist_metadata(self, session_token: str, user_id: str,playlist_id: str) -> PlaylistMetadata: url = f'{self.base_url}/Items/{playlist_id}' diff --git a/templates/partials/_playlist_info.html b/templates/partials/_playlist_info.html index 656ae86..35dfffb 100644 --- a/templates/partials/_playlist_info.html +++ b/templates/partials/_playlist_info.html @@ -9,6 +9,29 @@

{{ item.track_count }} songs, {{ total_duration }}

Last Updated: {{ item.last_updated}} | Last Change: {{ item.last_changed}}

{% include 'partials/_add_remove_button.html' %} + {% if session['is_admin'] and item.jellyfin_id %} +

+ + +

+ {% endif %} + \ No newline at end of file From fffeac8c746fa0ceb0804ee03ce3e712817755c0 Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 17 Dec 2024 17:45:15 +0000 Subject: [PATCH 03/22] fix: update Monaco Editor version in log view template --- templates/admin/logview.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/admin/logview.html b/templates/admin/logview.html index 1873595..f39c744 100644 --- a/templates/admin/logview.html +++ b/templates/admin/logview.html @@ -5,7 +5,7 @@ {% set logs = "Logfile empty or not found" %} {% endif %} {% set log_level = config['LOG_LEVEL'] %} - +

Log Viewer

From b9530a159c6a43b77c50cef28bd8ff149df9a8fb Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 17 Dec 2024 17:51:22 +0000 Subject: [PATCH 04/22] feat: make playlist item image clickable to view details --- templates/partials/playlist_item.html | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/templates/partials/playlist_item.html b/templates/partials/playlist_item.html index 475499c..1aeac07 100644 --- a/templates/partials/playlist_item.html +++ b/templates/partials/playlist_item.html @@ -20,7 +20,10 @@ @@ -30,17 +33,10 @@

{{ item.description }}

- {% if item.type == 'category'%} - - - - {%else%} - - {%endif%} {% include 'partials/_add_remove_button.html' %}
From 917ec9542f25311cfe5d8dc08416739a88d49f38 Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 18 Dec 2024 09:00:12 +0000 Subject: [PATCH 05/22] feat: add human-readable datetime filter and update playlist info template --- app/filters.py | 7 ++++++- templates/partials/_playlist_info.html | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/filters.py b/app/filters.py index c4ff498..97b188e 100644 --- a/app/filters.py +++ b/app/filters.py @@ -96,4 +96,9 @@ def jellyfin_link(jellyfin_id: str) -> Markup: return Markup(f"JELLYFIN_SERVER_URL not configured") link = f"{jellyfin_server_url}/web/#/details?id={jellyfin_id}" - return Markup(f'{jellyfin_id}') \ No newline at end of file + return Markup(f'{jellyfin_id}') + +# A template filter for displaying a datetime in a human-readable format +@template_filter('human_datetime') +def human_datetime(dt) -> str: + return dt.strftime('%Y-%m-%d %H:%M:%S') \ No newline at end of file diff --git a/templates/partials/_playlist_info.html b/templates/partials/_playlist_info.html index 35dfffb..1101543 100644 --- a/templates/partials/_playlist_info.html +++ b/templates/partials/_playlist_info.html @@ -7,7 +7,7 @@

{{ item.name }}

{{ item.description }}

{{ item.track_count }} songs, {{ total_duration }}

-

Last Updated: {{ item.last_updated}} | Last Change: {{ item.last_changed}}

+

Last Updated: {{ item.last_updated | human_datetime}} | Last Change: {{ item.last_changed | human_datetime}}

{% include 'partials/_add_remove_button.html' %} {% if session['is_admin'] and item.jellyfin_id %}

From 580906dc7864ca459b1f69e7c1446c74d53b96f5 Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 18 Dec 2024 09:22:34 +0000 Subject: [PATCH 06/22] feat: add Jellyfin link button filter and integrate into playlist info template --- app/filters.py | 11 +++++++++++ templates/partials/_playlist_info.html | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/filters.py b/app/filters.py index 97b188e..d3c047f 100644 --- a/app/filters.py +++ b/app/filters.py @@ -98,6 +98,17 @@ def jellyfin_link(jellyfin_id: str) -> Markup: link = f"{jellyfin_server_url}/web/#/details?id={jellyfin_id}" return Markup(f'{jellyfin_id}') +@template_filter('jellyfin_link_button') +def jellyfin_link_btn(jellyfin_id: str) -> Markup: + + jellyfin_server_url = app.config.get('JELLYFIN_SERVER_URL') + if not jellyfin_server_url: + return Markup(f"JELLYFIN_SERVER_URL not configured") + + link = f"{jellyfin_server_url}/web/#/details?id={jellyfin_id}" + return Markup(f'Open in Jellyfin') + + # A template filter for displaying a datetime in a human-readable format @template_filter('human_datetime') def human_datetime(dt) -> str: diff --git a/templates/partials/_playlist_info.html b/templates/partials/_playlist_info.html index 1101543..52d136c 100644 --- a/templates/partials/_playlist_info.html +++ b/templates/partials/_playlist_info.html @@ -9,8 +9,9 @@

{{ item.track_count }} songs, {{ total_duration }}

Last Updated: {{ item.last_updated | human_datetime}} | Last Change: {{ item.last_changed | human_datetime}}

{% include 'partials/_add_remove_button.html' %} - {% if session['is_admin'] and item.jellyfin_id %}

+ {{item.jellyfin_id | jellyfin_link_button}} + {% if session['is_admin'] and item.jellyfin_id %} -

- {% endif %} + {% endif %} +

From 7af86c926febf899c364c6618522a1042a590c0c Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 18 Dec 2024 09:23:41 +0000 Subject: [PATCH 07/22] refactor: remove preview button from track table template --- templates/partials/_track_table.html | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/templates/partials/_track_table.html b/templates/partials/_track_table.html index 4a0cb0e..8e127cc 100644 --- a/templates/partials/_track_table.html +++ b/templates/partials/_track_table.html @@ -6,7 +6,6 @@ Artist Duration {{provider_id}} - Preview Status Jellyfin @@ -25,18 +24,7 @@ - - {% if track.preview_url %} - - {% else %} - - - - {% endif %} - + {% if not track.downloaded %}