From a3c4558d5214e998c7b1ca0011b892f2b7ec2140 Mon Sep 17 00:00:00 2001 From: cwilvx Date: Sun, 30 Jun 2024 23:11:33 +0300 Subject: [PATCH] port: recent items for homepage --- TODO.md | 1 + app/db/__init__.py | 5 +++ app/db/libdata.py | 14 +++++-- app/db/userdata.py | 15 ++++++++ app/db/utils.py | 8 ++++ app/lib/home/recentlyplayed.py | 69 +++++++++++++++++++++------------- app/lib/playlistlib.py | 12 +++--- app/lib/tagger.py | 2 + app/models/logger.py | 3 +- 9 files changed, 92 insertions(+), 37 deletions(-) diff --git a/TODO.md b/TODO.md index dc6d5216..ef37f2ac 100644 --- a/TODO.md +++ b/TODO.md @@ -47,3 +47,4 @@ - Remove duplicates on artist page (test with Hanson) - Test foreign keys on delete - Map scrobble info on app start +- Make home page recent items faster! \ No newline at end of file diff --git a/app/db/__init__.py b/app/db/__init__.py index bd857356..853a0eac 100644 --- a/app/db/__init__.py +++ b/app/db/__init__.py @@ -3,6 +3,7 @@ from typing import Any from sqlalchemy import ( create_engine, delete, + func, insert, select, ) @@ -81,6 +82,10 @@ class Base(MappedAsDataclass, DeclarativeBase): def all(cls): return cls.execute(select(cls)) + @classmethod + def count(cls): + return cls.execute(select(func.count()).select_from(cls)).scalar() + def create_all(): Base().metadata.create_all(engine) diff --git a/app/db/libdata.py b/app/db/libdata.py index 0708b7fc..f8750453 100644 --- a/app/db/libdata.py +++ b/app/db/libdata.py @@ -35,9 +35,13 @@ class Base(MasterBase, DeclarativeBase): if cls.__tablename__ == "track": stmt = select(TrackTable.trackhash).where(cls.last_mod < create_date) elif cls.__tablename__ == "album": - stmt = select(AlbumTable.albumhash).where(cls.created_date < create_date) + stmt = select(AlbumTable.albumhash).where( + cls.created_date < create_date + ) elif cls.__tablename__ == "artist": - stmt = select(ArtistTable.artisthash).where(cls.created_date < create_date) + stmt = select(ArtistTable.artisthash).where( + cls.created_date < create_date + ) result = conn.execute(stmt) return {row[0] for row in result.fetchall()} @@ -206,6 +210,11 @@ class TrackTable(Base): return tracks_to_dataclasses(result.fetchall()) + @classmethod + def get_recently_played(cls, limit: int): + result = cls.execute(select(cls).order_by(cls.lastplayed.desc()).limit(limit)) + return tracks_to_dataclasses(result.fetchall()) + @classmethod def remove_tracks_by_filepaths(cls, filepaths: set[str]): with DbManager(commit=True) as conn: @@ -250,7 +259,6 @@ 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/db/userdata.py b/app/db/userdata.py index b57cd73f..1ca026a5 100644 --- a/app/db/userdata.py +++ b/app/db/userdata.py @@ -25,6 +25,8 @@ from app.db.utils import ( plugin_to_dataclasses, similar_artist_to_dataclass, similar_artists_to_dataclass, + tracklog_to_dataclass, + tracklog_to_dataclasses, tracks_to_dataclasses, user_to_dataclass, user_to_dataclasses, @@ -166,6 +168,7 @@ class FavoritesTable(Base): JSON(), nullable=True, default_factory=dict ) + @classmethod def get_all(cls): with DbManager() as conn: @@ -259,3 +262,15 @@ class ScrobbleTable(Base): def add(cls, item: dict[str, Any]): item["userid"] = get_current_userid() return cls.insert_one(item) + + @classmethod + def get_all(cls, start: int, limit: int): + result = cls.execute( + select(cls) + .where(cls.userid == get_current_userid()) + .order_by(cls.timestamp.desc()) + .offset(start) + .limit(limit) + ) + + return tracklog_to_dataclasses(result.fetchall()) diff --git a/app/db/utils.py b/app/db/utils.py index 0df36aab..0ed92c2c 100644 --- a/app/db/utils.py +++ b/app/db/utils.py @@ -3,6 +3,7 @@ from typing import Any from app.models import Album as AlbumModel, Artist as ArtistModel, Track as TrackModel from app.models.favorite import Favorite from app.models.lastfm import SimilarArtist +from app.models.logger import TrackLog from app.models.plugins import Plugin from app.models.user import User @@ -73,3 +74,10 @@ def plugin_to_dataclass(entry: Any): def plugin_to_dataclasses(entries: Any): return [plugin_to_dataclass(entry) for entry in entries] + +def tracklog_to_dataclass(entry: Any): + entry_dict = entry._asdict() + return TrackLog(**entry_dict) + +def tracklog_to_dataclasses(entries: Any): + return [tracklog_to_dataclass(entry) for entry in entries] \ No newline at end of file diff --git a/app/lib/home/recentlyplayed.py b/app/lib/home/recentlyplayed.py index 7dc5066e..a22bd61d 100644 --- a/app/lib/home/recentlyplayed.py +++ b/app/lib/home/recentlyplayed.py @@ -1,29 +1,36 @@ from datetime import datetime import os +from app.db.libdata import AlbumTable, ArtistTable, TrackTable +from app.db.userdata import FavoritesTable, ScrobbleTable from app.models.logger import TrackLog -from app.db.sqlite.logger.tracks import SQLiteTrackLogger as db -from app.db.sqlite.playlists import SQLitePlaylistMethods as pdb -from app.db.sqlite.favorite import SQLiteFavoriteMethods as fdb +# from app.db.sqlite.logger.tracks import SQLiteTrackLogger as db +# from app.db.sqlite.playlists import SQLitePlaylistMethods as pdb +# from app.db.sqlite.favorite import SQLiteFavoriteMethods as fdb from app.models.playlist import Playlist from app.serializers.track import serialize_track from app.serializers.album import album_serializer from app.lib.playlistlib import get_first_4_images -from app.utils.dates import create_new_date, date_string_to_time_passed, timestamp_to_time_passed +from app.store.folder import FolderStore +from app.utils.dates import ( + create_new_date, + date_string_to_time_passed, + timestamp_to_time_passed, +) from app.serializers.artist import serialize_for_card from app.serializers.playlist import serialize_for_card as serialize_playlist from app.lib.home.recentlyadded import get_recently_added_playlist -from app.store.albums import AlbumStore -from app.store.tracks import TrackStore -from app.store.artists import ArtistStore - +# from app.store.albums import AlbumStore +# from app.store.tracks import TrackStore +# from app.store.artists import ArtistStore def get_recently_played(limit=7): # TODO: Paginate this - entries = db.get_all() + # entries = db.get_all() + entries = ScrobbleTable.get_all(0, 200) items = [] added = set() @@ -36,7 +43,7 @@ def get_recently_played(limit=7): if len(items) >= limit: break - entry = TrackLog(*entry) + # entry = TrackLog(*entry) if entry.source in added: continue @@ -44,7 +51,8 @@ def get_recently_played(limit=7): added.add(entry.source) if entry.type == "album": - album = AlbumStore.get_album_by_hash(entry.type_src) + # album = AlbumStore.get_album_by_hash(entry.type_src) + album = AlbumTable.get_album_by_albumhash(entry.type_src) if album is None: continue @@ -72,7 +80,8 @@ def get_recently_played(limit=7): continue if entry.type == "artist": - artist = ArtistStore.get_artist_by_hash(entry.type_src) + # artist = ArtistStore.get_artist_by_hash(entry.type_src) + artist = ArtistTable.get_artist_by_hash(entry.type_src) if artist is None: continue @@ -107,13 +116,14 @@ def get_recently_played(limit=7): # print(folder) # folder = os.path.join("/", folder, "") # print(folder) - count = len([t for t in TrackStore.tracks if t.folder == folder]) + # count = len([t for t in TrackStore.tracks if t.folder == folder]) + count = FolderStore.count_tracks_containing_paths([folder]) items.append( { "type": "folder", "item": { "path": folder, - "count": count, + "count": count[0]["trackcount"], "help_text": "folder", "time": timestamp_to_time_passed(entry.timestamp), }, @@ -122,12 +132,15 @@ def get_recently_played(limit=7): continue if entry.type == "playlist": + continue is_custom = entry.type_src in [i["name"] for i in custom_playlists] # is_recently_added = entry.type_src == "recentlyadded" if is_custom: playlist, _ = next( - i["handler"]() for i in custom_playlists if i["name"] == entry.type_src + i["handler"]() + for i in custom_playlists + if i["name"] == entry.type_src ) playlist.images = [i["image"] for i in playlist.images] @@ -175,16 +188,17 @@ def get_recently_played(limit=7): "type": "favorite_tracks", "item": { "help_text": "playlist", - "count": fdb.get_track_count(), + "count": FavoritesTable.count(), "time": timestamp_to_time_passed(entry.timestamp), }, } ) continue - try: - track = TrackStore.get_tracks_by_trackhashes([entry.trackhash])[0] - except IndexError: + # track = TrackStore.get_tracks_by_trackhashes([entry.trackhash])[0] + track = TrackTable.get_track_by_trackhash(entry.trackhash) + + if track is None: continue track = serialize_track(track) @@ -202,10 +216,12 @@ def get_recently_played(limit=7): def get_recently_played_tracks(limit: int): - records = db.get_recently_played(start=0, limit=limit) - last_updated = records[0].timestamp - tracks = TrackStore.get_tracks_by_trackhashes([r.trackhash for r in records]) - return tracks, last_updated + # records = db.get_recently_played(start=0, limit=limit) + # last_updated = records[0].timestamp + # tracks = TrackStore.get_tracks_by_trackhashes([r.trackhash for r in records]) + # return tracks, last_updated + return TrackTable.get_recently_played(limit) + def get_recently_played_playlist(limit: int = 100): playlist = Playlist( @@ -217,13 +233,12 @@ def get_recently_played_playlist(limit: int = 100): trackhashes=[], ) - tracks, timestamp = get_recently_played_tracks(limit) - - date = datetime.fromtimestamp(timestamp) + tracks = get_recently_played_tracks(limit) + date = datetime.fromtimestamp(tracks[0].lastplayed) playlist.last_updated = date_string_to_time_passed(create_new_date(date)) images = get_first_4_images(tracks=tracks) playlist.images = images playlist.set_count(len(tracks)) - return playlist, tracks \ No newline at end of file + return playlist, tracks diff --git a/app/lib/playlistlib.py b/app/lib/playlistlib.py index f9512fe1..5d8f7292 100644 --- a/app/lib/playlistlib.py +++ b/app/lib/playlistlib.py @@ -10,10 +10,8 @@ from typing import Any from PIL import Image, ImageSequence from app import settings +from app.db.libdata import AlbumTable, TrackTable from app.models.track import Track -from app.store.albums import AlbumStore -from app.store.tracks import TrackStore - def create_thumbnail(image: Any, img_path: str) -> str: """ @@ -105,7 +103,8 @@ def get_first_4_images( tracks: list[Track] = [], trackhashes: list[str] = [] ) -> list[dict["str", str]]: if len(trackhashes) > 0: - tracks = TrackStore.get_tracks_by_trackhashes(trackhashes) + # tracks = TrackStore.get_tracks_by_trackhashes(trackhashes) + tracks = TrackTable.get_tracks_by_trackhashes(trackhashes) albums = [] @@ -116,11 +115,12 @@ def get_first_4_images( if len(albums) == 4: break - albums = AlbumStore.get_albums_by_hashes(albums) + # albums = AlbumStore.get_albums_by_hashes(albums) + albums = AlbumTable.get_albums_by_albumhashes(albums) images = [ { "image": album.image, - "color": "".join(album.colors), + "color": album.color, } for album in albums ] diff --git a/app/lib/tagger.py b/app/lib/tagger.py index 2bb7f660..052a7dff 100644 --- a/app/lib/tagger.py +++ b/app/lib/tagger.py @@ -1,3 +1,4 @@ +import gc import os from pprint import pprint from time import time @@ -280,6 +281,7 @@ class IndexEverything: # pass CordinateMedia(instance_key=str(time())) + gc.collect() @background diff --git a/app/models/logger.py b/app/models/logger.py index 0f1e92d8..e4b6e368 100644 --- a/app/models/logger.py +++ b/app/models/logger.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Literal +from typing import Any, Literal @dataclass @@ -14,6 +14,7 @@ class TrackLog: timestamp: int source: str userid: int + extra: dict[str, Any] type = "track" type_src = None