from __future__ import annotations from datetime import datetime from pathlib import Path from typing import List, Optional, Any class Entity: def __init__(self): self.id: str = None self.mbid : str = None self.title: str = None self.fav: bool = False self.rating: int = 0 self.play_count : int = 0 self.date_added : datetime = None self.date_released : datetime = None self.date_last_play : datetime = None self.auto_score: float = 0 self.local_id: str = None self.resolved_percentage : float = 0 class Artist: def __init__(self): self.id: str = None self.title: str = None self.tracks: List[Track] = [] self.albums: List[Album] = [] self.local_id: str = None self.auto_score: float = 0 self.fav: bool = False self.rating: int = 0 self.resolved_percentage : float = 0 class Track: def __init__(self): self.id: str = None self.title: str = None self.artists: List[Artist] = [] self.album: Album = None self.duration_ms: int = None self.added_at: datetime = None self.local_path: Path = None self.has_lyrics: bool = False self.local_id: str = None self.auto_score: float = 0 self.fav: bool = False self.rating: int = 0 class Album: def __init__(self): self.id: str = None self.title: str = None self.release_date: datetime = None self.tracks: List[Track] = [] self.artists: List[Artist] = [] self.local_id: str = None self.auto_score: float = 0 self.fav: bool = False self.rating: int = 0 self.resolved_percentage : float = 0 class Playlist: def __init__(self): self.title: str = None self.tracks: List[Track] = [] self.created_at: datetime = None self.description: str = None self.auto_score: float = 0 self.fav: bool = False self.rating: int = 0 self.resolved_percentage : float = 0 class Library: def __init__(self): self.artists: List[Artist] = [] self.playlists: List[Playlist] = [] self.tracks: List[Track] = [] self.albums: List[Album] = [] self.liked_tracks: List[Track] = [] self.top_tracks: List[Track] = [] self.top_artists: List[Artist] = [] self.artist_map: dict[str, Artist] = None self.album_map: dict[str, Album] = None self.track_map: dict[str, Track] = None self.name = "Unnamed" def update_cache(self): self.update_id_maps() self.create_reverse_links() self.score_albums() self.calc_resolved_percentage() def update_id_maps(self): self.artist_map: dict[str, Artist] = {artist.id: artist for artist in self.artists} self.album_map: dict[str, Album] = {album.id: album for album in self.albums} self.track_map: dict[str, Track] = {track.id: track for track in self.tracks} def create_reverse_links(self): for track_id, track in self.track_map.items(): for artist in track.artists: if track not in artist.tracks: artist.tracks.append(track) if track not in track.album.tracks: track.album.tracks.append(track) for album_id, album in self.album_map.items(): for artist in album.artists: if album not in artist.albums: artist.albums.append(album) def auto_score(self): self.score_tracks() self.score_artists() self.score_albums() def score_tracks(self): for idx, track in enumerate(self.top_tracks): score = len(self.top_tracks) - idx track.auto_score = score def score_artists(self): for track in self.tracks: for artist in track.artists: artist.auto_score += track.auto_score def score_albums(self): for track in self.tracks: track.album.auto_score += track.auto_score def calc_resolved_percentage(self): for artist in self.artists: artist_count_resolved = 0 artist_count = 0 for album in artist.albums: album_count_resolved = 0 for track in album.tracks: if track.local_id: album_count_resolved += 1 album.resolved_percentage = album_count_resolved / len(album.tracks) artist_count_resolved += album_count_resolved artist_count += len(album.tracks) artist.resolved_percentage = artist_count_resolved / artist_count