working on plex_playlists based on gemini
This commit is contained in:
parent
ce48d867a9
commit
88d1f94748
3 changed files with 142 additions and 96 deletions
|
|
@ -1,7 +1,9 @@
|
||||||
|
# discovery_sync.py
|
||||||
|
|
||||||
from config import *
|
from config import *
|
||||||
from lastfm_helpers import lf_request, recent_artists
|
from lastfm_helpers import recent_artists, get_similar_artists_pylast # Korrekt
|
||||||
from lidarr_helpers import lidarr_api_add_artist
|
from lidarr_helpers import lidarr_api_add_artist # Antar att lidarr_helpers bara har denna funktion att exportera
|
||||||
from musicbrainz_helpers import load_cache, save_cache
|
from musicbrainz_helpers import load_cache, save_cache # Antar att musicbrainz_helpers bara har dessa funktioner att exportera
|
||||||
import time, logging
|
import time, logging
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
@ -14,9 +16,9 @@ def sync():
|
||||||
similar_cache = cache.setdefault("similar_cache", {})
|
similar_cache = cache.setdefault("similar_cache", {})
|
||||||
|
|
||||||
recent = recent_artists()
|
recent = recent_artists()
|
||||||
log.info(f"🎧 Analyserar {len(recent)} senaste artister från Last.fm")
|
log.info(f"🎧 Analyzing {len(recent)} recent artists from Last.fm")
|
||||||
|
|
||||||
new = 0
|
new_artists_added_count = 0
|
||||||
for name, mbid in recent:
|
for name, mbid in recent:
|
||||||
if not mbid or mbid in added_artists:
|
if not mbid or mbid in added_artists:
|
||||||
continue
|
continue
|
||||||
|
|
@ -24,25 +26,25 @@ def sync():
|
||||||
if mbid in similar_cache:
|
if mbid in similar_cache:
|
||||||
sims = similar_cache[mbid]["data"]
|
sims = similar_cache[mbid]["data"]
|
||||||
else:
|
else:
|
||||||
js = lf_request("artist.getSimilar", mbid=mbid, limit=MAX_SIMILAR_PER_ART)
|
sims = get_similar_artists_pylast(mbid, MAX_SIMILAR_PER_ART)
|
||||||
sims = js.get("similarartists", {}).get("artist", []) if js else []
|
|
||||||
similar_cache[mbid] = {"ts": time.time(), "data": sims}
|
similar_cache[mbid] = {"ts": time.time(), "data": sims}
|
||||||
save_cache(cache)
|
save_cache(cache)
|
||||||
|
|
||||||
for sim in sims:
|
for sim_artist_obj, match in sims:
|
||||||
sid = sim.get("mbid")
|
sid = sim_artist_obj.mbid
|
||||||
match = float(sim.get("match", 0))
|
match_float = float(match)
|
||||||
if not sid or sid in added_artists or match < SIMILAR_MATCH_MIN:
|
|
||||||
|
if not sid or sid in added_artists or match_float < SIMILAR_MATCH_MIN:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
log.info(f"✨ Ny artist: {sim.get('name')} (match {match:.2f})")
|
log.info(f"✨ New artist: {sim_artist_obj.name} (match {match_float:.2f})")
|
||||||
if lidarr_api_add_artist(sid):
|
if lidarr_api_add_artist(sid):
|
||||||
added_artists.add(sid)
|
added_artists.add(sid)
|
||||||
new += 1
|
new_artists_added_count += 1
|
||||||
cache["added_artists"] = list(added_artists)
|
cache["added_artists"] = list(added_artists)
|
||||||
save_cache(cache)
|
save_cache(cache)
|
||||||
|
|
||||||
log.info(f"✅ Klar! {new} nya artister tillagda på {((time.time()-start)/60):.1f} min")
|
log.info(f"✅ Done! {new_artists_added_count} new artists added in {((time.time()-start)/60):.1f} min")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sync()
|
sync()
|
||||||
|
|
@ -1,47 +1,89 @@
|
||||||
from config import *
|
# lastfm_helpers.py
|
||||||
import requests, time, urllib.parse
|
|
||||||
from collections import defaultdict
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
def lf_request(method, **params):
|
import pylast
|
||||||
# Fixa 'from_' → 'from' och 'to_' → 'to' (Last.fm accepterar inte Python-säkra namn)
|
from config import (
|
||||||
for alt, real in (("from_", "from"), ("to_", "to")):
|
LASTFM_API_KEY, LASTFM_API_SECRET, LASTFM_USERNAME,
|
||||||
if alt in params:
|
MIN_PLAYS, RECENT_MONTHS
|
||||||
params[real] = params.pop(alt)
|
)
|
||||||
url = "https://ws.audioscrobbler.com/2.0/"
|
import logging
|
||||||
params.update({
|
from datetime import datetime, timedelta
|
||||||
"method": method,
|
from collections import defaultdict
|
||||||
"api_key": LASTFM_API_KEY,
|
|
||||||
"format": "json"
|
log = logging.getLogger("LastFmHelpers")
|
||||||
})
|
|
||||||
|
LASTFM_NETWORK = None
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params)
|
LASTFM_NETWORK = pylast.LastFMNetwork(
|
||||||
r.raise_for_status()
|
api_key=LASTFM_API_KEY,
|
||||||
return r.json()
|
api_secret=LASTFM_API_SECRET,
|
||||||
|
username=LASTFM_USERNAME
|
||||||
|
)
|
||||||
|
log.info("✅ Connected to Last.fm API.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[LFM ERR] {e}")
|
log.error(f"❌ Failed to initialize Last.fm network. Check API keys and username: {e}")
|
||||||
return None
|
|
||||||
|
|
||||||
def recent_artists():
|
def recent_artists():
|
||||||
since = int((datetime.utcnow() - timedelta(days=30 * RECENT_MONTHS)).timestamp())
|
"""Fetches recently played artists from Last.fm, filtered by play count and recency."""
|
||||||
|
if not LASTFM_NETWORK:
|
||||||
|
log.error("Last.fm network not initialized. Cannot fetch recent artists.")
|
||||||
|
return []
|
||||||
|
|
||||||
|
user = LASTFM_NETWORK.get_user(LASTFM_USERNAME)
|
||||||
|
since_timestamp = int((datetime.utcnow() - timedelta(days=30 * RECENT_MONTHS)).timestamp())
|
||||||
counts = defaultdict(int)
|
counts = defaultdict(int)
|
||||||
page = 1
|
|
||||||
|
|
||||||
while True:
|
log.info(f"Fetching recent tracks for {LASTFM_USERNAME} since {datetime.fromtimestamp(since_timestamp).strftime('%Y-%m-%d %H:%M:%S')}")
|
||||||
js = lf_request(
|
try:
|
||||||
"user.getRecentTracks", user=LASTFM_USERNAME,
|
for track in user.get_recent_tracks(time_from=since_timestamp, limit=None):
|
||||||
limit=200, page=page, from_=since
|
artist = track.artist
|
||||||
)
|
counts[(artist.name, artist.mbid)] += 1
|
||||||
if not js:
|
except pylast.NetworkError as ne:
|
||||||
break
|
log.error(f"Network error fetching recent tracks: {ne}")
|
||||||
|
return []
|
||||||
|
except pylast.WSError as wse:
|
||||||
|
log.error(f"Last.fm API error fetching recent tracks: {wse}")
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Unexpected error fetching recent tracks: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
for t in js.get("recenttracks", {}).get("track", []):
|
return [(name, mbid) for (name, mbid), count in counts.items() if count >= MIN_PLAYS]
|
||||||
a = t["artist"]
|
|
||||||
counts[(a["#text"], a.get("mbid", ""))] += 1
|
|
||||||
|
|
||||||
attr = js.get("recenttracks", {}).get("@attr", {})
|
def get_similar_artists_pylast(artist_mbid, limit):
|
||||||
if page >= int(attr.get("totalPages", 1)):
|
"""Fetches artists similar to a given artist from Last.fm."""
|
||||||
break
|
if not LASTFM_NETWORK:
|
||||||
page += 1
|
log.error("Last.fm network not initialized. Cannot fetch similar artists.")
|
||||||
|
return []
|
||||||
|
|
||||||
return [(n, m) for (n, m), c in counts.items() if c >= MIN_PLAYS]
|
try:
|
||||||
|
artist = LASTFM_NETWORK.get_artist_by_mbid(artist_mbid)
|
||||||
|
similar_artists_tuples = artist.get_similar(limit=limit)
|
||||||
|
return similar_artists_tuples
|
||||||
|
except pylast.WSError as wse:
|
||||||
|
log.warning(f"Last.fm API error fetching similar artists for MBID {artist_mbid}: {wse}. Check MBID.")
|
||||||
|
return []
|
||||||
|
except pylast.NetworkError as ne:
|
||||||
|
log.warning(f"Network error fetching similar artists for MBID {artist_mbid}: {ne}")
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
log.warning(f"Could not fetch similar artists for MBID {artist_mbid}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_artist_top_tracks(artist_name, limit=5):
|
||||||
|
"""Fetches top tracks for a specific artist from Last.fm."""
|
||||||
|
if not LASTFM_NETWORK:
|
||||||
|
log.error("Last.fm network not initialized. Cannot fetch top tracks.")
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
artist = LASTFM_NETWORK.get_artist(artist_name)
|
||||||
|
top_tracks = artist.get_top_tracks(limit=limit)
|
||||||
|
return [{"artist": track.item.artist.name, "title": track.item.title} for track in top_tracks]
|
||||||
|
except pylast.WSError as wse:
|
||||||
|
log.warning(f"Last.fm API error fetching top tracks for '{artist_name}': {wse}. Check artist name.")
|
||||||
|
return []
|
||||||
|
except pylast.NetworkError as ne:
|
||||||
|
log.warning(f"Network error fetching top tracks for '{artist_name}': {ne}")
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
log.warning(f"Unexpected error fetching top tracks for '{artist_name}': {e}")
|
||||||
|
return []
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
# plex_playlist_sync.py (Den fullständiga koden från mitt tidigare svar)
|
# plex_playlist_sync.py
|
||||||
|
|
||||||
# Importera konfiguration och hjälpfunktioner från dina befintliga filer
|
|
||||||
from config import (
|
from config import (
|
||||||
LASTFM_API_KEY, LASTFM_API_SECRET, LASTFM_USERNAME,
|
LASTFM_API_KEY, LASTFM_API_SECRET, LASTFM_USERNAME,
|
||||||
PLEX_BASEURL, PLEX_TOKEN,
|
PLEX_BASEURL, PLEX_TOKEN,
|
||||||
MIN_PLAYS, RECENT_MONTHS, MAX_SIMILAR_PER_ART, SIMILAR_MATCH_MIN,
|
MIN_PLAYS, RECENT_MONTHS, MAX_SIMILAR_PER_ART, SIMILAR_MATCH_MIN,
|
||||||
CACHE_TTL_HOURS, DEBUG_PRINT
|
CACHE_TTL_HOURS, DEBUG_PRINT
|
||||||
)
|
)
|
||||||
from lastfm_helpers import lf_request, recent_artists
|
# Importera relevanta funktioner från lastfm_helpers
|
||||||
|
from lastfm_helpers import recent_artists, get_artist_top_tracks
|
||||||
from musicbrainz_helpers import load_cache, save_cache # Används för cache
|
from musicbrainz_helpers import load_cache, save_cache # Används för cache
|
||||||
|
|
||||||
import pylast
|
import pylast # Behövs för pylast.LastFMNetwork initiering i denna fil
|
||||||
from plexapi.server import PlexServer
|
from plexapi.server import PlexServer
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
|
|
@ -19,6 +19,11 @@ import logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
log = logging.getLogger("PlexPlaylistSync")
|
log = logging.getLogger("PlexPlaylistSync")
|
||||||
|
|
||||||
|
# Initialisera Last.fm-nätverket i denna fil också, om det behövs här.
|
||||||
|
# OBS: lastfm_helpers initialiserar det globalt, så du kan potentiellt ta bort detta block
|
||||||
|
# om du är säker på att lastfm_helpers alltid laddas först och initierar nätverket korrekt.
|
||||||
|
# Men för att vara säker, kan du behålla det eller flytta initieringen till en central punkt.
|
||||||
|
LASTFM_NETWORK = None
|
||||||
try:
|
try:
|
||||||
LASTFM_NETWORK = pylast.LastFMNetwork(
|
LASTFM_NETWORK = pylast.LastFMNetwork(
|
||||||
api_key=LASTFM_API_KEY,
|
api_key=LASTFM_API_KEY,
|
||||||
|
|
@ -26,74 +31,71 @@ try:
|
||||||
username=LASTFM_USERNAME
|
username=LASTFM_USERNAME
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Kunde inte initiera Last.fm-nätverket. Kontrollera nycklar/användarnamn: {e}")
|
log.error(f"Failed to initialize Last.fm network. Check keys/username: {e}")
|
||||||
LASTFM_NETWORK = None
|
LASTFM_NETWORK = None
|
||||||
|
|
||||||
def get_artist_top_tracks(artist_name, limit=5):
|
# get_artist_top_tracks funktionen behöver INTE definieras här
|
||||||
if not LASTFM_NETWORK:
|
# om den importeras från lastfm_helpers.py
|
||||||
return []
|
# Jag tar bort den härifrån, så den används korrekt importerad.
|
||||||
try:
|
|
||||||
artist = LASTFM_NETWORK.get_artist(artist_name)
|
|
||||||
top_tracks = artist.get_top_tracks(limit=limit)
|
|
||||||
return [{"artist": track.item.artist.name, "title": track.item.title} for track in top_tracks]
|
|
||||||
except Exception as e:
|
|
||||||
log.warning(f"Kunde inte hämta top-spår för '{artist_name}' från Last.fm: {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
def create_lastfm_recommended_playlist():
|
def create_lastfm_recommended_playlist():
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
log.info("🚀 Börjar processen för att skapa Last.fm-baserade spellistor i Plex.")
|
log.info("🚀 Starting process to create Last.fm-based playlists in Plex.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
plex = PlexServer(PLEX_BASEURL, PLEX_TOKEN)
|
plex = PlexServer(PLEX_BASEURL, PLEX_TOKEN)
|
||||||
log.info(f"✅ Ansluten till Plex Media Server: {plex.baseurl}")
|
log.info(f"✅ Connected to Plex Media Server: {plex.baseurl}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"❌ Kunde inte ansluta till Plex Server: {e}")
|
log.error(f"❌ Could not connect to Plex Server: {e}")
|
||||||
log.error("Kontrollera PLEX_BASEURL och PLEX_TOKEN i config_local.py.")
|
log.error("Check PLEX_BASEURL and PLEX_TOKEN in config_local.py.")
|
||||||
return
|
return
|
||||||
|
|
||||||
music_library = None
|
music_library = None
|
||||||
try:
|
try:
|
||||||
music_library = plex.library.section('Music')
|
music_library = plex.library.section('Music')
|
||||||
log.info(f"Använder Plex-biblioteket: '{music_library.title}'")
|
log.info(f"Using Plex library: '{music_library.title}'")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"❌ Kunde inte hitta musikbiblioteket 'Music' i Plex: {e}")
|
log.error(f"❌ Could not find 'Music' library in Plex: {e}")
|
||||||
log.error("Kontrollera namnet på ditt musikbibliotek i Plex.")
|
log.error("Check your music library name in Plex.")
|
||||||
return
|
return
|
||||||
|
|
||||||
artists_for_playlist = []
|
artists_for_playlist = []
|
||||||
cache = load_cache()
|
cache = load_cache()
|
||||||
added_artists_mbids = cache.get("added_artists", [])
|
added_artists_mbids = cache.get("added_artists", [])
|
||||||
|
|
||||||
log.info("Samlar in artister för spellistan...")
|
log.info("Gathering artists for the playlist...")
|
||||||
|
# Get names for artists added by Lidarr sync
|
||||||
for mbid in added_artists_mbids:
|
for mbid in added_artists_mbids:
|
||||||
try:
|
try:
|
||||||
artist_info = LASTFM_NETWORK.get_artist_by_mbid(mbid)
|
# Re-use the LASTFM_NETWORK initialized above or in lastfm_helpers
|
||||||
|
artist_info = LASTFM_NETWORK.get_artist_by_mbid(mbid) # Needs LASTFM_NETWORK from this file or lastfm_helpers
|
||||||
artists_for_playlist.append(artist_info.name)
|
artists_for_playlist.append(artist_info.name)
|
||||||
except Exception:
|
except Exception:
|
||||||
log.debug(f"Kunde inte hitta namn för MBID: {mbid} via pylast.")
|
log.debug(f"Could not find name for MBID: {mbid} via pylast.")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
recent_played_artists = recent_artists()
|
# Add some of the most recently played artists as well
|
||||||
|
recent_played_artists = recent_artists() # Uses recent_artists from lastfm_helpers
|
||||||
for name, mbid in recent_played_artists[:10]:
|
for name, mbid in recent_played_artists[:10]:
|
||||||
if name not in artists_for_playlist:
|
if name not in artists_for_playlist:
|
||||||
artists_for_playlist.append(name)
|
artists_for_playlist.append(name)
|
||||||
|
|
||||||
if not artists_for_playlist:
|
if not artists_for_playlist:
|
||||||
log.info("Inga artister hittades för att skapa en spellista. Se till att Last.fm-synkroniseringen har kört.")
|
log.info("No artists found to create a playlist. Ensure Last.fm sync has run.")
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info(f"Hittade {len(artists_for_playlist)} unika artister för att bygga spellistan.")
|
log.info(f"Found {len(artists_for_playlist)} unique artists to build the playlist.")
|
||||||
|
|
||||||
all_recommended_tracks_info = []
|
all_recommended_tracks_info = []
|
||||||
for artist_name in artists_for_playlist:
|
for artist_name in artists_for_playlist:
|
||||||
|
# Use the imported get_artist_top_tracks
|
||||||
top_tracks = get_artist_top_tracks(artist_name, limit=3)
|
top_tracks = get_artist_top_tracks(artist_name, limit=3)
|
||||||
all_recommended_tracks_info.extend(top_tracks)
|
all_recommended_tracks_info.extend(top_tracks)
|
||||||
|
|
||||||
unique_tracks_to_add = []
|
unique_tracks_to_add = []
|
||||||
seen_track_identifiers = set()
|
seen_track_identifiers = set()
|
||||||
|
|
||||||
log.info(f"Söker efter {len(all_recommended_tracks_info)} potentiella spår i Plex-biblioteket...")
|
log.info(f"Searching for {len(all_recommended_tracks_info)} potential tracks in Plex library...")
|
||||||
for track_info in all_recommended_tracks_info:
|
for track_info in all_recommended_tracks_info:
|
||||||
artist_name = track_info["artist"]
|
artist_name = track_info["artist"]
|
||||||
track_title = track_info["title"]
|
track_title = track_info["title"]
|
||||||
|
|
@ -112,28 +114,28 @@ def create_lastfm_recommended_playlist():
|
||||||
break
|
break
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning(f"Fel vid Plex-sökning efter '{track_title}' av '{artist_name}': {e}")
|
log.warning(f"Error searching Plex for '{track_title}' by '{artist_name}': {e}")
|
||||||
|
|
||||||
if found_plex_track:
|
if found_plex_track:
|
||||||
unique_tracks_to_add.append(found_plex_track)
|
unique_tracks_to_add.append(found_plex_track)
|
||||||
seen_track_identifiers.add(identifier)
|
seen_track_identifiers.add(identifier)
|
||||||
log.info(f" ✅ Hittade: {found_plex_track.artist().title} - {found_plex_track.title}")
|
log.info(f" ✅ Found: {found_plex_track.artist().title} - {found_plex_track.title}")
|
||||||
else:
|
else:
|
||||||
log.info(f" ❌ Hittade inte: '{track_title}' av '{artist_name}' i Plex.")
|
log.info(f" ❌ Not found: '{track_title}' by '{artist_name}' in Plex.")
|
||||||
|
|
||||||
if not unique_tracks_to_add:
|
if not unique_tracks_to_add:
|
||||||
log.info("Inga nya matchande låtar hittades i Plex för att skapa en spellista.")
|
log.info("No new matching songs found in Plex to create a playlist.")
|
||||||
return
|
return
|
||||||
|
|
||||||
current_date = datetime.datetime.now().strftime("%Y-%m")
|
current_date = datetime.datetime.now().strftime("%Y-%m")
|
||||||
playlist_name = f"Last.fm Rekommendationer {current_date}"
|
playlist_name = f"Last.fm Recommendations {current_date}"
|
||||||
|
|
||||||
playlist = None
|
playlist = None
|
||||||
try:
|
try:
|
||||||
playlist = plex.playlist(playlist_name)
|
playlist = plex.playlist(playlist_name)
|
||||||
log.info(f"Spellistan '{playlist_name}' finns redan.")
|
log.info(f"Playlist '{playlist_name}' already exists.")
|
||||||
except Exception:
|
except Exception:
|
||||||
log.info(f"Skapar ny spellista: '{playlist_name}'")
|
log.info(f"Creating new playlist: '{playlist_name}'")
|
||||||
|
|
||||||
if playlist:
|
if playlist:
|
||||||
existing_playlist_items = playlist.items()
|
existing_playlist_items = playlist.items()
|
||||||
|
|
@ -142,19 +144,19 @@ def create_lastfm_recommended_playlist():
|
||||||
if new_items_to_add:
|
if new_items_to_add:
|
||||||
try:
|
try:
|
||||||
playlist.addItems(new_items_to_add)
|
playlist.addItems(new_items_to_add)
|
||||||
log.info(f"Lade till {len(new_items_to_add)} nya låtar i befintlig spellista '{playlist_name}'.")
|
log.info(f"Added {len(new_items_to_add)} new songs to existing playlist '{playlist_name}'.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Kunde inte lägga till låtar i befintlig spellista: {e}")
|
log.error(f"Could not add songs to existing playlist: {e}")
|
||||||
else:
|
else:
|
||||||
log.info(f"Inga nya låtar att lägga till i befintlig spellista '{playlist_name}'.")
|
log.info(f"No new songs to add to existing playlist '{playlist_name}'.")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
new_playlist = plex.createPlaylist(playlist_name, items=unique_tracks_to_add)
|
new_playlist = plex.createPlaylist(playlist_name, items=unique_tracks_to_add)
|
||||||
log.info(f"✅ Skapade ny spellista '{new_playlist.title}' med {len(unique_tracks_to_add)} låtar.")
|
log.info(f"✅ Created new playlist '{new_playlist.title}' with {len(unique_tracks_to_add)} songs.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"❌ Kunde inte skapa spellista i Plex: {e}")
|
log.error(f"❌ Could not create playlist in Plex: {e}")
|
||||||
|
|
||||||
log.info(f"🎉 Klar! Processen tog {((time.time()-start_time)/60):.1f} minuter.")
|
log.info(f"🎉 Done! Process took {((time.time()-start_time)/60):.1f} minutes.")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
create_lastfm_recommended_playlist()
|
create_lastfm_recommended_playlist()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue