mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
port: recent items for homepage
This commit is contained in:
@@ -47,3 +47,4 @@
|
|||||||
- Remove duplicates on artist page (test with Hanson)
|
- Remove duplicates on artist page (test with Hanson)
|
||||||
- Test foreign keys on delete
|
- Test foreign keys on delete
|
||||||
- Map scrobble info on app start
|
- Map scrobble info on app start
|
||||||
|
- Make home page recent items faster!
|
||||||
@@ -3,6 +3,7 @@ from typing import Any
|
|||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
create_engine,
|
create_engine,
|
||||||
delete,
|
delete,
|
||||||
|
func,
|
||||||
insert,
|
insert,
|
||||||
select,
|
select,
|
||||||
)
|
)
|
||||||
@@ -81,6 +82,10 @@ class Base(MappedAsDataclass, DeclarativeBase):
|
|||||||
def all(cls):
|
def all(cls):
|
||||||
return cls.execute(select(cls))
|
return cls.execute(select(cls))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def count(cls):
|
||||||
|
return cls.execute(select(func.count()).select_from(cls)).scalar()
|
||||||
|
|
||||||
|
|
||||||
def create_all():
|
def create_all():
|
||||||
Base().metadata.create_all(engine)
|
Base().metadata.create_all(engine)
|
||||||
|
|||||||
+11
-3
@@ -35,9 +35,13 @@ class Base(MasterBase, DeclarativeBase):
|
|||||||
if cls.__tablename__ == "track":
|
if cls.__tablename__ == "track":
|
||||||
stmt = select(TrackTable.trackhash).where(cls.last_mod < create_date)
|
stmt = select(TrackTable.trackhash).where(cls.last_mod < create_date)
|
||||||
elif cls.__tablename__ == "album":
|
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":
|
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)
|
result = conn.execute(stmt)
|
||||||
return {row[0] for row in result.fetchall()}
|
return {row[0] for row in result.fetchall()}
|
||||||
@@ -206,6 +210,11 @@ class TrackTable(Base):
|
|||||||
|
|
||||||
return tracks_to_dataclasses(result.fetchall())
|
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
|
@classmethod
|
||||||
def remove_tracks_by_filepaths(cls, filepaths: set[str]):
|
def remove_tracks_by_filepaths(cls, filepaths: set[str]):
|
||||||
with DbManager(commit=True) as conn:
|
with DbManager(commit=True) as conn:
|
||||||
@@ -250,7 +259,6 @@ class AlbumTable(Base):
|
|||||||
all = result.fetchall()
|
all = result.fetchall()
|
||||||
return albums_to_dataclasses(all)
|
return albums_to_dataclasses(all)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_album_by_albumhash(cls, hash: str):
|
def get_album_by_albumhash(cls, hash: str):
|
||||||
with DbManager() as conn:
|
with DbManager() as conn:
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ from app.db.utils import (
|
|||||||
plugin_to_dataclasses,
|
plugin_to_dataclasses,
|
||||||
similar_artist_to_dataclass,
|
similar_artist_to_dataclass,
|
||||||
similar_artists_to_dataclass,
|
similar_artists_to_dataclass,
|
||||||
|
tracklog_to_dataclass,
|
||||||
|
tracklog_to_dataclasses,
|
||||||
tracks_to_dataclasses,
|
tracks_to_dataclasses,
|
||||||
user_to_dataclass,
|
user_to_dataclass,
|
||||||
user_to_dataclasses,
|
user_to_dataclasses,
|
||||||
@@ -166,6 +168,7 @@ class FavoritesTable(Base):
|
|||||||
JSON(), nullable=True, default_factory=dict
|
JSON(), nullable=True, default_factory=dict
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls):
|
def get_all(cls):
|
||||||
with DbManager() as conn:
|
with DbManager() as conn:
|
||||||
@@ -259,3 +262,15 @@ class ScrobbleTable(Base):
|
|||||||
def add(cls, item: dict[str, Any]):
|
def add(cls, item: dict[str, Any]):
|
||||||
item["userid"] = get_current_userid()
|
item["userid"] = get_current_userid()
|
||||||
return cls.insert_one(item)
|
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())
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from typing import Any
|
|||||||
from app.models import Album as AlbumModel, Artist as ArtistModel, Track as TrackModel
|
from app.models import Album as AlbumModel, Artist as ArtistModel, Track as TrackModel
|
||||||
from app.models.favorite import Favorite
|
from app.models.favorite import Favorite
|
||||||
from app.models.lastfm import SimilarArtist
|
from app.models.lastfm import SimilarArtist
|
||||||
|
from app.models.logger import TrackLog
|
||||||
from app.models.plugins import Plugin
|
from app.models.plugins import Plugin
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
|
|
||||||
@@ -73,3 +74,10 @@ def plugin_to_dataclass(entry: Any):
|
|||||||
|
|
||||||
def plugin_to_dataclasses(entries: Any):
|
def plugin_to_dataclasses(entries: Any):
|
||||||
return [plugin_to_dataclass(entry) for entry in entries]
|
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]
|
||||||
@@ -1,29 +1,36 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
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.models.logger import TrackLog
|
||||||
|
|
||||||
from app.db.sqlite.logger.tracks import SQLiteTrackLogger as db
|
# from app.db.sqlite.logger.tracks import SQLiteTrackLogger as db
|
||||||
from app.db.sqlite.playlists import SQLitePlaylistMethods as pdb
|
# from app.db.sqlite.playlists import SQLitePlaylistMethods as pdb
|
||||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as fdb
|
# from app.db.sqlite.favorite import SQLiteFavoriteMethods as fdb
|
||||||
|
|
||||||
from app.models.playlist import Playlist
|
from app.models.playlist import Playlist
|
||||||
from app.serializers.track import serialize_track
|
from app.serializers.track import serialize_track
|
||||||
from app.serializers.album import album_serializer
|
from app.serializers.album import album_serializer
|
||||||
from app.lib.playlistlib import get_first_4_images
|
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.artist import serialize_for_card
|
||||||
from app.serializers.playlist import serialize_for_card as serialize_playlist
|
from app.serializers.playlist import serialize_for_card as serialize_playlist
|
||||||
from app.lib.home.recentlyadded import get_recently_added_playlist
|
from app.lib.home.recentlyadded import get_recently_added_playlist
|
||||||
|
|
||||||
from app.store.albums import AlbumStore
|
# from app.store.albums import AlbumStore
|
||||||
from app.store.tracks import TrackStore
|
# from app.store.tracks import TrackStore
|
||||||
from app.store.artists import ArtistStore
|
# from app.store.artists import ArtistStore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_recently_played(limit=7):
|
def get_recently_played(limit=7):
|
||||||
# TODO: Paginate this
|
# TODO: Paginate this
|
||||||
entries = db.get_all()
|
# entries = db.get_all()
|
||||||
|
entries = ScrobbleTable.get_all(0, 200)
|
||||||
items = []
|
items = []
|
||||||
added = set()
|
added = set()
|
||||||
|
|
||||||
@@ -36,7 +43,7 @@ def get_recently_played(limit=7):
|
|||||||
if len(items) >= limit:
|
if len(items) >= limit:
|
||||||
break
|
break
|
||||||
|
|
||||||
entry = TrackLog(*entry)
|
# entry = TrackLog(*entry)
|
||||||
|
|
||||||
if entry.source in added:
|
if entry.source in added:
|
||||||
continue
|
continue
|
||||||
@@ -44,7 +51,8 @@ def get_recently_played(limit=7):
|
|||||||
added.add(entry.source)
|
added.add(entry.source)
|
||||||
|
|
||||||
if entry.type == "album":
|
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:
|
if album is None:
|
||||||
continue
|
continue
|
||||||
@@ -72,7 +80,8 @@ def get_recently_played(limit=7):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if entry.type == "artist":
|
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:
|
if artist is None:
|
||||||
continue
|
continue
|
||||||
@@ -107,13 +116,14 @@ def get_recently_played(limit=7):
|
|||||||
# print(folder)
|
# print(folder)
|
||||||
# folder = os.path.join("/", folder, "")
|
# folder = os.path.join("/", folder, "")
|
||||||
# print(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(
|
items.append(
|
||||||
{
|
{
|
||||||
"type": "folder",
|
"type": "folder",
|
||||||
"item": {
|
"item": {
|
||||||
"path": folder,
|
"path": folder,
|
||||||
"count": count,
|
"count": count[0]["trackcount"],
|
||||||
"help_text": "folder",
|
"help_text": "folder",
|
||||||
"time": timestamp_to_time_passed(entry.timestamp),
|
"time": timestamp_to_time_passed(entry.timestamp),
|
||||||
},
|
},
|
||||||
@@ -122,12 +132,15 @@ def get_recently_played(limit=7):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if entry.type == "playlist":
|
if entry.type == "playlist":
|
||||||
|
continue
|
||||||
is_custom = entry.type_src in [i["name"] for i in custom_playlists]
|
is_custom = entry.type_src in [i["name"] for i in custom_playlists]
|
||||||
# is_recently_added = entry.type_src == "recentlyadded"
|
# is_recently_added = entry.type_src == "recentlyadded"
|
||||||
|
|
||||||
if is_custom:
|
if is_custom:
|
||||||
playlist, _ = next(
|
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]
|
playlist.images = [i["image"] for i in playlist.images]
|
||||||
|
|
||||||
@@ -175,16 +188,17 @@ def get_recently_played(limit=7):
|
|||||||
"type": "favorite_tracks",
|
"type": "favorite_tracks",
|
||||||
"item": {
|
"item": {
|
||||||
"help_text": "playlist",
|
"help_text": "playlist",
|
||||||
"count": fdb.get_track_count(),
|
"count": FavoritesTable.count(),
|
||||||
"time": timestamp_to_time_passed(entry.timestamp),
|
"time": timestamp_to_time_passed(entry.timestamp),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
# track = TrackStore.get_tracks_by_trackhashes([entry.trackhash])[0]
|
||||||
track = TrackStore.get_tracks_by_trackhashes([entry.trackhash])[0]
|
track = TrackTable.get_track_by_trackhash(entry.trackhash)
|
||||||
except IndexError:
|
|
||||||
|
if track is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
track = serialize_track(track)
|
track = serialize_track(track)
|
||||||
@@ -202,10 +216,12 @@ def get_recently_played(limit=7):
|
|||||||
|
|
||||||
|
|
||||||
def get_recently_played_tracks(limit: int):
|
def get_recently_played_tracks(limit: int):
|
||||||
records = db.get_recently_played(start=0, limit=limit)
|
# records = db.get_recently_played(start=0, limit=limit)
|
||||||
last_updated = records[0].timestamp
|
# last_updated = records[0].timestamp
|
||||||
tracks = TrackStore.get_tracks_by_trackhashes([r.trackhash for r in records])
|
# tracks = TrackStore.get_tracks_by_trackhashes([r.trackhash for r in records])
|
||||||
return tracks, last_updated
|
# return tracks, last_updated
|
||||||
|
return TrackTable.get_recently_played(limit)
|
||||||
|
|
||||||
|
|
||||||
def get_recently_played_playlist(limit: int = 100):
|
def get_recently_played_playlist(limit: int = 100):
|
||||||
playlist = Playlist(
|
playlist = Playlist(
|
||||||
@@ -217,13 +233,12 @@ def get_recently_played_playlist(limit: int = 100):
|
|||||||
trackhashes=[],
|
trackhashes=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
tracks, timestamp = get_recently_played_tracks(limit)
|
tracks = get_recently_played_tracks(limit)
|
||||||
|
date = datetime.fromtimestamp(tracks[0].lastplayed)
|
||||||
date = datetime.fromtimestamp(timestamp)
|
|
||||||
playlist.last_updated = date_string_to_time_passed(create_new_date(date))
|
playlist.last_updated = date_string_to_time_passed(create_new_date(date))
|
||||||
|
|
||||||
images = get_first_4_images(tracks=tracks)
|
images = get_first_4_images(tracks=tracks)
|
||||||
playlist.images = images
|
playlist.images = images
|
||||||
playlist.set_count(len(tracks))
|
playlist.set_count(len(tracks))
|
||||||
|
|
||||||
return playlist, tracks
|
return playlist, tracks
|
||||||
|
|||||||
@@ -10,10 +10,8 @@ from typing import Any
|
|||||||
from PIL import Image, ImageSequence
|
from PIL import Image, ImageSequence
|
||||||
|
|
||||||
from app import settings
|
from app import settings
|
||||||
|
from app.db.libdata import AlbumTable, TrackTable
|
||||||
from app.models.track import Track
|
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:
|
def create_thumbnail(image: Any, img_path: str) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -105,7 +103,8 @@ def get_first_4_images(
|
|||||||
tracks: list[Track] = [], trackhashes: list[str] = []
|
tracks: list[Track] = [], trackhashes: list[str] = []
|
||||||
) -> list[dict["str", str]]:
|
) -> list[dict["str", str]]:
|
||||||
if len(trackhashes) > 0:
|
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 = []
|
albums = []
|
||||||
|
|
||||||
@@ -116,11 +115,12 @@ def get_first_4_images(
|
|||||||
if len(albums) == 4:
|
if len(albums) == 4:
|
||||||
break
|
break
|
||||||
|
|
||||||
albums = AlbumStore.get_albums_by_hashes(albums)
|
# albums = AlbumStore.get_albums_by_hashes(albums)
|
||||||
|
albums = AlbumTable.get_albums_by_albumhashes(albums)
|
||||||
images = [
|
images = [
|
||||||
{
|
{
|
||||||
"image": album.image,
|
"image": album.image,
|
||||||
"color": "".join(album.colors),
|
"color": album.color,
|
||||||
}
|
}
|
||||||
for album in albums
|
for album in albums
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import gc
|
||||||
import os
|
import os
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from time import time
|
from time import time
|
||||||
@@ -280,6 +281,7 @@ class IndexEverything:
|
|||||||
# pass
|
# pass
|
||||||
|
|
||||||
CordinateMedia(instance_key=str(time()))
|
CordinateMedia(instance_key=str(time()))
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
@background
|
@background
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Literal
|
from typing import Any, Literal
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -14,6 +14,7 @@ class TrackLog:
|
|||||||
timestamp: int
|
timestamp: int
|
||||||
source: str
|
source: str
|
||||||
userid: int
|
userid: int
|
||||||
|
extra: dict[str, Any]
|
||||||
|
|
||||||
type = "track"
|
type = "track"
|
||||||
type_src = None
|
type_src = None
|
||||||
|
|||||||
Reference in New Issue
Block a user