mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
add recently played playlist
This commit is contained in:
@@ -3,4 +3,8 @@
|
||||
<!-- TODO: ELABORATE -->
|
||||
- Auth
|
||||
|
||||
## Improvements
|
||||
- The context menu now doesn't take forever to open up
|
||||
- Merged "Save as Playlist" with "Add to Playlist" > "New Playlist"
|
||||
|
||||
## Development
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# TODO
|
||||
- Migrations:
|
||||
1. Move userdata to new hashing algorithm
|
||||
- Store on the correct user account:
|
||||
- Store (and read) from the correct user account:
|
||||
1. Playlists
|
||||
2. Favorites
|
||||
- Package jsoni and publish on PyPi
|
||||
|
||||
# DONE
|
||||
- Add recently played playlist
|
||||
- Move user track logs to user zero
|
||||
- Move future logs to appropriate user id
|
||||
@@ -2,7 +2,7 @@ from flask_openapi3 import Tag
|
||||
from flask_openapi3 import APIBlueprint
|
||||
|
||||
from app.api.apischemas import GenericLimitSchema
|
||||
from app.lib.home.recentlyadded import get_recent_items
|
||||
from app.lib.home.recentlyadded import get_recently_added_items
|
||||
from app.lib.home.recentlyplayed import get_recently_played
|
||||
|
||||
bp_tag = Tag(name="Home", description="Homepage items")
|
||||
@@ -14,7 +14,7 @@ def get_recently_added(query: GenericLimitSchema):
|
||||
"""
|
||||
Get recently added
|
||||
"""
|
||||
return {"items": get_recent_items(query.limit)}
|
||||
return {"items": get_recently_added_items(query.limit)}
|
||||
|
||||
|
||||
@api.get("/recents/played")
|
||||
|
||||
+26
-12
@@ -15,6 +15,8 @@ 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.recentlyadded import get_recently_added_playlist
|
||||
from app.lib.home.recentlyplayed import get_recently_played_playlist
|
||||
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
|
||||
@@ -174,6 +176,18 @@ class GetPlaylistQuery(BaseModel):
|
||||
no_tracks: bool = Field(False, description="Whether to include tracks")
|
||||
|
||||
|
||||
def format_custom_playlist(playlist: models.Playlist, tracks: list[models.Track]):
|
||||
duration = sum(t.duration for t in tracks)
|
||||
|
||||
playlist.set_duration(duration)
|
||||
playlist = serialize_for_card(playlist)
|
||||
|
||||
return {
|
||||
"info": playlist,
|
||||
"tracks": tracks,
|
||||
}
|
||||
|
||||
|
||||
@api.get("/<playlistid>")
|
||||
def get_playlist(path: PlaylistIDPath, query: GetPlaylistQuery):
|
||||
"""
|
||||
@@ -182,18 +196,18 @@ def get_playlist(path: PlaylistIDPath, query: GetPlaylistQuery):
|
||||
no_tracks = query.no_tracks
|
||||
playlistid = path.playlistid
|
||||
|
||||
is_recently_added = playlistid == "recentlyadded"
|
||||
custom_playlists = [
|
||||
{"name": "recentlyadded", "handler": get_recently_added_playlist},
|
||||
{"name": "recentlyplayed", "handler": get_recently_played_playlist},
|
||||
]
|
||||
is_custom = playlistid in {p["name"] for p in custom_playlists}
|
||||
|
||||
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}
|
||||
if is_custom:
|
||||
handler = next(
|
||||
p["handler"] for p in custom_playlists if p["name"] == playlistid
|
||||
)
|
||||
playlist, tracks = handler()
|
||||
return format_custom_playlist(playlist, tracks)
|
||||
|
||||
playlist = PL.get_playlist_by_id(int(playlistid))
|
||||
|
||||
@@ -247,7 +261,7 @@ def update_playlist_info(path: PlaylistIDPath, form: UpdatePlaylistForm):
|
||||
settings["has_gif"] = False
|
||||
|
||||
playlist = {
|
||||
"id": playlistid,
|
||||
"id": int(playlistid),
|
||||
"image": db_playlist.image,
|
||||
"last_updated": create_new_date(),
|
||||
"name": str(form.name).strip(),
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from app.db.sqlite.utils import SQLiteManager
|
||||
from app.models.logger import TrackLog as TrackLog
|
||||
|
||||
|
||||
class SQLiteTrackLogger:
|
||||
@classmethod
|
||||
def insert_track(cls, trackhash: str, duration: int, source: str, timestamp: int, userid: int):
|
||||
"""
|
||||
Inserts a track into the database
|
||||
Inserts a track play record into the database
|
||||
"""
|
||||
|
||||
with SQLiteManager(userdata_db=True) as cur:
|
||||
@@ -26,7 +27,7 @@ class SQLiteTrackLogger:
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
"""
|
||||
Returns all tracks from the database
|
||||
Returns all track play records from the database
|
||||
"""
|
||||
|
||||
with SQLiteManager(userdata_db=True) as cur:
|
||||
@@ -36,3 +37,17 @@ class SQLiteTrackLogger:
|
||||
rows = cur.fetchall()
|
||||
|
||||
return rows
|
||||
|
||||
@classmethod
|
||||
def get_recently_played(cls, start: int = 0, limit: int = 100):
|
||||
"""
|
||||
Returns a list of recently played tracks
|
||||
"""
|
||||
|
||||
with SQLiteManager(userdata_db=True) as cur:
|
||||
sql = """SELECT * FROM track_logger ORDER BY timestamp DESC LIMIT ?,?"""
|
||||
|
||||
cur.execute(sql, (start, limit))
|
||||
rows = cur.fetchall()
|
||||
|
||||
return [TrackLog(*row) for row in rows]
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from flask import g
|
||||
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
|
||||
@@ -12,7 +13,7 @@ from app.serializers.artist import serialize_for_card
|
||||
|
||||
from itertools import groupby
|
||||
|
||||
from app.utils.dates import timestamp_to_time_passed
|
||||
from app.utils.dates import create_new_date, date_string_to_time_passed, timestamp_to_time_passed
|
||||
|
||||
older_albums = set()
|
||||
older_artists = set()
|
||||
@@ -191,7 +192,7 @@ def group_track_by_folders(tracks: Track):
|
||||
return sorted(groups, key=lambda group: group["time"], reverse=True)
|
||||
|
||||
|
||||
def get_recent_items(limit: int = 7):
|
||||
def get_recently_added_items(limit: int = 7):
|
||||
tracks = sorted(TrackStore.tracks, key=lambda t: t.created_date)
|
||||
groups = group_track_by_folders(tracks)
|
||||
|
||||
@@ -216,6 +217,33 @@ def get_recent_items(limit: int = 7):
|
||||
return recent_items
|
||||
|
||||
|
||||
def get_recent_tracks(limit: int):
|
||||
|
||||
def get_recently_added_playlist(limit: int = 100):
|
||||
playlist = Playlist(
|
||||
id="recentlyadded",
|
||||
name="Recently Added",
|
||||
image=None,
|
||||
last_updated="Now",
|
||||
settings={},
|
||||
trackhashes=[],
|
||||
)
|
||||
|
||||
tracks = get_recently_added_tracks(limit=limit)
|
||||
|
||||
try:
|
||||
# Create date to show as last updated
|
||||
date = datetime.fromtimestamp(tracks[0].created_date)
|
||||
except IndexError:
|
||||
return playlist, []
|
||||
|
||||
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
|
||||
|
||||
def get_recently_added_tracks(limit: int):
|
||||
tracks = sorted(TrackStore.tracks, key=lambda t: t.created_date, reverse=True)
|
||||
return tracks[:limit]
|
||||
@@ -1,27 +1,37 @@
|
||||
from datetime import datetime
|
||||
import os
|
||||
from app.models.logger import Track as TrackLog
|
||||
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.models.playlist import Playlist
|
||||
from app.serializers.track import serialize_track
|
||||
from app.serializers.album import album_serializer
|
||||
from app.utils.dates import timestamp_to_time_passed
|
||||
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.serializers.artist import serialize_for_card
|
||||
from app.serializers.playlist import serialize_for_card as serialize_playlist
|
||||
from app.lib.playlistlib import get_first_4_images, get_recently_added_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
|
||||
|
||||
|
||||
|
||||
def get_recently_played(limit=7):
|
||||
# TODO: Paginate this
|
||||
entries = db.get_all()
|
||||
items = []
|
||||
added = set()
|
||||
|
||||
custom_playlists = [
|
||||
{"name": "recentlyadded", "handler": get_recently_added_playlist},
|
||||
{"name": "recentlyplayed", "handler": get_recently_played_playlist},
|
||||
]
|
||||
|
||||
for entry in entries:
|
||||
if len(items) >= limit:
|
||||
break
|
||||
@@ -112,10 +122,13 @@ def get_recently_played(limit=7):
|
||||
continue
|
||||
|
||||
if entry.type == "playlist":
|
||||
is_recently_added = entry.type_src == "recentlyadded"
|
||||
is_custom = entry.type_src in [i["name"] for i in custom_playlists]
|
||||
# is_recently_added = entry.type_src == "recentlyadded"
|
||||
|
||||
if is_recently_added:
|
||||
playlist, _ = get_recently_added_playlist()
|
||||
if is_custom:
|
||||
playlist, _ = next(
|
||||
i["handler"]() for i in custom_playlists if i["name"] == entry.type_src
|
||||
)
|
||||
playlist.images = [i["image"] for i in playlist.images]
|
||||
|
||||
playlist = serialize_playlist(
|
||||
@@ -186,3 +199,31 @@ def get_recently_played(limit=7):
|
||||
)
|
||||
|
||||
return items
|
||||
|
||||
|
||||
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
|
||||
|
||||
def get_recently_played_playlist(limit: int = 100):
|
||||
playlist = Playlist(
|
||||
id="recentlyplayed",
|
||||
name="Recently Played",
|
||||
image=None,
|
||||
last_updated="Now",
|
||||
settings={},
|
||||
trackhashes=[],
|
||||
)
|
||||
|
||||
tracks, timestamp = get_recently_played_tracks(limit)
|
||||
|
||||
date = datetime.fromtimestamp(timestamp)
|
||||
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
|
||||
@@ -5,18 +5,14 @@ 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, date_string_to_time_passed
|
||||
|
||||
|
||||
def create_thumbnail(image: Any, img_path: str) -> str:
|
||||
@@ -133,30 +129,3 @@ def get_first_4_images(
|
||||
return images
|
||||
|
||||
return duplicate_images(images)
|
||||
|
||||
|
||||
def get_recently_added_playlist(limit: int = 100):
|
||||
playlist = Playlist(
|
||||
id="recentlyadded",
|
||||
name="Recently Added",
|
||||
image=None,
|
||||
last_updated="Now",
|
||||
settings={},
|
||||
trackhashes=[],
|
||||
)
|
||||
|
||||
tracks = get_recent_tracks(limit=limit)
|
||||
|
||||
try:
|
||||
# Create date to show as last updated
|
||||
date = datetime.fromtimestamp(tracks[0].created_date)
|
||||
except IndexError:
|
||||
return playlist, []
|
||||
|
||||
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
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import Literal
|
||||
|
||||
|
||||
@dataclass
|
||||
class Track:
|
||||
class TrackLog:
|
||||
"""
|
||||
Track play logger model
|
||||
"""
|
||||
|
||||
+10
-2
@@ -129,10 +129,18 @@ class TrackStore:
|
||||
"""
|
||||
Returns a list of tracks by their hashes.
|
||||
"""
|
||||
hash_set = set(trackhashes)
|
||||
set_len = len(hash_set)
|
||||
|
||||
trackhashes = " ".join(trackhashes)
|
||||
tracks = [track for track in cls.tracks if track.trackhash in trackhashes]
|
||||
tracks = []
|
||||
for track in cls.tracks:
|
||||
if track.trackhash in hash_set:
|
||||
tracks.append(track)
|
||||
|
||||
if len(tracks) == set_len:
|
||||
break
|
||||
|
||||
# sort the tracks in the order of the given trackhashes
|
||||
tracks.sort(key=lambda t: trackhashes.index(t.trackhash))
|
||||
return tracks
|
||||
|
||||
|
||||
Reference in New Issue
Block a user