changed "spotify" to "provider"
This commit is contained in:
146
app/functions.py
146
app/functions.py
@@ -1,4 +1,7 @@
|
||||
import json
|
||||
from typing import Optional
|
||||
from flask import flash, redirect, session, url_for
|
||||
import requests
|
||||
from app.models import JellyfinUser, Playlist,Track
|
||||
from app import sp, cache, app, jellyfin ,jellyfin_admin_token, jellyfin_admin_id,device_id, cache
|
||||
from functools import wraps
|
||||
@@ -57,51 +60,57 @@ def prepPlaylistData(data):
|
||||
|
||||
for playlist_data in data['playlists']['items']:
|
||||
# Fetch the playlist from the database if it exists
|
||||
db_playlist = Playlist.query.filter_by(spotify_playlist_id=playlist_data['id']).first()
|
||||
if playlist_data:
|
||||
db_playlist = Playlist.query.filter_by(provider_playlist_id=playlist_data['id']).first()
|
||||
|
||||
if db_playlist:
|
||||
# If the playlist is in the database, use the stored values
|
||||
if isinstance(playlist_data['tracks'],list):
|
||||
track_count = len(playlist_data['tracks'] )
|
||||
if db_playlist:
|
||||
# If the playlist is in the database, use the stored values
|
||||
if playlist_data.get('tracks'):
|
||||
if isinstance(playlist_data['tracks'],list):
|
||||
track_count = len(playlist_data['tracks'] )
|
||||
else:
|
||||
track_count = playlist_data['tracks']['total'] or 0
|
||||
else:
|
||||
track_count = 0
|
||||
tracks_available = db_playlist.tracks_available or 0
|
||||
tracks_linked = len([track for track in db_playlist.tracks if track.jellyfin_id]) or 0
|
||||
percent_available = (tracks_available / track_count * 100) if track_count > 0 else 0
|
||||
|
||||
# Determine playlist status
|
||||
if not playlist_data.get('status'):
|
||||
if tracks_available == track_count and track_count > 0:
|
||||
playlist_data['status'] = 'green' # Fully available
|
||||
elif tracks_available > 0:
|
||||
playlist_data['status'] = 'yellow' # Partially available
|
||||
else:
|
||||
playlist_data['status'] = 'red' # Not available
|
||||
|
||||
else:
|
||||
track_count = playlist_data['tracks']['total'] or 0
|
||||
tracks_available = db_playlist.tracks_available or 0
|
||||
tracks_linked = len([track for track in db_playlist.tracks if track.jellyfin_id]) or 0
|
||||
percent_available = (tracks_available / track_count * 100) if track_count > 0 else 0
|
||||
|
||||
# Determine playlist status
|
||||
if tracks_available == track_count and track_count > 0:
|
||||
status = 'green' # Fully available
|
||||
elif tracks_available > 0:
|
||||
status = 'yellow' # Partially available
|
||||
else:
|
||||
status = 'red' # Not available
|
||||
else:
|
||||
# If the playlist is not in the database, initialize with 0
|
||||
track_count = 0
|
||||
tracks_available = 0
|
||||
tracks_linked = 0
|
||||
percent_available = 0
|
||||
status = 'red' # Not requested yet
|
||||
# If the playlist is not in the database, initialize with 0
|
||||
track_count = 0
|
||||
tracks_available = 0
|
||||
tracks_linked = 0
|
||||
percent_available = 0
|
||||
playlist_data['status'] = 'red' # Not requested yet
|
||||
|
||||
# Append playlist data to the list
|
||||
playlists.append({
|
||||
'name': playlist_data['name'],
|
||||
'description': playlist_data['description'],
|
||||
'image': playlist_data['images'][0]['url'] if playlist_data['images'] else 'default-image.jpg',
|
||||
'url': playlist_data['external_urls']['spotify'],
|
||||
'id': playlist_data['id'],
|
||||
'jellyfin_id': db_playlist.jellyfin_id if db_playlist else '',
|
||||
'can_add': (db_playlist not in jellyfin_user.playlists) if db_playlist else True,
|
||||
'can_remove' : (db_playlist in jellyfin_user.playlists) if db_playlist else False,
|
||||
'last_updated':db_playlist.last_updated if db_playlist else '',
|
||||
'last_changed':db_playlist.last_changed if db_playlist else '',
|
||||
'tracks_available': tracks_available,
|
||||
'track_count': track_count,
|
||||
'tracks_linked': tracks_linked,
|
||||
'percent_available': percent_available,
|
||||
'status': status # Red, yellow, or green based on availability
|
||||
})
|
||||
# Append playlist data to the list
|
||||
playlists.append({
|
||||
'name': playlist_data['name'],
|
||||
'description': playlist_data['description'],
|
||||
'image': playlist_data['images'][0]['url'] if playlist_data.get('images') else '/static/images/placeholder.png',
|
||||
'url': playlist_data['external_urls']['spotify'] if playlist_data.get('external_urls') else '',
|
||||
'id': playlist_data['id'] if playlist_data['id'] else '',
|
||||
'jellyfin_id': db_playlist.jellyfin_id if db_playlist else '',
|
||||
'can_add': (db_playlist not in jellyfin_user.playlists) if db_playlist else True,
|
||||
'can_remove' : (db_playlist in jellyfin_user.playlists) if db_playlist else False,
|
||||
'last_updated':db_playlist.last_updated if db_playlist else '',
|
||||
'last_changed':db_playlist.last_changed if db_playlist else '',
|
||||
'tracks_available': tracks_available,
|
||||
'track_count': track_count,
|
||||
'tracks_linked': tracks_linked,
|
||||
'percent_available': percent_available,
|
||||
'status': playlist_data['status'] # Red, yellow, or green based on availability
|
||||
})
|
||||
|
||||
return playlists
|
||||
|
||||
@@ -115,24 +124,57 @@ def get_cached_spotify_playlists(playlist_ids):
|
||||
spotify_data = {'playlists': {'items': []}}
|
||||
|
||||
for playlist_id in playlist_ids:
|
||||
playlist_data = get_cached_spotify_playlist(playlist_id)
|
||||
playlist_data = None
|
||||
not_found = False
|
||||
try:
|
||||
playlist_data = get_cached_spotify_playlist(playlist_id)
|
||||
|
||||
except SpotifyException as e:
|
||||
app.logger.error(f"Error Fetching Playlist {playlist_id}: {e}")
|
||||
not_found = 'http status: 404' in str(e)
|
||||
if not_found:
|
||||
playlist_data = {
|
||||
'status':'red',
|
||||
'description': 'Playlist has most likely been removed. You can keep it, but won´t receive Updates.',
|
||||
'id': playlist_id,
|
||||
'name' : ''
|
||||
|
||||
}
|
||||
|
||||
if playlist_data:
|
||||
spotify_data['playlists']['items'].append(playlist_data)
|
||||
else:
|
||||
app.logger.warning(f"Playlist data for ID {playlist_id} could not be retrieved.")
|
||||
|
||||
return spotify_data
|
||||
|
||||
@cache.memoize(timeout=3600)
|
||||
def get_cached_spotify_playlist(playlist_id):
|
||||
@cache.memoize(timeout=3600)
|
||||
def get_cached_playlist(playlist_id):
|
||||
"""
|
||||
Fetches a Spotify playlist by its ID, utilizing caching to minimize API calls.
|
||||
|
||||
:param playlist_id: The Spotify playlist ID.
|
||||
:return: Playlist data as a dictionary, or None if an error occurs.
|
||||
"""
|
||||
playlist_data = sp.playlist(playlist_id) # Fetch data from Spotify API
|
||||
return playlist_data
|
||||
# When the playlist_id starts with 37i9dQZF1, we need to use the new function
|
||||
# as the standard Spotify API endpoints are deprecated for these playlists.
|
||||
# Reference: https://github.com/kamilkosek/jellyplist/issues/25
|
||||
|
||||
if playlist_id.startswith("37i9dQZF1"):
|
||||
app.logger.warning(f"Algorithmic or Spotify-owned editorial playlist, using custom Implementation to fetch details")
|
||||
# Use the custom implementation for these playlists
|
||||
try:
|
||||
data = fetch_spotify_playlist(playlist_id)
|
||||
return transform_playlist_response(data)
|
||||
except Exception as e:
|
||||
print(f"Error fetching playlist with custom method: {e}")
|
||||
return None
|
||||
|
||||
# Otherwise, use the standard Spotipy API
|
||||
try:
|
||||
playlist_data = sp.playlist(playlist_id) # Fetch data using Spotipy
|
||||
return playlist_data
|
||||
except Exception as e:
|
||||
print(f"Error fetching playlist with Spotipy: {e}")
|
||||
return None
|
||||
|
||||
@cache.memoize(timeout=3600*24*10)
|
||||
def get_cached_spotify_track(track_id):
|
||||
@@ -189,7 +231,7 @@ def getFeaturedPlaylists(country: str, offset: int):
|
||||
|
||||
def getCategoryPlaylists(category: str, offset: int):
|
||||
try:
|
||||
playlists_data = sp.category_playlists(category_id=category, limit=16, offset=offset)
|
||||
playlists_data = sp.category_playlists(category_id=category, country=app.config['SPOTIFY_COUNTRY_CODE'], limit=16, offset=offset)
|
||||
return prepPlaylistData(playlists_data), playlists_data['playlists']['total'], f"Category {playlists_data['message']}"
|
||||
except SpotifyException as e:
|
||||
app.logger.error(f"Spotify API error in getCategoryPlaylists: {e}")
|
||||
@@ -215,14 +257,14 @@ def get_tracks_for_playlist(data):
|
||||
tracks = []
|
||||
is_admin = session.get('is_admin', False)
|
||||
|
||||
for idx, item in enumerate(results['tracks']):
|
||||
for idx, item in enumerate(results['tracks']['items']):
|
||||
track_data = item['track']
|
||||
if track_data:
|
||||
duration_ms = track_data['duration_ms']
|
||||
minutes = duration_ms // 60000
|
||||
seconds = (duration_ms % 60000) // 1000
|
||||
|
||||
track_db = Track.query.filter_by(spotify_track_id=track_data['id']).first()
|
||||
track_db = Track.query.filter_by(provider_track_id=track_data['id']).first()
|
||||
|
||||
if track_db:
|
||||
downloaded = track_db.downloaded
|
||||
|
||||
@@ -16,25 +16,37 @@ def jellyfin_playlists():
|
||||
try:
|
||||
# Fetch playlists from Jellyfin
|
||||
playlists = jellyfin.get_playlists(session_token=functions._get_token_from_sessioncookie())
|
||||
|
||||
spotify_data = {'playlists': {'items': []}}
|
||||
|
||||
# Extract Spotify playlist IDs from the database
|
||||
spotify_playlist_ids = []
|
||||
for pl in playlists:
|
||||
# Retrieve the playlist from the database using Jellyfin ID
|
||||
from_db = Playlist.query.filter_by(jellyfin_id=pl['Id']).first()
|
||||
if from_db and from_db.spotify_playlist_id:
|
||||
spotify_playlist_ids.append(from_db.spotify_playlist_id)
|
||||
playlist_data = None
|
||||
not_found = False
|
||||
if from_db and from_db.provider_playlist_id:
|
||||
pl_id = from_db.provider_playlist_id
|
||||
try:
|
||||
playlist_data = functions.get_cached_spotify_playlist(pl_id)
|
||||
|
||||
except SpotifyException as e:
|
||||
app.logger.error(f"Error Fetching Playlist {pl_id}: {e}")
|
||||
not_found = 'http status: 404' in str(e)
|
||||
if not_found:
|
||||
playlist_data = {
|
||||
'status':'red',
|
||||
'description': 'Playlist has most likely been removed. You can keep it, but won´t receive Updates.',
|
||||
'id': from_db.provider_playlist_id,
|
||||
'name' : from_db.name
|
||||
|
||||
}
|
||||
|
||||
if playlist_data:
|
||||
spotify_data['playlists']['items'].append(playlist_data)
|
||||
|
||||
else:
|
||||
app.logger.warning(f"No database entry found for Jellyfin playlist ID: {pl['Id']}")
|
||||
|
||||
if not spotify_playlist_ids:
|
||||
flash('No Spotify playlists found to display.', 'warning')
|
||||
return render_template('jellyfin_playlists.html', playlists=functions.prepPlaylistData({'playlists': {'items': []}}))
|
||||
|
||||
# Use the cached function to fetch Spotify playlists
|
||||
spotify_data = functions.get_cached_spotify_playlists(spotify_playlist_ids)
|
||||
|
||||
# Prepare the data for the template
|
||||
prepared_data = functions.prepPlaylistData(spotify_data)
|
||||
|
||||
return render_template('jellyfin_playlists.html', playlists=prepared_data)
|
||||
@@ -63,13 +75,13 @@ def add_playlist():
|
||||
playlist_data = functions.get_cached_spotify_playlist(playlist_id)
|
||||
|
||||
# Check if playlist already exists in the database
|
||||
playlist = Playlist.query.filter_by(spotify_playlist_id=playlist_id).first()
|
||||
playlist = Playlist.query.filter_by(provider_playlist_id=playlist_id).first()
|
||||
|
||||
if not playlist:
|
||||
# Add new playlist if it doesn't exist
|
||||
# create the playlist via api key, with the first admin as 'owner'
|
||||
fromJellyfin = jellyfin.create_music_playlist(functions._get_api_token(),playlist_data['name'],[],functions._get_admin_id())['Id']
|
||||
playlist = Playlist(name=playlist_data['name'], spotify_playlist_id=playlist_id,spotify_uri=playlist_data['uri'],track_count = playlist_data['tracks']['total'], tracks_available=0, jellyfin_id = fromJellyfin)
|
||||
playlist = Playlist(name=playlist_data['name'], provider_playlist_id=playlist_id,provider_uri=playlist_data['uri'],track_count = playlist_data['tracks']['total'], tracks_available=0, jellyfin_id = fromJellyfin)
|
||||
db.session.add(playlist)
|
||||
db.session.commit()
|
||||
if app.config['START_DOWNLOAD_AFTER_PLAYLIST_ADD']:
|
||||
@@ -83,7 +95,7 @@ def add_playlist():
|
||||
spotify_tracks = {}
|
||||
offset = 0
|
||||
while True:
|
||||
playlist_items = sp.playlist_items(playlist.spotify_playlist_id, offset=offset, limit=100)
|
||||
playlist_items = sp.playlist_items(playlist.provider_playlist_id, offset=offset, limit=100)
|
||||
items = playlist_items['items']
|
||||
spotify_tracks.update({offset + idx: track['track'] for idx, track in enumerate(items) if track['track']})
|
||||
|
||||
@@ -94,11 +106,11 @@ def add_playlist():
|
||||
track_info = track_data
|
||||
if not track_info:
|
||||
continue
|
||||
track = Track.query.filter_by(spotify_track_id=track_info['id']).first()
|
||||
track = Track.query.filter_by(provider_track_id=track_info['id']).first()
|
||||
|
||||
if not track:
|
||||
# Add new track if it doesn't exist
|
||||
track = Track(name=track_info['name'], spotify_track_id=track_info['id'], spotify_uri=track_info['uri'], downloaded=False)
|
||||
track = Track(name=track_info['name'], provider_track_id=track_info['id'], provider_uri=track_info['uri'], downloaded=False)
|
||||
db.session.add(track)
|
||||
db.session.commit()
|
||||
elif track.downloaded:
|
||||
@@ -158,7 +170,7 @@ def delete_playlist(playlist_id):
|
||||
flash('Playlist removed')
|
||||
item = {
|
||||
"name" : playlist.name,
|
||||
"id" : playlist.spotify_playlist_id,
|
||||
"id" : playlist.provider_playlist_id,
|
||||
"can_add":True,
|
||||
"can_remove":False,
|
||||
"jellyfin_id" : playlist.jellyfin_id
|
||||
@@ -182,7 +194,7 @@ def wipe_playlist(playlist_id):
|
||||
if playlist:
|
||||
# Delete the playlist
|
||||
name = playlist.name
|
||||
id = playlist.spotify_playlist_id
|
||||
id = playlist.provider_playlist_id
|
||||
jf_id = playlist.jellyfin_id
|
||||
db.session.delete(playlist)
|
||||
db.session.commit()
|
||||
|
||||
@@ -22,8 +22,8 @@ user_playlists = db.Table('user_playlists',
|
||||
class Playlist(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(150), nullable=False)
|
||||
spotify_playlist_id = db.Column(db.String(120), unique=True, nullable=False)
|
||||
spotify_uri = db.Column(db.String(120), unique=True, nullable=False)
|
||||
provider_playlist_id = db.Column(db.String(120), unique=True, nullable=False)
|
||||
provider_uri = db.Column(db.String(120), unique=True, nullable=False)
|
||||
|
||||
# Relationship with Tracks
|
||||
tracks = db.relationship('Track', secondary='playlist_tracks', back_populates='playlists')
|
||||
@@ -37,7 +37,7 @@ class Playlist(db.Model):
|
||||
users = db.relationship('JellyfinUser', secondary=user_playlists, back_populates='playlists')
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Playlist {self.name}:{self.spotify_playlist_id}>'
|
||||
return f'<Playlist {self.name}:{self.provider_playlist_id}>'
|
||||
|
||||
# Association table between Playlists and Tracks
|
||||
playlist_tracks = db.Table('playlist_tracks',
|
||||
@@ -50,8 +50,8 @@ playlist_tracks = db.Table('playlist_tracks',
|
||||
class Track(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(150), nullable=False)
|
||||
spotify_track_id = db.Column(db.String(120), unique=True, nullable=False)
|
||||
spotify_uri = db.Column(db.String(120), unique=True, nullable=False)
|
||||
provider_track_id = db.Column(db.String(120), unique=True, nullable=False)
|
||||
provider_uri = db.Column(db.String(120), unique=True, nullable=False)
|
||||
downloaded = db.Column(db.Boolean())
|
||||
filesystem_path = db.Column(db.String(), nullable=True)
|
||||
jellyfin_id = db.Column(db.String(120), nullable=True) # Add Jellyfin track ID field
|
||||
@@ -60,4 +60,4 @@ class Track(db.Model):
|
||||
# Many-to-Many relationship with Playlists
|
||||
playlists = db.relationship('Playlist', secondary=playlist_tracks, back_populates='tracks')
|
||||
def __repr__(self):
|
||||
return f'<Track {self.name}:{self.spotify_track_id}>'
|
||||
return f'<Track {self.name}:{self.provider_track_id}>'
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
from flask import Flask, Response, jsonify, render_template, request, redirect, url_for, session, flash
|
||||
import json
|
||||
import re
|
||||
from flask import Flask, Response, jsonify, render_template, request, redirect, url_for, session, flash, Blueprint, g
|
||||
from app import app, db, functions, sp, jellyfin, celery, jellyfin_admin_token, jellyfin_admin_id,device_id, cache, read_dev_build_file, tasks
|
||||
from app.models import JellyfinUser,Playlist,Track
|
||||
from celery.result import AsyncResult
|
||||
|
||||
from app.providers import base
|
||||
from app.providers.base import MusicProviderClient
|
||||
from app.providers.spotify import SpotifyClient
|
||||
from app.registry.music_provider_registry import MusicProviderRegistry
|
||||
from .version import __version__
|
||||
from spotipy.exceptions import SpotifyException
|
||||
|
||||
pl_bp = Blueprint('playlist', __name__)
|
||||
@pl_bp.before_request
|
||||
def set_active_provider():
|
||||
"""
|
||||
Middleware to select the active provider based on request parameters.
|
||||
"""
|
||||
provider_id = request.args.get('provider', 'Spotify') # Default to Spotify
|
||||
try:
|
||||
g.music_provider = MusicProviderRegistry.get_provider(provider_id)
|
||||
except ValueError as e:
|
||||
return {"error": str(e)}, 400
|
||||
|
||||
@app.context_processor
|
||||
def add_context():
|
||||
unlinked_track_count = len(Track.query.filter_by(downloaded=True,jellyfin_id=None).all())
|
||||
@@ -45,7 +64,7 @@ def link_issues():
|
||||
unlinked_tracks = Track.query.filter_by(downloaded=True,jellyfin_id=None).all()
|
||||
tracks = []
|
||||
for ult in unlinked_tracks:
|
||||
sp_track = functions.get_cached_spotify_track(ult.spotify_track_id)
|
||||
sp_track = functions.get_cached_spotify_track(ult.provider_track_id)
|
||||
duration_ms = sp_track['duration_ms']
|
||||
minutes = duration_ms // 60000
|
||||
seconds = (duration_ms % 60000) // 1000
|
||||
@@ -117,7 +136,7 @@ def login():
|
||||
db.session.add(new_user)
|
||||
db.session.commit()
|
||||
|
||||
return redirect('/playlists')
|
||||
return redirect('/')
|
||||
except:
|
||||
flash('Login failed. Please check your Jellyfin credentials and try again.', 'error')
|
||||
return redirect(url_for('login'))
|
||||
@@ -130,6 +149,32 @@ def logout():
|
||||
session.pop('jellyfin_access_token', None)
|
||||
return redirect(url_for('login'))
|
||||
|
||||
@app.route('/add_single',methods=['GET'])
|
||||
@functions.jellyfin_login_required
|
||||
def add_single():
|
||||
playlist = request.args.get('playlist')
|
||||
error = None
|
||||
errdata= None
|
||||
if playlist:
|
||||
parsed = sp._get_id(type='playlist',id=playlist)
|
||||
if parsed:
|
||||
try:
|
||||
functions.get_cached_spotify_playlist(parsed)
|
||||
|
||||
return redirect(f'/playlist/view/{parsed}')
|
||||
except SpotifyException as e:
|
||||
url_match = re.search(sp._regex_spotify_url, playlist)
|
||||
if url_match is not None:
|
||||
resp = functions.fetch_spotify_playlist(playlist,None)
|
||||
parsed_data = functions.parse_spotify_playlist_html(resp)
|
||||
error = (f'Playlist can´t be fetched')
|
||||
|
||||
errdata = str(e)
|
||||
|
||||
return render_template('index.html',error_message = error, error_data = errdata)
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route('/playlists')
|
||||
@app.route('/categories')
|
||||
@@ -147,8 +192,13 @@ def loaditems():
|
||||
try:
|
||||
db_playlists = db.session.query(Playlist).offset(offset).limit(limit).all()
|
||||
max_items = db.session.query(Playlist).count()
|
||||
spotify_playlist_ids = [playlist.spotify_playlist_id for playlist in db_playlists]
|
||||
spotify_data = functions.get_cached_spotify_playlists(tuple(spotify_playlist_ids))
|
||||
|
||||
provider_playlist_ids = [playlist.provider_playlist_id for playlist in db_playlists]
|
||||
spotify_data = functions.get_cached_spotify_playlists(tuple(provider_playlist_ids))
|
||||
for x in spotify_data['playlists']['items']:
|
||||
for from_db in db_playlists:
|
||||
if x['id'] == from_db.provider_playlist_id:
|
||||
x['name'] = from_db.name
|
||||
data = functions.prepPlaylistData(spotify_data)
|
||||
items_title = "Monitored Playlists"
|
||||
items_subtitle = "These playlists are already monitored by the Server. If you add one to your Jellyfin account, they will be available immediately."
|
||||
@@ -209,11 +259,11 @@ def searchResults():
|
||||
context = {}
|
||||
if query:
|
||||
# Add your logic here to perform the search on Spotify (or Jellyfin)
|
||||
search_result = sp.search(q = query, type= 'track,album,artist,playlist')
|
||||
search_result = sp.search(q = query, type= 'playlist',limit= 50, market=app.config['SPOTIFY_COUNTRY_CODE'])
|
||||
context = {
|
||||
'artists' : functions.prepArtistData(search_result ),
|
||||
#'artists' : functions.prepArtistData(search_result ),
|
||||
'playlists' : functions.prepPlaylistData(search_result ),
|
||||
'albums' : functions.prepAlbumData(search_result ),
|
||||
#'albums' : functions.prepAlbumData(search_result ),
|
||||
'query' : query
|
||||
}
|
||||
return render_template('search.html', **context)
|
||||
@@ -221,14 +271,14 @@ def searchResults():
|
||||
return render_template('search.html', query=None, results={})
|
||||
|
||||
|
||||
@app.route('/playlist/view/<playlist_id>')
|
||||
@pl_bp.route('/playlist/view/<playlist_id>')
|
||||
@functions.jellyfin_login_required
|
||||
def get_playlist_tracks(playlist_id):
|
||||
# Hol dir alle Tracks für die Playlist
|
||||
data = functions.get_full_playlist_data(playlist_id) # Diese neue Funktion holt alle Tracks der Playlist
|
||||
tracks = functions.get_tracks_for_playlist(data) # Deine Funktion, um Tracks zu holen
|
||||
provider: MusicProviderClient = g.music_provider # Explicit type hint for g.music_provider
|
||||
playlist: base.Playlist = provider.get_playlist(playlist_id)
|
||||
tracks = functions.get_tracks_for_playlist(playlist.tracks) # Deine Funktion, um Tracks zu holen
|
||||
# Berechne die gesamte Dauer der Playlist
|
||||
total_duration_ms = sum([track['track']['duration_ms'] for track in data['tracks'] if track['track']])
|
||||
total_duration_ms = sum([track['track']['duration_ms'] for track in data['tracks']['items'] if track['track']])
|
||||
|
||||
# Konvertiere die Gesamtdauer in ein lesbares Format
|
||||
hours, remainder = divmod(total_duration_ms // 1000, 3600)
|
||||
@@ -263,7 +313,7 @@ def associate_track():
|
||||
flash('Missing Jellyfin or Spotify ID')
|
||||
|
||||
# Retrieve the track by Spotify ID
|
||||
track = Track.query.filter_by(spotify_track_id=spotify_id).first()
|
||||
track = Track.query.filter_by(provider_track_id=spotify_id).first()
|
||||
|
||||
if not track:
|
||||
flash('Track not found')
|
||||
@@ -296,4 +346,10 @@ def unlock_key():
|
||||
|
||||
@app.route('/test')
|
||||
def test():
|
||||
playlist_id = "37i9dQZF1DX12qgyzUprB6"
|
||||
client = SpotifyClient(cookie_file='/jellyplist/open.spotify.com_cookies.txt')
|
||||
client.authenticate()
|
||||
pl = client.get_playlist(playlist_id=playlist_id)
|
||||
browse = client.browse_all()
|
||||
page = client.browse_page(browse[0].items[12])
|
||||
return ''
|
||||
32
app/tasks.py
32
app/tasks.py
@@ -49,7 +49,7 @@ def update_all_playlists_track_status(self):
|
||||
for playlist in playlists:
|
||||
total_tracks = 0
|
||||
available_tracks = 0
|
||||
app.logger.debug(f"Current Playlist: {playlist.name} [{playlist.id}:{playlist.spotify_playlist_id}]" )
|
||||
app.logger.debug(f"Current Playlist: {playlist.name} [{playlist.id}:{playlist.provider_playlist_id}]" )
|
||||
for track in playlist.tracks:
|
||||
total_tracks += 1
|
||||
if track.filesystem_path and os.path.exists(track.filesystem_path):
|
||||
@@ -106,21 +106,21 @@ def download_missing_tracks(self):
|
||||
processed_tracks = 0
|
||||
failed_downloads = 0
|
||||
for track in undownloaded_tracks:
|
||||
app.logger.info(f"Processing track: {track.name} [{track.spotify_track_id}]")
|
||||
app.logger.info(f"Processing track: {track.name} [{track.provider_track_id}]")
|
||||
|
||||
# Check if the track already exists in the output directory
|
||||
file_path = f"{output_dir.replace('{track-id}', track.spotify_track_id)}.mp3"
|
||||
file_path = f"{output_dir.replace('{track-id}', track.provider_track_id)}.mp3"
|
||||
# region search before download
|
||||
if search_before_download:
|
||||
app.logger.info(f"Searching for track in Jellyfin: {track.name}")
|
||||
spotify_track = functions.get_cached_spotify_track(track.spotify_track_id)
|
||||
spotify_track = functions.get_cached_spotify_track(track.provider_track_id)
|
||||
# at first try to find the track without fingerprinting it
|
||||
best_match = find_best_match_from_jellyfin(track)
|
||||
if best_match:
|
||||
track.downloaded = True
|
||||
if track.jellyfin_id != best_match['Id']:
|
||||
track.jellyfin_id = best_match['Id']
|
||||
app.logger.info(f"Updated Jellyfin ID for track: {track.name} ({track.spotify_track_id})")
|
||||
app.logger.info(f"Updated Jellyfin ID for track: {track.name} ({track.provider_track_id})")
|
||||
if track.filesystem_path != best_match['Path']:
|
||||
track.filesystem_path = best_match['Path']
|
||||
|
||||
@@ -171,8 +171,8 @@ def download_missing_tracks(self):
|
||||
|
||||
# Attempt to download the track using spotdl
|
||||
try:
|
||||
app.logger.info(f"Trying to download track: {track.name} ({track.spotify_track_id}), spotdl timeout = 90")
|
||||
s_url = f"https://open.spotify.com/track/{track.spotify_track_id}"
|
||||
app.logger.info(f"Trying to download track: {track.name} ({track.provider_track_id}), spotdl timeout = 90")
|
||||
s_url = f"https://open.spotify.com/track/{track.provider_track_id}"
|
||||
|
||||
command = [
|
||||
"spotdl", "download", s_url,
|
||||
@@ -251,7 +251,7 @@ def check_for_playlist_updates(self):
|
||||
|
||||
for playlist in playlists:
|
||||
playlist.last_updated = datetime.now( timezone.utc)
|
||||
sp_playlist = sp.playlist(playlist.spotify_playlist_id)
|
||||
sp_playlist = sp.playlist(playlist.provider_playlist_id)
|
||||
full_update = True
|
||||
app.logger.info(f'Checking updates for playlist: {playlist.name}, s_snapshot = {sp_playlist['snapshot_id']}')
|
||||
db.session.commit()
|
||||
@@ -266,7 +266,7 @@ def check_for_playlist_updates(self):
|
||||
offset = 0
|
||||
playlist.snapshot_id = sp_playlist['snapshot_id']
|
||||
while True:
|
||||
playlist_data = sp.playlist_items(playlist.spotify_playlist_id, offset=offset, limit=100)
|
||||
playlist_data = sp.playlist_items(playlist.provider_playlist_id, offset=offset, limit=100)
|
||||
items = playlist_data['items']
|
||||
spotify_tracks.update({offset + idx: track['track'] for idx, track in enumerate(items) if track['track']})
|
||||
|
||||
@@ -274,7 +274,7 @@ def check_for_playlist_updates(self):
|
||||
break
|
||||
offset += 100 # Move to the next batch
|
||||
|
||||
existing_tracks = {track.spotify_track_id: track for track in playlist.tracks}
|
||||
existing_tracks = {track.provider_track_id: track for track in playlist.tracks}
|
||||
|
||||
# Determine tracks to add and remove
|
||||
tracks_to_add = []
|
||||
@@ -282,9 +282,9 @@ def check_for_playlist_updates(self):
|
||||
if track_info:
|
||||
track_id = track_info['id']
|
||||
if track_id not in existing_tracks:
|
||||
track = Track.query.filter_by(spotify_track_id=track_id).first()
|
||||
track = Track.query.filter_by(provider_track_id=track_id).first()
|
||||
if not track:
|
||||
track = Track(name=track_info['name'], spotify_track_id=track_id, spotify_uri=track_info['uri'], downloaded=False)
|
||||
track = Track(name=track_info['name'], provider_track_id=track_id, provider_uri=track_info['uri'], downloaded=False)
|
||||
db.session.add(track)
|
||||
db.session.commit()
|
||||
app.logger.info(f'Added new track: {track.name}')
|
||||
@@ -382,10 +382,10 @@ def update_jellyfin_id_for_downloaded_tracks(self):
|
||||
track.downloaded = True
|
||||
if track.jellyfin_id != best_match['Id']:
|
||||
track.jellyfin_id = best_match['Id']
|
||||
app.logger.info(f"Updated Jellyfin ID for track: {track.name} ({track.spotify_track_id})")
|
||||
app.logger.info(f"Updated Jellyfin ID for track: {track.name} ({track.provider_track_id})")
|
||||
if track.filesystem_path != best_match['Path']:
|
||||
track.filesystem_path = best_match['Path']
|
||||
app.logger.info(f"Updated filesystem_path for track: {track.name} ({track.spotify_track_id})")
|
||||
app.logger.info(f"Updated filesystem_path for track: {track.name} ({track.provider_track_id})")
|
||||
|
||||
|
||||
|
||||
@@ -422,10 +422,10 @@ def find_best_match_from_jellyfin(track: Track):
|
||||
|
||||
for result in search_results:
|
||||
|
||||
app.logger.debug(f"Processing search result: {result['Id']}")
|
||||
app.logger.debug(f"Processing search result: {result['Id']}, Path = {result['Path']}")
|
||||
quality_score = compute_quality_score(result, app.config['FIND_BEST_MATCH_USE_FFPROBE'])
|
||||
try:
|
||||
spotify_track = functions.get_cached_spotify_track(track.spotify_track_id)
|
||||
spotify_track = functions.get_cached_spotify_track(track.provider_track_id)
|
||||
spotify_track_name = spotify_track['name'].lower()
|
||||
spotify_artists = [artist['name'].lower() for artist in spotify_track['artists']]
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user