from tqdm import tqdm import src.lyrics.lyrics as Lyrics from Env import client_id, client_secret, local_library_path from Env import work_dir from src.Library import * from src.LibrarySerializer import LibrarySaver, LibraryLoader from src.backends.spotify.SpotifyWebAPI import fetch_all from src.backends.spotify.ParseSpotify import Parser from src.backends.local.LocalLibraryIndexer import update_local_library from src.backends.local.ParseLocal import LocalParser from src.backends.itunes.ParseItunesXml import ParseItunesXml from src.mappers.RemoteLibraryResolver import resolve_remote_tracks from src.StatGenerator import log_stats class Flow: spotify_library : Library = None local_library : Library = None itunes_library : Library = None @staticmethod def fetch_spotify(self): fetch_all(client_id, client_secret, work_dir) @staticmethod def fetch_local(): update_local_library(local_library_path, work_dir) @staticmethod def parse_spotify_library(): parser = Parser() library_parsed = parser.parse( work_dir / "spotify" / "playlistTracks.json", work_dir / "spotify" / "tracks.json", work_dir / "spotify" / "top_tracks.json", work_dir / "spotify" / "top_artists.json", ) LibrarySaver(library_parsed).save(work_dir / "spotify_library.json") @staticmethod def parse_itunes_library(): parser = ParseItunesXml() library_parsed = parser.parse( work_dir / "itunes" / "Library.xml", work_dir / "itunes" / "Library.json" ) LibrarySaver(library_parsed).save(work_dir / "itunes_library.json") @staticmethod def parse_local_library(): parser = LocalParser() library_parsed = parser.parse(work_dir / "local" / "local_library.json") LibrarySaver(library_parsed).save(work_dir / "local_library.json") def fetch_and_save_lyrics(self): """ Fetches and writes lyrics for tracks that don't have lyrics yet. Displays stats and uses a progress bar. """ # ---------- Step 1: Collect tracks without lyrics ---------- tracks_missing_lyrics = [ track for track in self.local_library.tracks if len(track.artists) > 0 and not track.has_lyrics ] total_tracks = len(self.local_library.tracks) missing_count = len(tracks_missing_lyrics) print(f"[INFO] Total tracks in library: {total_tracks}") print(f"[INFO] Tracks missing lyrics: {missing_count}") if missing_count == 0: print("[INFO] No tracks need lyrics. Exiting.") return # ---------- Step 2: Fetch and write lyrics with progress bar ---------- for track in tqdm(tracks_missing_lyrics, desc="Fetching lyrics", unit="track"): artist_name = track.artists[0].title album_title = track.album.title if track.album else "Unknown Album" print(f"\n[INFO] Processing: '{track.title}' by '{artist_name}' on '{album_title}'") lyrics_text = Lyrics.fetch_lyrics(artist_name, album_title, track.title, track.duration_ms) if lyrics_text: print("[SUCCESS] Lyrics found, writing to file...") file_path = local_library_path / track.local_path try: Lyrics.write_lyrics(file_path, lyrics_text) print(f"[SUCCESS] Lyrics written for '{track.title}'") except Exception as e: print(f"[ERROR] Failed to write lyrics for '{track.title}': {e}") else: print(f"[WARNING] Lyrics not found for '{track.title}'") def load_libraries(self): self.spotify_library = LibraryLoader().load(work_dir / "spotify_library.json") self.itunes_library = LibraryLoader().load(work_dir / "itunes_library.json") self.local_library = LibraryLoader().load(work_dir / "local_library.json") def save_libraries(self): LibrarySaver(self.spotify_library).save(work_dir / "spotify_library.json") LibrarySaver(self.local_library).save(work_dir / "local_library.json") def map_local_to_spotify(self): resolve_remote_tracks(client_id, client_secret, self.local_library, self.spotify_library, work_dir) def log_stats(self): log_stats(work_dir / "remote_to_local_map.json", work_dir / "stats", self.local_library, self.spotify_library) def run(self, arg): self.fetch_local() # self.do_fetch_spotify() self.parse_local_library() self.parse_spotify_library() self.load_libraries() # self.map_local_to_spotify() return True