206 lines
No EOL
6.7 KiB
Python
206 lines
No EOL
6.7 KiB
Python
import time
|
|
|
|
import streamlit as st
|
|
from st_aggrid import AgGrid, GridOptionsBuilder, GridUpdateMode
|
|
import pandas as pd
|
|
|
|
import Flow
|
|
|
|
from src.Library import Library, Artist, Album, Track, Playlist
|
|
|
|
def track_to_row(track: Track):
|
|
return {
|
|
"Title": track.title,
|
|
"Album": track.album.title if track.album else "",
|
|
"Artists": ", ".join(a.title if a.title else "no_arist_name" for a in track.artists),
|
|
"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):
|
|
return {
|
|
"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):
|
|
return {
|
|
"Title": album.title,
|
|
"AutoScore": album.auto_score,
|
|
"Resolved": int(album.resolved_percentage * 100),
|
|
"LocalId": str(album.local_id) if album.local_id else "",
|
|
}
|
|
|
|
|
|
class LibraryView:
|
|
def __init__(self):
|
|
self.lib : Library = None
|
|
self.libs : list[Library] = None
|
|
self.view = None
|
|
self.lyrics_only = False
|
|
self.query = None
|
|
|
|
def add_libraries(self, libs : list[Library]):
|
|
self.libs = libs
|
|
|
|
def render(self):
|
|
st.set_page_config(layout="wide")
|
|
|
|
with st.sidebar:
|
|
lib = st.selectbox(
|
|
"Library",
|
|
options=[lib.name for lib in self.libs],
|
|
)
|
|
|
|
for iter in self.libs:
|
|
if iter.name == lib:
|
|
self.lib = iter
|
|
|
|
st.write(f"Showing library '{self.lib.name}'")
|
|
|
|
self.view = st.radio(
|
|
"View",
|
|
["Tree"]
|
|
)
|
|
|
|
if self.view == "Tree":
|
|
self.render_artists_albums_tracks()
|
|
# elif self.view == "Tracks":
|
|
# self.render_tracks()
|
|
# elif self.view == "Playlists":
|
|
# self.render_playlists()
|
|
|
|
def track_visible(
|
|
self,
|
|
track: Track,
|
|
artist: Artist | None,
|
|
album: Album | None,
|
|
):
|
|
if self.lyrics_only and not track.has_lyrics:
|
|
return False
|
|
|
|
if self.query and self.query.lower() not in track.title.lower():
|
|
return False
|
|
|
|
if artist and all(a.id != artist.id for a in track.artists):
|
|
return False
|
|
|
|
if album and (not track.album or track.album.id != album.id):
|
|
return False
|
|
|
|
return True
|
|
|
|
def render_artists_albums_tracks(self):
|
|
# --- ARTISTS TABLE ---
|
|
st.subheader("Artists")
|
|
artist_rows = [artist_to_row(a) for a in self.lib.artists]
|
|
df_artists = pd.DataFrame(artist_rows)
|
|
|
|
gb_artists = GridOptionsBuilder.from_dataframe(df_artists)
|
|
gb_artists.configure_selection(selection_mode="multiple", use_checkbox=True)
|
|
gb_artists.configure_column("Title", filter="agTextColumnFilter")
|
|
gb_artists.configure_column("AutoScore", sort="desc")
|
|
grid_options_artists = gb_artists.build()
|
|
|
|
grid_response_artists = AgGrid(
|
|
df_artists,
|
|
gridOptions=grid_options_artists,
|
|
update_mode=GridUpdateMode.SELECTION_CHANGED,
|
|
allow_unsafe_jscode=True,
|
|
enable_enterprise_modules=False,
|
|
fit_columns_on_grid_load=True,
|
|
)
|
|
|
|
selected_rows_df = grid_response_artists.get("selected_rows")
|
|
selected_artist_titles = selected_rows_df["Title"].tolist() if selected_rows_df is not None and not selected_rows_df.empty else []
|
|
selected_artists = [a for a in self.lib.artists if a.title in selected_artist_titles]
|
|
|
|
# --- ALBUMS TABLE ---
|
|
st.subheader("Albums")
|
|
if selected_artists:
|
|
albums_list = []
|
|
for artist in selected_artists:
|
|
albums_list.extend(artist.albums)
|
|
albums_list = list({al.id: al for al in albums_list}.values())
|
|
else:
|
|
albums_list = self.lib.albums
|
|
|
|
album_rows = [album_to_row(a) for a in albums_list]
|
|
df_albums = pd.DataFrame(album_rows)
|
|
|
|
gb_albums = GridOptionsBuilder.from_dataframe(df_albums)
|
|
gb_albums.configure_selection(selection_mode="multiple", use_checkbox=True)
|
|
gb_albums.configure_column("Title", filter="agTextColumnFilter")
|
|
gb_albums.configure_column("AutoScore", sort="desc")
|
|
grid_options_albums = gb_albums.build()
|
|
|
|
grid_response_albums = AgGrid(
|
|
df_albums,
|
|
gridOptions=grid_options_albums,
|
|
update_mode=GridUpdateMode.SELECTION_CHANGED,
|
|
allow_unsafe_jscode=True,
|
|
enable_enterprise_modules=False,
|
|
fit_columns_on_grid_load=True,
|
|
)
|
|
|
|
selected_rows_df = grid_response_albums.get("selected_rows")
|
|
selected_album_titles = selected_rows_df["Title"].tolist() if selected_rows_df is not None and not selected_rows_df.empty else []
|
|
selected_albums = [al for al in albums_list if al.title in selected_album_titles]
|
|
|
|
# --- TRACKS TABLE ---
|
|
st.subheader("Tracks")
|
|
if selected_albums:
|
|
tracks_list = []
|
|
for album in selected_albums:
|
|
tracks_list.extend(album.tracks)
|
|
elif selected_artists:
|
|
tracks_list = []
|
|
for artist in selected_artists:
|
|
tracks_list.extend([t for t in self.lib.tracks if artist in t.artists])
|
|
else:
|
|
tracks_list = self.lib.tracks
|
|
|
|
track_rows = [track_to_row(t) for t in tracks_list]
|
|
df_tracks = pd.DataFrame(track_rows)
|
|
|
|
gb_tracks = GridOptionsBuilder.from_dataframe(df_tracks)
|
|
gb_tracks.configure_selection(selection_mode="multiple", use_checkbox=True)
|
|
gb_tracks.configure_column("Title", filter="agTextColumnFilter")
|
|
gb_tracks.configure_column("AutoScore", sort="desc")
|
|
grid_options_tracks = gb_tracks.build()
|
|
|
|
AgGrid(
|
|
df_tracks,
|
|
gridOptions=grid_options_tracks,
|
|
update_mode=GridUpdateMode.SELECTION_CHANGED,
|
|
allow_unsafe_jscode=True,
|
|
enable_enterprise_modules=False,
|
|
fit_columns_on_grid_load=True,
|
|
)
|
|
|
|
|
|
def run():
|
|
flow = Flow.Flow()
|
|
|
|
# flow.fetch_spotify()
|
|
# flow.fetch_local()
|
|
|
|
# flow.parse_spotify_library()
|
|
# flow.parse_local_library()
|
|
|
|
flow.load_libraries()
|
|
|
|
# flow.map_local_to_spotify()
|
|
|
|
# flow.log_stats()
|
|
|
|
gui = LibraryView()
|
|
gui.add_libraries([flow.spotify_library, flow.local_library])
|
|
gui.render()
|
|
|
|
run() |