nice
This commit is contained in:
parent
426ad381de
commit
b6d88d435a
6 changed files with 112 additions and 128 deletions
2
Flow.py
2
Flow.py
|
|
@ -23,6 +23,7 @@ from src.StatGenerator import log_stats
|
||||||
class Flow:
|
class Flow:
|
||||||
spotify_library : Library = None
|
spotify_library : Library = None
|
||||||
local_library : Library = None
|
local_library : Library = None
|
||||||
|
itunes_library : Library = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fetch_spotify(self):
|
def fetch_spotify(self):
|
||||||
|
|
@ -107,6 +108,7 @@ class Flow:
|
||||||
|
|
||||||
def load_libraries(self):
|
def load_libraries(self):
|
||||||
self.spotify_library = LibraryLoader().load(work_dir / "spotify_library.json")
|
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")
|
self.local_library = LibraryLoader().load(work_dir / "local_library.json")
|
||||||
|
|
||||||
def save_libraries(self):
|
def save_libraries(self):
|
||||||
|
|
|
||||||
38
Gui.py
38
Gui.py
|
|
@ -6,34 +6,36 @@ import pandas as pd
|
||||||
|
|
||||||
import Flow
|
import Flow
|
||||||
|
|
||||||
from src.Library import Library, Artist, Album, Track, Playlist
|
from src.Library import *
|
||||||
|
|
||||||
|
def entity_to_row(entity: Entity):
|
||||||
|
return {
|
||||||
|
"id": entity.id,
|
||||||
|
"mbid": entity.mbid,
|
||||||
|
"Title": entity.title,
|
||||||
|
"PLay Count": entity.play_count,
|
||||||
|
"Resolved": int(entity.resolved_percentage * 100),
|
||||||
|
"AutoScore": entity.auto_score,
|
||||||
|
"Added": entity.date_added.strftime("%Y-%m-%d") if entity.date_added else None,
|
||||||
|
"Played": entity.date_last_play.strftime("%Y-%m-%d") if entity.date_last_play else None,
|
||||||
|
"Released": entity.date_released.strftime("%Y-%m-%d") if entity.date_released else None,
|
||||||
|
"LocalId": str(entity.local_id) if entity.local_id else None,
|
||||||
|
"Path": str(entity.local_path) if entity.local_path else None,
|
||||||
|
}
|
||||||
|
|
||||||
def track_to_row(track: Track):
|
def track_to_row(track: Track):
|
||||||
return {
|
return entity_to_row(track) | {
|
||||||
"Title": track.title,
|
|
||||||
"Album": track.album.title if track.album else "",
|
"Album": track.album.title if track.album else "",
|
||||||
"Artists": ", ".join(a.title if a.title else "no_arist_name" for a in track.artists),
|
"Artists": ", ".join(a.title if a.title else "no_arist_name" for a in track.artists),
|
||||||
"Lyrics": track.has_lyrics,
|
"Lyrics": track.has_lyrics,
|
||||||
"AutoScore": track.auto_score,
|
|
||||||
"Added": track.added_at.strftime("%Y-%m-%d") if track.added_at else "",
|
|
||||||
"LocalId": str(track.local_id) if track.local_id else "",
|
|
||||||
"Path": str(track.local_path) if track.local_path else "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def artist_to_row(artist: Artist):
|
def artist_to_row(artist: Artist):
|
||||||
return {
|
return entity_to_row(artist) | {
|
||||||
"Title": artist.title,
|
|
||||||
"AutoScore": artist.auto_score,
|
|
||||||
"Resolved": int(artist.resolved_percentage * 100),
|
|
||||||
"LocalId": str(artist.local_id) if artist.local_id else "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def album_to_row(album: Album):
|
def album_to_row(album: Album):
|
||||||
return {
|
return entity_to_row(album) | {
|
||||||
"Title": album.title,
|
|
||||||
"AutoScore": album.auto_score,
|
|
||||||
"Resolved": int(album.resolved_percentage * 100),
|
|
||||||
"LocalId": str(album.local_id) if album.local_id else "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -200,7 +202,7 @@ def run():
|
||||||
# flow.log_stats()
|
# flow.log_stats()
|
||||||
|
|
||||||
gui = LibraryView()
|
gui = LibraryView()
|
||||||
gui.add_libraries([flow.spotify_library, flow.local_library])
|
gui.add_libraries([flow.spotify_library, flow.itunes_library, flow.local_library])
|
||||||
gui.render()
|
gui.render()
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
|
@ -4,77 +4,58 @@ from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Any
|
from typing import List, Optional, Any
|
||||||
|
|
||||||
|
|
||||||
class Entity:
|
class Entity:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id: str = None
|
self.id: str = None
|
||||||
self.mbid : str = None
|
self.mbid: str = None
|
||||||
|
|
||||||
self.title: str = None
|
self.title: str = None
|
||||||
|
self.duration_ms: int = None
|
||||||
|
|
||||||
self.fav: bool = False
|
self.fav: bool = False
|
||||||
self.rating: int = 0
|
self.rating: int = 0
|
||||||
self.play_count : int = 0
|
self.play_count: int = 0
|
||||||
self.date_added : datetime = None
|
self.date_added: datetime = None
|
||||||
self.date_released : datetime = None
|
self.date_released: datetime = None
|
||||||
self.date_last_play : datetime = None
|
self.date_last_play: datetime = None
|
||||||
self.auto_score: float = 0
|
self.auto_score: float = 0
|
||||||
|
|
||||||
self.local_id: str = None
|
self.local_id: str = None
|
||||||
self.resolved_percentage : float = 0
|
self.local_path: Path = None
|
||||||
|
self.resolved_percentage: float = 0
|
||||||
|
|
||||||
class Artist:
|
|
||||||
|
class Artist(Entity):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id: str = None
|
super().__init__()
|
||||||
self.title: str = None
|
|
||||||
self.tracks: List[Track] = []
|
self.tracks: List[Track] = []
|
||||||
self.albums: List[Album] = []
|
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:
|
class Track(Entity):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id: str = None
|
super().__init__()
|
||||||
self.title: str = None
|
|
||||||
self.artists: List[Artist] = []
|
self.artists: List[Artist] = []
|
||||||
self.album: Album = None
|
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.has_lyrics: bool = False
|
||||||
self.local_id: str = None
|
|
||||||
self.auto_score: float = 0
|
|
||||||
self.fav: bool = False
|
|
||||||
self.rating: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
class Album:
|
class Album(Entity):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id: str = None
|
super().__init__()
|
||||||
self.title: str = None
|
|
||||||
self.release_date: datetime = None
|
|
||||||
self.tracks: List[Track] = []
|
self.tracks: List[Track] = []
|
||||||
self.artists: List[Artist] = []
|
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:
|
class Playlist(Entity):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.title: str = None
|
super().__init__()
|
||||||
self.tracks: List[Track] = []
|
self.tracks: List[Track] = []
|
||||||
self.created_at: datetime = None
|
self.created_at: datetime = None
|
||||||
self.description: str = 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:
|
class Library:
|
||||||
|
|
@ -120,14 +101,8 @@ class Library:
|
||||||
artist.albums.append(album)
|
artist.albums.append(album)
|
||||||
|
|
||||||
def auto_score(self):
|
def auto_score(self):
|
||||||
self.score_tracks()
|
|
||||||
self.score_artists()
|
|
||||||
self.score_albums()
|
self.score_albums()
|
||||||
|
self.score_artists()
|
||||||
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):
|
def score_artists(self):
|
||||||
for track in self.tracks:
|
for track in self.tracks:
|
||||||
|
|
|
||||||
|
|
@ -26,60 +26,51 @@ class LibrarySaver:
|
||||||
def __init__(self, library: Library):
|
def __init__(self, library: Library):
|
||||||
self.library = library
|
self.library = library
|
||||||
|
|
||||||
@staticmethod
|
def _entity_to_dict(self, entity: Entity) -> dict[str, Any]:
|
||||||
def _artist_to_dict(artist: Artist) -> dict[str, Any]:
|
|
||||||
return {
|
return {
|
||||||
"id": artist.id,
|
"id": entity.id,
|
||||||
"title": artist.title,
|
"mbid": entity.mbid,
|
||||||
"tracks": [track.id for track in artist.tracks],
|
|
||||||
"albums": [album.id for album in artist.albums],
|
"title": entity.title,
|
||||||
"local_id": artist.local_id,
|
"duration": entity.duration_ms,
|
||||||
"auto_score": artist.auto_score,
|
|
||||||
"fav" : artist.fav,
|
"fav" : entity.fav,
|
||||||
"rating" : artist.rating,
|
"rating" : entity.rating,
|
||||||
|
"play_count": entity.play_count,
|
||||||
|
"date_added": entity.date_added,
|
||||||
|
"date_released": entity.date_released,
|
||||||
|
"date_last_play": entity.date_last_play,
|
||||||
|
"auto_score": entity.auto_score,
|
||||||
|
|
||||||
|
"local_id": entity.local_id,
|
||||||
|
"local_path": entity.local_path,
|
||||||
|
"resolved_percentage": entity.resolved_percentage,
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _artist_to_dict(self, artist: Artist) -> dict[str, Any]:
|
||||||
def _track_to_dict(track: Track) -> dict[str, Any]:
|
return self._entity_to_dict(artist) | {
|
||||||
return {
|
"tracks": [track.id for track in artist.tracks],
|
||||||
"id": track.id,
|
"albums": [album.id for album in artist.albums],
|
||||||
"title": track.title,
|
}
|
||||||
|
|
||||||
|
def _track_to_dict(self, track: Track) -> dict[str, Any]:
|
||||||
|
return self._entity_to_dict(track) | {
|
||||||
"artists": [artist.id for artist in track.artists],
|
"artists": [artist.id for artist in track.artists],
|
||||||
"album": track.album.id,
|
"album": track.album.id,
|
||||||
"duration_ms": track.duration_ms,
|
"duration_ms": track.duration_ms,
|
||||||
"added_at": _dt_to_str(track.added_at),
|
|
||||||
"local_path": track.local_path,
|
|
||||||
"has_lyrics": track.has_lyrics,
|
"has_lyrics": track.has_lyrics,
|
||||||
"local_id": track.local_id,
|
|
||||||
"auto_score": track.auto_score,
|
|
||||||
"fav" : track.fav,
|
|
||||||
"rating" : track.rating,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _playlist_to_dict(self, playlist: Playlist) -> dict[str, Any]:
|
||||||
def _playlist_to_dict(playlist: Playlist) -> dict[str, Any]:
|
return self._entity_to_dict(playlist) | {
|
||||||
return {
|
|
||||||
"title": playlist.title,
|
|
||||||
"tracks": [track.id for track in playlist.tracks],
|
"tracks": [track.id for track in playlist.tracks],
|
||||||
"created_at": _dt_to_str(playlist.created_at),
|
|
||||||
"description": playlist.description,
|
"description": playlist.description,
|
||||||
"auto_score": playlist.auto_score,
|
|
||||||
"fav" : playlist.fav,
|
|
||||||
"rating" : playlist.rating,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
def _album_to_dict(self ,album: Album) -> dict[str, Any]:
|
||||||
def _album_to_dict(album: Album) -> dict[str, Any]:
|
return self._entity_to_dict(album) | {
|
||||||
return {
|
|
||||||
"id": album.id,
|
|
||||||
"title": album.title,
|
|
||||||
"release_date": album.release_date,
|
|
||||||
"tracks": [track.id for track in album.tracks],
|
"tracks": [track.id for track in album.tracks],
|
||||||
"artists": [artist.id for artist in album.artists],
|
"artists": [artist.id for artist in album.artists],
|
||||||
"local_id": album.local_id,
|
|
||||||
"auto_score": album.auto_score,
|
|
||||||
"fav" : album.fav,
|
|
||||||
"rating" : album.rating,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def save(self, path: Path) -> None:
|
def save(self, path: Path) -> None:
|
||||||
|
|
@ -100,6 +91,7 @@ class LibrarySaver:
|
||||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LibraryLoader:
|
class LibraryLoader:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.track_map: dict[str, Track] = {}
|
self.track_map: dict[str, Track] = {}
|
||||||
|
|
@ -127,48 +119,54 @@ class LibraryLoader:
|
||||||
self.track_map[id] = item
|
self.track_map[id] = item
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
def load_entity(self, entity : Entity, data: dict[str, Any]):
|
||||||
|
entity.id = data.get("id")
|
||||||
|
entity.mbid = data.get("mbid")
|
||||||
|
|
||||||
|
entity.title = data.get("title")
|
||||||
|
entity.duration_ms = data.get("duration_ms")
|
||||||
|
|
||||||
|
entity.fav = data.get("fav")
|
||||||
|
entity.rating = data.get("rating")
|
||||||
|
entity.play_count = data.get("play_count")
|
||||||
|
entity.date_added = _str_to_dt(data.get("date_added"))
|
||||||
|
entity.date_released = _str_to_dt(data.get("date_released"))
|
||||||
|
entity.date_last_play = _str_to_dt(data.get("date_last_play"))
|
||||||
|
entity.auto_score = data.get("auto_score")
|
||||||
|
|
||||||
|
entity.local_id = data.get("local_id")
|
||||||
|
entity.local_path = data.get("local_path")
|
||||||
|
entity.resolved_percentage = data.get("resolved_percentage")
|
||||||
|
|
||||||
|
|
||||||
def load_track(self, data: dict[str, Any]) -> Track:
|
def load_track(self, data: dict[str, Any]) -> Track:
|
||||||
track = self.get_track(data.get("id"))
|
track = self.get_track(data.get("id"))
|
||||||
track.id = data.get("id")
|
self.load_entity(track, data)
|
||||||
track.title = data.get("title")
|
|
||||||
track.duration_ms = data.get("duration_ms")
|
track.duration_ms = data.get("duration_ms")
|
||||||
track.added_at = _str_to_dt(data.get("added_at"))
|
|
||||||
track.local_path = data.get("local_path")
|
|
||||||
track.artists = [self.get_artist(artist_id) for artist_id in data.get("artists")]
|
track.artists = [self.get_artist(artist_id) for artist_id in data.get("artists")]
|
||||||
track.album = self.get_album(data.get("album"))
|
track.album = self.get_album(data.get("album"))
|
||||||
track.has_lyrics = data.get("has_lyrics")
|
track.has_lyrics = data.get("has_lyrics")
|
||||||
track.local_id = data.get("local_id")
|
|
||||||
track.auto_score = data.get("auto_score")
|
|
||||||
track.fav = data.get("fav")
|
|
||||||
track.rating = data.get("rating")
|
|
||||||
|
|
||||||
self.track_map[track.id] = track
|
self.track_map[track.id] = track
|
||||||
return track
|
return track
|
||||||
|
|
||||||
def load_artist(self, data: dict[str, Any]):
|
def load_artist(self, data: dict[str, Any]):
|
||||||
artist = self.get_artist(data.get("id"))
|
artist = self.get_artist(data.get("id"))
|
||||||
artist.id = data.get("id")
|
self.load_entity(artist, data)
|
||||||
artist.title = data.get("title")
|
|
||||||
artist.tracks = [self.get_track(track_id) for track_id in data.get("tracks")]
|
artist.tracks = [self.get_track(track_id) for track_id in data.get("tracks")]
|
||||||
artist.albums = [self.get_album(album_id) for album_id in data.get("albums")] if data.get("albums") else []
|
artist.albums = [self.get_album(album_id) for album_id in data.get("albums")] if data.get("albums") else []
|
||||||
artist.local_id = data.get("local_id")
|
|
||||||
artist.auto_score = data.get("auto_score")
|
|
||||||
artist.fav = data.get("fav")
|
|
||||||
artist.rating = data.get("rating")
|
|
||||||
|
|
||||||
self.artist_map[artist.id] = artist
|
self.artist_map[artist.id] = artist
|
||||||
return artist
|
return artist
|
||||||
|
|
||||||
def load_album(self, data: dict[str, Any]):
|
def load_album(self, data: dict[str, Any]):
|
||||||
album = self.get_album(data.get("id"))
|
album = self.get_album(data.get("id"))
|
||||||
album.id = data.get("id")
|
self.load_entity(album, data)
|
||||||
|
|
||||||
album.tracks = [self.get_track(track_id) for track_id in data.get("tracks")]
|
album.tracks = [self.get_track(track_id) for track_id in data.get("tracks")]
|
||||||
album.title = data.get("title")
|
|
||||||
album.artists = [self.get_artist(artist_id) for artist_id in data.get("artists")]
|
album.artists = [self.get_artist(artist_id) for artist_id in data.get("artists")]
|
||||||
album.local_id = data.get("local_id")
|
|
||||||
album.auto_score = data.get("auto_score")
|
|
||||||
album.fav = data.get("fav")
|
|
||||||
album.rating = data.get("rating")
|
|
||||||
|
|
||||||
self.album_map[album.id] = album
|
self.album_map[album.id] = album
|
||||||
return album
|
return album
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,7 @@ class ParseItunesXml:
|
||||||
track.title = data.get("Name")
|
track.title = data.get("Name")
|
||||||
track.artists = self.parse_artists([data.get("Artist")])
|
track.artists = self.parse_artists([data.get("Artist")])
|
||||||
track.album = self.parse_album(data.get("Album"))
|
track.album = self.parse_album(data.get("Album"))
|
||||||
|
track.play_count = int(data.get("Play Count"))
|
||||||
|
|
||||||
if not track.album or not len(track.artists) or not track.title:
|
if not track.album or not len(track.artists) or not track.title:
|
||||||
raise "error parsing"
|
raise "error parsing"
|
||||||
|
|
@ -183,10 +184,9 @@ class ParseItunesXml:
|
||||||
|
|
||||||
self.library.name = "Itunes"
|
self.library.name = "Itunes"
|
||||||
|
|
||||||
|
for track in self.library.tracks:
|
||||||
|
track.auto_score = track.play_count
|
||||||
|
|
||||||
return self.library
|
return self.library
|
||||||
|
|
||||||
|
|
||||||
def parse_track_item(self, id, track: dict[str, Any]) -> Track:
|
|
||||||
|
|
||||||
return track
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ class Parser:
|
||||||
self.library.name = "Spotify"
|
self.library.name = "Spotify"
|
||||||
self.library.auto_score()
|
self.library.auto_score()
|
||||||
|
|
||||||
|
self.score_tracks()
|
||||||
|
|
||||||
return self.library
|
return self.library
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -122,3 +124,8 @@ class Parser:
|
||||||
self.library.artists.append(artist)
|
self.library.artists.append(artist)
|
||||||
|
|
||||||
return artist
|
return artist
|
||||||
|
|
||||||
|
def score_tracks(self):
|
||||||
|
for idx, track in enumerate(self.library.top_tracks):
|
||||||
|
score = len(self.library.top_tracks) - idx
|
||||||
|
track.auto_score = score
|
||||||
Loading…
Add table
Add a link
Reference in a new issue