add methods to get recently played items

This commit is contained in:
mungai-njoroge 2023-12-03 20:35:13 +03:00
parent 5a420214f2
commit ddfa7f1b03
10 changed files with 277 additions and 101 deletions

View File

@ -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")

View File

@ -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)}

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View 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