From 5759521de0c5c1892a608d0744c9e82c637cbef6 Mon Sep 17 00:00:00 2001 From: cwilvx Date: Sun, 30 Jun 2024 21:40:49 +0300 Subject: [PATCH] fix: recently added --- app/db/libdata.py | 21 +++++- app/lib/home/recentlyadded.py | 137 +++++++++++++++++++++------------- app/models/playlist.py | 4 +- app/utils/__init__.py | 9 +++ 4 files changed, 113 insertions(+), 58 deletions(-) diff --git a/app/db/libdata.py b/app/db/libdata.py index 9748fe3f..0708b7fc 100644 --- a/app/db/libdata.py +++ b/app/db/libdata.py @@ -30,14 +30,14 @@ def create_all(): class Base(MasterBase, DeclarativeBase): @classmethod - def get_all_hashes(cls): + def get_all_hashes(cls, create_date: int | None = None): with DbManager() as conn: if cls.__tablename__ == "track": - stmt = select(TrackTable.trackhash) + stmt = select(TrackTable.trackhash).where(cls.last_mod < create_date) elif cls.__tablename__ == "album": - stmt = select(AlbumTable.albumhash) + stmt = select(AlbumTable.albumhash).where(cls.created_date < create_date) elif cls.__tablename__ == "artist": - stmt = select(ArtistTable.artisthash) + stmt = select(ArtistTable.artisthash).where(cls.created_date < create_date) result = conn.execute(stmt) return {row[0] for row in result.fetchall()} @@ -194,6 +194,18 @@ class TrackTable(Base): ) return tracks_to_dataclasses(result.fetchall()) + @classmethod + def get_recently_added(cls, start: int, limit: int): + with DbManager() as conn: + result = conn.execute( + select(TrackTable) + .order_by(TrackTable.last_mod.desc()) + .offset(start) + .limit(limit) + ) + + return tracks_to_dataclasses(result.fetchall()) + @classmethod def remove_tracks_by_filepaths(cls, filepaths: set[str]): with DbManager(commit=True) as conn: @@ -238,6 +250,7 @@ class AlbumTable(Base): all = result.fetchall() return albums_to_dataclasses(all) + @classmethod def get_album_by_albumhash(cls, hash: str): with DbManager() as conn: diff --git a/app/lib/home/recentlyadded.py b/app/lib/home/recentlyadded.py index ce9c86cf..ba99c8d1 100644 --- a/app/lib/home/recentlyadded.py +++ b/app/lib/home/recentlyadded.py @@ -1,11 +1,15 @@ from datetime import datetime +from pprint import pprint +from time import time +from app.db.libdata import AlbumTable, ArtistTable, TrackTable from app.lib.playlistlib import get_first_4_images from app.models.playlist import Playlist from app.models.track import Track -from app.store.tracks import TrackStore -from app.store.albums import AlbumStore -from app.store.artists import ArtistStore + +# from app.store.tracks import TrackStore +# from app.store.albums import AlbumStore +# from app.store.artists import ArtistStore from app.serializers.track import serialize_track from app.serializers.album import album_serializer @@ -13,7 +17,12 @@ from app.serializers.artist import serialize_for_card from itertools import groupby -from app.utils.dates import create_new_date, date_string_to_time_passed, timestamp_to_time_passed +from app.utils import flatten +from app.utils.dates import ( + create_new_date, + date_string_to_time_passed, + timestamp_to_time_passed, +) older_albums = set() older_artists = set() @@ -36,7 +45,7 @@ def check_is_album_folder(tracks: list[Track]): def check_is_artist_folder(tracks: list[Track]): # INFO: flatten artist hashes using "-" as a separator - artisthashes = "-".join(t.artist_hashes for t in tracks).split("-") + artisthashes = flatten([t.artisthashes for t in tracks]) return calc_based_on_percent(artisthashes, len(tracks)) @@ -48,27 +57,22 @@ def check_is_track_folder(tracks: list[Track]): return [create_track(t) for t in tracks] -def check_is_new_artist(artisthash: str, timestamp: int): - """ - Checks if an artist already exists in the library. - """ - tracks = filter( - lambda t: t.last_mod < timestamp and artisthash in t.artist_hashes, - TrackStore.tracks, - ) - - return next(tracks, None) is None +# def check_is_new_artist(hashes: set[str], artisthash: str, timestamp: int): +# """ +# Checks if an artist already exists in the library. +# """ +# return artisthash not in hashes -def check_is_new_album(albumhash: str, timestamp: int): - """ - Checks if an album already exists in the library. - """ - tracks = filter( - lambda t: t.last_mod < timestamp and t.albumhash == albumhash, TrackStore.tracks - ) +# def check_is_new_album(albumhash: str, timestamp: int): +# """ +# Checks if an album already exists in the library. +# """ +# tracks = filter( +# lambda t: t.last_mod < timestamp and t.albumhash == albumhash, TrackStore.tracks +# ) - return next(tracks, None) is None +# return next(tracks, None) is None def create_track(t: Track): @@ -88,13 +92,19 @@ def create_track(t: Track): group_type = dict[str, list[Track], float] -def check_folder_type(group_: group_type) -> str: +def check_folder_type(group_: group_type): # check if all tracks in group have the same albumhash # if so, return "album" key = group_["folder"] tracks = group_["tracks"] time = group_["time"] + print(f"Checking folder: {key}") + print(f"Tracks: {len(tracks)}") + + existing_artist_hashes: set[str] = set(ArtistTable.get_all_hashes(time)) + existing_album_hashes: set[str] = set(AlbumTable.get_all_hashes(time)) + if len(tracks) == 1: entry = create_track(tracks[0]) entry["item"]["time"] = timestamp_to_time_passed(time) @@ -102,7 +112,7 @@ def check_folder_type(group_: group_type) -> str: is_album, albumhash, _ = check_is_album_folder(tracks) if is_album: - album = AlbumStore.get_album_by_hash(albumhash) + album = AlbumTable.get_album_by_albumhash(albumhash) if album is None: return None @@ -120,7 +130,7 @@ def check_folder_type(group_: group_type) -> str: }, ) album["help_text"] = ( - "NEW ALBUM" if check_is_new_album(albumhash, time) else "NEW TRACKS" + "NEW ALBUM" if albumhash in existing_album_hashes else "NEW TRACKS" ) album["time"] = timestamp_to_time_passed(time) @@ -131,7 +141,7 @@ def check_folder_type(group_: group_type) -> str: is_artist, artisthash, trackcount = check_is_artist_folder(tracks) if is_artist: - artist = ArtistStore.get_artist_by_hash(artisthash) + artist = ArtistTable.get_artist_by_hash(artisthash) if artist is None: return None @@ -139,7 +149,7 @@ def check_folder_type(group_: group_type) -> str: artist = serialize_for_card(artist) artist["trackcount"] = trackcount artist["help_text"] = ( - "NEW ARTIST" if check_is_new_artist(artisthash, time) else "NEW MUSIC" + "NEW ARTIST" if artisthash not in existing_artist_hashes else "NEW MUSIC" ) artist["time"] = timestamp_to_time_passed(time) @@ -165,40 +175,62 @@ def check_folder_type(group_: group_type) -> str: ) -def group_track_by_folders(tracks: Track): +def group_track_by_folders(tracks: list[Track], groups: dict[str, list[Track]]): """ Groups tracks by folder and returns a list of groups sorted by last modified date. Uses generator expressions to avoid creating intermediate lists. """ - # INFO: sort tracks by folder name, then group by folder name tracks = sorted(tracks, key=lambda t: t.folder) - groups = groupby(tracks, lambda t: t.folder) + thisgroup = groupby(tracks, lambda t: t.folder) - # INFO: sort tracks by last modified date in descending order to get the most recent last modified date - groups = ( - (folder, sorted(tracks, key=lambda t: t.last_mod, reverse=True)) - for folder, tracks in groups - ) + for folder, thistracks in thisgroup: + groups.setdefault(folder, []).extend(thistracks) - # INFO: Return a generator of the groups - groups = ( - {"folder": folder, "tracks": list(tracks), "time": tracks[0].last_mod} - for folder, tracks in groups - ) - - # sort groups by last modified date - return sorted(groups, key=lambda group: group["time"], reverse=True) + return groups def get_recently_added_items(limit: int = 7): - tracks = sorted(TrackStore.tracks, key=lambda t: t.created_date) - groups = group_track_by_folders(tracks) + # tracks = sorted(TrackStore.tracks, key=lambda t: t.created_date) + now = time() + tracks = get_recently_added_tracks(start=0, limit=None) + then = time() + + print(f"Time taken to get tracks: {then - now}") + groups = group_track_by_folders(tracks, {}) + # print(groups) + last_trackcount: int = len(tracks) + + # while len(groups.keys()) < limit and last_trackcount > 0: + # distracks = get_recently_added_tracks(start=len(tracks), limit=100) + # last_trackcount = len(distracks) + + # tracks.extend(distracks) + # groups = group_track_by_folders(tracks, groups) + + grouplist = [] + + # INFO: sort tracks by last modified date in descending order to get the most recent last modified date + for folder, trackgroup in groups.items(): + trackgroup.sort(key=lambda t: t.last_mod, reverse=True) + grouplist.append( + { + "folder": folder, + "len": len(trackgroup), + "tracks": trackgroup, + "time": trackgroup[0].last_mod, + } + ) + + pprint(f"😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅😅 {grouplist[0]['len']}") + + # sort groups by last modified date + grouplist = sorted(grouplist, key=lambda group: group["time"], reverse=True) recent_items = [] - for group in groups: + for group in grouplist: item = check_folder_type(group) if item not in recent_items: @@ -217,7 +249,6 @@ def get_recently_added_items(limit: int = 7): return recent_items - def get_recently_added_playlist(limit: int = 100): playlist = Playlist( id="recentlyadded", @@ -232,7 +263,7 @@ def get_recently_added_playlist(limit: int = 100): try: # Create date to show as last updated - date = datetime.fromtimestamp(tracks[0].created_date) + date = datetime.fromtimestamp(tracks[0].last_mod) except IndexError: return playlist, [] @@ -244,6 +275,8 @@ def get_recently_added_playlist(limit: int = 100): return playlist, tracks -def get_recently_added_tracks(limit: int): - tracks = sorted(TrackStore.tracks, key=lambda t: t.created_date, reverse=True) - return tracks[:limit] \ No newline at end of file + +def get_recently_added_tracks(start: int = 0, limit: int = 100): + # tracks = sorted(TrackStore.tracks, key=lambda t: t.created_date, reverse=True) + return TrackTable.get_recently_added(start, limit) + # return tracks[:limit] diff --git a/app/models/playlist.py b/app/models/playlist.py index a916bb3d..34e95c3f 100644 --- a/app/models/playlist.py +++ b/app/models/playlist.py @@ -10,7 +10,7 @@ from app import settings class Playlist: """Creates playlist objects""" - id: int + id: int | str image: str | None last_updated: str name: str @@ -21,7 +21,7 @@ class Playlist: count: int = 0 duration: int = 0 has_image: bool = False - images: list[str] = dataclasses.field(default_factory=list) + images: list[dict[str, str]] = dataclasses.field(default_factory=list) pinned: bool = False def __post_init__(self): diff --git a/app/utils/__init__.py b/app/utils/__init__.py index 84cb6dd0..7cce8009 100644 --- a/app/utils/__init__.py +++ b/app/utils/__init__.py @@ -1,4 +1,7 @@ import locale +from typing import TypeVar + +T = TypeVar("T") # Set to user's default locale: locale.setlocale(locale.LC_ALL, "") @@ -9,3 +12,9 @@ locale.setlocale(locale.LC_ALL, "") def format_number(number: float) -> str: return locale.format_string("%d", number, grouping=True) + + + + +def flatten(list_: list[list[T]]) -> list[T]: + return [item for sublist in list_ for item in sublist]