mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-06 19:25:34 +00:00
add methods to get recently played items
This commit is contained in:
parent
5a420214f2
commit
ddfa7f1b03
@ -1,10 +1,11 @@
|
||||
from flask import Blueprint
|
||||
from flask_restful import Api
|
||||
|
||||
from .recents import RecentlyAdded
|
||||
from .recents import RecentlyAdded, RecentlyPlayed
|
||||
|
||||
api_bp = Blueprint("home", __name__, url_prefix="/home")
|
||||
api = Api(api_bp)
|
||||
|
||||
|
||||
api.add_resource(RecentlyAdded, "/recents/added")
|
||||
api.add_resource(RecentlyPlayed, "/recents/played")
|
||||
|
@ -1,6 +1,7 @@
|
||||
from flask_restful import Resource, reqparse
|
||||
|
||||
from app.lib.home.recents import get_recent_items
|
||||
from app.lib.home.recentlyadded import get_recent_items
|
||||
from app.lib.home.recentlyplayed import get_recently_played
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
|
||||
@ -15,3 +16,11 @@ class RecentlyAdded(Resource):
|
||||
limit = args["limit"]
|
||||
|
||||
return {"items": get_recent_items(cutoff, limit), "cutoff": cutoff}
|
||||
|
||||
|
||||
class RecentlyPlayed(Resource):
|
||||
def get(self):
|
||||
args = parser.parse_args()
|
||||
limit = args["limit"]
|
||||
|
||||
return {"items": get_recently_played(limit)}
|
||||
|
@ -12,9 +12,7 @@ from app import models
|
||||
from app.db.sqlite.playlists import SQLitePlaylistMethods
|
||||
from app.lib import playlistlib
|
||||
from app.lib.albumslib import sort_by_track_no
|
||||
from app.lib.home.recents import get_recent_tracks
|
||||
from app.models.track import Track
|
||||
from app.store.albums import AlbumStore
|
||||
from app.serializers.playlist import serialize_for_card
|
||||
from app.store.tracks import TrackStore
|
||||
from app.utils.dates import create_new_date, date_string_to_time_passed
|
||||
from app.utils.remove_duplicates import remove_duplicates
|
||||
@ -25,47 +23,6 @@ api = Blueprint("playlist", __name__, url_prefix="/")
|
||||
PL = SQLitePlaylistMethods
|
||||
|
||||
|
||||
def duplicate_images(images: list):
|
||||
if len(images) == 1:
|
||||
images *= 4
|
||||
elif len(images) == 2:
|
||||
images += list(reversed(images))
|
||||
elif len(images) == 3:
|
||||
images = images + images[:1]
|
||||
|
||||
return images
|
||||
|
||||
|
||||
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)
|
||||
|
||||
albums = []
|
||||
|
||||
for track in tracks:
|
||||
if track.albumhash not in albums:
|
||||
albums.append(track.albumhash)
|
||||
|
||||
if len(albums) == 4:
|
||||
break
|
||||
|
||||
albums = AlbumStore.get_albums_by_hashes(albums)
|
||||
images = [
|
||||
{
|
||||
"image": album.image,
|
||||
"color": "".join(album.colors),
|
||||
}
|
||||
for album in albums
|
||||
]
|
||||
|
||||
if len(images) == 4:
|
||||
return images
|
||||
|
||||
return duplicate_images(images)
|
||||
|
||||
|
||||
@api.route("/playlists", methods=["GET"])
|
||||
def send_all_playlists():
|
||||
"""
|
||||
@ -78,7 +35,9 @@ def send_all_playlists():
|
||||
|
||||
for playlist in playlists:
|
||||
if not no_images:
|
||||
playlist.images = get_first_4_images(trackhashes=playlist.trackhashes)
|
||||
playlist.images = playlistlib.get_first_4_images(
|
||||
trackhashes=playlist.trackhashes
|
||||
)
|
||||
playlist.images = [img["image"] for img in playlist.images]
|
||||
|
||||
playlist.clear_lists()
|
||||
@ -204,32 +163,28 @@ def get_playlist(playlistid: str):
|
||||
"""
|
||||
Gets a playlist by id, and if it exists, it gets all the tracks in the playlist and returns them.
|
||||
"""
|
||||
no_tracks = request.args.get("no_tracks", False)
|
||||
no_tracks = request.args.get("no_tracks", "false")
|
||||
no_tracks = no_tracks == "true"
|
||||
|
||||
is_recently_added = playlistid == "recentlyadded"
|
||||
|
||||
if not is_recently_added:
|
||||
playlist = PL.get_playlist_by_id(int(playlistid))
|
||||
else:
|
||||
playlist = models.Playlist(
|
||||
id="recentlyadded",
|
||||
name="Recently Added",
|
||||
image=None,
|
||||
last_updated="Now",
|
||||
settings={},
|
||||
trackhashes=[],
|
||||
)
|
||||
if is_recently_added:
|
||||
playlist, tracks = playlistlib.get_recently_added_playlist()
|
||||
|
||||
tracks = remove_duplicates(tracks)
|
||||
duration = sum(t.duration for t in tracks)
|
||||
|
||||
playlist.set_duration(duration)
|
||||
playlist = serialize_for_card(playlist)
|
||||
|
||||
return {"info": playlist, "tracks": tracks}
|
||||
|
||||
playlist = PL.get_playlist_by_id(int(playlistid))
|
||||
|
||||
if playlist is None:
|
||||
return {"msg": "Playlist not found"}, 404
|
||||
|
||||
if is_recently_added:
|
||||
tracks = get_recent_tracks(cutoff_days=14)
|
||||
date = datetime.fromtimestamp(tracks[0].created_date)
|
||||
playlist.last_updated = create_new_date(date)
|
||||
else:
|
||||
tracks = TrackStore.get_tracks_by_trackhashes(list(playlist.trackhashes))
|
||||
tracks = TrackStore.get_tracks_by_trackhashes(list(playlist.trackhashes))
|
||||
|
||||
tracks = remove_duplicates(tracks)
|
||||
duration = sum(t.duration for t in tracks)
|
||||
@ -239,7 +194,7 @@ def get_playlist(playlistid: str):
|
||||
playlist.set_count(len(tracks))
|
||||
|
||||
if not playlist.has_image:
|
||||
playlist.images = get_first_4_images(tracks)
|
||||
playlist.images = playlistlib.get_first_4_images(tracks)
|
||||
|
||||
playlist.clear_lists()
|
||||
|
||||
@ -342,7 +297,7 @@ def remove_playlist_image(playlistid: str):
|
||||
playlist.settings["has_gif"] = False
|
||||
playlist.has_image = False
|
||||
|
||||
playlist.images = get_first_4_images(trackhashes=playlist.trackhashes)
|
||||
playlist.images = playlistlib.get_first_4_images(trackhashes=playlist.trackhashes)
|
||||
playlist.last_updated = date_string_to_time_passed(playlist.last_updated)
|
||||
|
||||
return {"playlist": playlist}, 200
|
||||
@ -463,7 +418,7 @@ def save_item_as_playlist():
|
||||
PL.add_tracks_to_playlist(playlist.id, trackhashes)
|
||||
playlist.set_count(len(trackhashes))
|
||||
|
||||
images = get_first_4_images(trackhashes=trackhashes)
|
||||
images = playlistlib.get_first_4_images(trackhashes=trackhashes)
|
||||
playlist.images = [img["image"] for img in images]
|
||||
|
||||
return {"playlist": playlist}, 201
|
||||
|
@ -24,3 +24,17 @@ class SQLiteTrackLogger:
|
||||
lastrowid = cur.lastrowid
|
||||
|
||||
return lastrowid
|
||||
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
"""
|
||||
Returns all tracks from the database
|
||||
"""
|
||||
|
||||
with SQLiteManager(userdata_db=True) as cur:
|
||||
sql = """SELECT * FROM track_logger ORDER BY timestamp DESC"""
|
||||
|
||||
cur.execute(sql)
|
||||
rows = cur.fetchall()
|
||||
|
||||
return rows
|
||||
|
122
app/lib/home/recentlyplayed.py
Normal file
122
app/lib/home/recentlyplayed.py
Normal file
@ -0,0 +1,122 @@
|
||||
from dataclasses import asdict
|
||||
|
||||
from tomlkit import item
|
||||
|
||||
from app.db.sqlite.logger.tracks import SQLiteTrackLogger as db
|
||||
from app.db.sqlite.playlists import SQLitePlaylistMethods as pdb
|
||||
from app.lib.playlistlib import get_first_4_images, get_recently_added_playlist
|
||||
from app.models.logger import Track as TrackLog
|
||||
from app.serializers.album import album_serializer
|
||||
from app.serializers.artist import serialize_for_card
|
||||
from app.serializers.playlist import serialize_for_card as serialize_playlist
|
||||
from app.serializers.track import serialize_track
|
||||
from app.store.albums import AlbumStore
|
||||
from app.store.artists import ArtistStore
|
||||
from app.store.tracks import TrackStore
|
||||
|
||||
|
||||
def get_recently_played(limit=7):
|
||||
entries = db.get_all()
|
||||
items = []
|
||||
added = set()
|
||||
|
||||
for entry in entries:
|
||||
if len(items) >= limit:
|
||||
break
|
||||
|
||||
entry = TrackLog(*entry)
|
||||
|
||||
if entry.source in added:
|
||||
continue
|
||||
|
||||
added.add(entry.source)
|
||||
|
||||
if entry.type == "album":
|
||||
album = AlbumStore.get_album_by_hash(entry.type_src)
|
||||
|
||||
if album is None:
|
||||
continue
|
||||
|
||||
album = album_serializer(
|
||||
album,
|
||||
{
|
||||
"genres",
|
||||
"date",
|
||||
"count",
|
||||
"duration",
|
||||
"albumartists_hashes",
|
||||
"og_title",
|
||||
},
|
||||
)
|
||||
|
||||
items.append({"type": "album", "item": album})
|
||||
continue
|
||||
|
||||
if entry.type == "artist":
|
||||
artist = ArtistStore.get_artist_by_hash(entry.type_src)
|
||||
|
||||
if artist is None:
|
||||
continue
|
||||
|
||||
artist = serialize_for_card(artist)
|
||||
|
||||
items.append({"type": "artist", "item": artist})
|
||||
|
||||
continue
|
||||
|
||||
if entry.type == "track":
|
||||
try:
|
||||
track = TrackStore.get_tracks_by_trackhashes([entry.trackhash])[0]
|
||||
except IndexError:
|
||||
continue
|
||||
|
||||
track = serialize_track(track)
|
||||
|
||||
items.append({"type": "track", "item": track})
|
||||
|
||||
continue
|
||||
|
||||
if entry.type == "folder":
|
||||
count = len([t for t in TrackStore.tracks if t.folder == entry.type_src])
|
||||
items.append(
|
||||
{
|
||||
"type": "folder",
|
||||
"item": {
|
||||
"path": entry.type_src,
|
||||
"count": count,
|
||||
},
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
if entry.type == "playlist":
|
||||
is_recently_added = entry.type_src == "recentlyadded"
|
||||
|
||||
if is_recently_added:
|
||||
playlist, _ = get_recently_added_playlist()
|
||||
playlist.images = [i["image"] for i in playlist.images]
|
||||
items.append(
|
||||
{
|
||||
"type": "playlist",
|
||||
"item": serialize_playlist(
|
||||
playlist, to_remove={"settings", "duration"}
|
||||
),
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
playlist = pdb.get_playlist_by_id(entry.type_src)
|
||||
if playlist is None:
|
||||
continue
|
||||
|
||||
tracks = TrackStore.get_tracks_by_trackhashes(playlist.trackhashes)
|
||||
playlist.clear_lists()
|
||||
|
||||
if not playlist.has_image:
|
||||
images = get_first_4_images(tracks)
|
||||
images = [i["image"] for i in images]
|
||||
playlist.images = images
|
||||
|
||||
items.append({"type": "playlist", "item": serialize_playlist(playlist)})
|
||||
|
||||
return items
|
@ -4,11 +4,18 @@ This library contains all the functions related to playlists.
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from PIL import Image, ImageSequence
|
||||
|
||||
from app import settings
|
||||
from app.lib.home.recentlyadded import get_recent_tracks
|
||||
from app.models.playlist import Playlist
|
||||
from app.models.track import Track
|
||||
from app.store.albums import AlbumStore
|
||||
from app.store.tracks import TrackStore
|
||||
from app.utils.dates import create_new_date
|
||||
|
||||
|
||||
def create_thumbnail(image: Any, img_path: str) -> str:
|
||||
@ -86,33 +93,63 @@ def save_p_image(
|
||||
return filename
|
||||
|
||||
|
||||
#
|
||||
# class ValidatePlaylistThumbs:
|
||||
# """
|
||||
# Removes all unused images in the images/playlists folder.
|
||||
# """
|
||||
#
|
||||
# def __init__(self) -> None:
|
||||
# images = []
|
||||
# playlists = Get.get_all_playlists()
|
||||
#
|
||||
# log.info("Validating playlist thumbnails")
|
||||
# for playlist in playlists:
|
||||
# if playlist.image:
|
||||
# img_path = playlist.image.split("/")[-1]
|
||||
# thumb_path = playlist.thumb.split("/")[-1]
|
||||
#
|
||||
# images.append(img_path)
|
||||
# images.append(thumb_path)
|
||||
#
|
||||
# p_path = os.path.join(settings.APP_DIR, "images", "playlists")
|
||||
#
|
||||
# for image in os.listdir(p_path):
|
||||
# if image not in images:
|
||||
# os.remove(os.path.join(p_path, image))
|
||||
#
|
||||
# log.info("Validating playlist thumbnails ... ✅")
|
||||
#
|
||||
def duplicate_images(images: list):
|
||||
if len(images) == 1:
|
||||
images *= 4
|
||||
elif len(images) == 2:
|
||||
images += list(reversed(images))
|
||||
elif len(images) == 3:
|
||||
images = images + images[:1]
|
||||
|
||||
return images
|
||||
|
||||
|
||||
# TODO: Fix ValidatePlaylistThumbs
|
||||
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)
|
||||
|
||||
albums = []
|
||||
|
||||
for track in tracks:
|
||||
if track.albumhash not in albums:
|
||||
albums.append(track.albumhash)
|
||||
|
||||
if len(albums) == 4:
|
||||
break
|
||||
|
||||
albums = AlbumStore.get_albums_by_hashes(albums)
|
||||
images = [
|
||||
{
|
||||
"image": album.image,
|
||||
"color": "".join(album.colors),
|
||||
}
|
||||
for album in albums
|
||||
]
|
||||
|
||||
if len(images) == 4:
|
||||
return images
|
||||
|
||||
return duplicate_images(images)
|
||||
|
||||
|
||||
def get_recently_added_playlist(cutoff: int = 14):
|
||||
playlist = Playlist(
|
||||
id="recentlyplayed",
|
||||
name="Recently Added",
|
||||
image=None,
|
||||
last_updated="Now",
|
||||
settings={},
|
||||
trackhashes=[],
|
||||
)
|
||||
|
||||
tracks = get_recent_tracks(cutoff)
|
||||
date = datetime.fromtimestamp(tracks[0].created_date)
|
||||
playlist.last_updated = create_new_date(date)
|
||||
|
||||
images = get_first_4_images(tracks=tracks)
|
||||
playlist.images = images
|
||||
playlist.set_count(len(tracks))
|
||||
|
||||
return playlist, tracks
|
||||
|
@ -1,11 +1,36 @@
|
||||
from attr import dataclass
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
|
||||
@dataclass
|
||||
@dataclass
|
||||
class Track:
|
||||
"""
|
||||
Track play logger model
|
||||
"""
|
||||
|
||||
id: int
|
||||
trackhash: str
|
||||
duration: int
|
||||
timestamp: int
|
||||
timestamp: int
|
||||
source: str
|
||||
userid: int
|
||||
|
||||
type = "track"
|
||||
type_src = None
|
||||
|
||||
def __post_init__(self):
|
||||
prefix_map = {
|
||||
"al:": "album",
|
||||
"ar:": "artist",
|
||||
"pl:": "playlist",
|
||||
"fo:": "folder",
|
||||
}
|
||||
|
||||
for prefix, srctype in prefix_map.items():
|
||||
if self.source.startswith(prefix):
|
||||
try:
|
||||
self.type_src = self.source.split(":", 1)[1]
|
||||
except IndexError:
|
||||
pass
|
||||
self.type = srctype
|
||||
break
|
||||
|
@ -11,13 +11,13 @@ class Playlist:
|
||||
"""Creates playlist objects"""
|
||||
|
||||
id: int
|
||||
image: str
|
||||
image: str | None
|
||||
last_updated: str
|
||||
name: str
|
||||
settings: str | dict
|
||||
trackhashes: str | list[str]
|
||||
|
||||
thumb: str = ""
|
||||
thumb: str | None = ""
|
||||
count: int = 0
|
||||
duration: int = 0
|
||||
has_image: bool = False
|
||||
|
13
app/serializers/playlist.py
Normal file
13
app/serializers/playlist.py
Normal file
@ -0,0 +1,13 @@
|
||||
from dataclasses import asdict
|
||||
from app.models.playlist import Playlist
|
||||
|
||||
|
||||
def serialize_for_card(playlist: Playlist, to_remove=set()):
|
||||
p_dict = asdict(playlist)
|
||||
|
||||
props = {"trackhashes"}.union(to_remove)
|
||||
|
||||
for key in props:
|
||||
p_dict.pop(key, None)
|
||||
|
||||
return p_dict
|
Loading…
x
Reference in New Issue
Block a user