mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-06 03:05:35 +00:00
add routes for getting recently added items
This commit is contained in:
parent
7749b4fc3c
commit
b03e721ee5
@ -21,6 +21,7 @@ from app.api import (
|
|||||||
lyrics,
|
lyrics,
|
||||||
plugins,
|
plugins,
|
||||||
logger,
|
logger,
|
||||||
|
home,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -56,4 +57,7 @@ def create_api():
|
|||||||
# Logger
|
# Logger
|
||||||
app.register_blueprint(logger.api_bp)
|
app.register_blueprint(logger.api_bp)
|
||||||
|
|
||||||
|
# Home
|
||||||
|
app.register_blueprint(home.api_bp)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
10
app/api/home/__init__.py
Normal file
10
app/api/home/__init__.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from flask import Blueprint
|
||||||
|
from flask_restful import Api
|
||||||
|
|
||||||
|
from .recents import RecentlyAdded
|
||||||
|
|
||||||
|
api_bp = Blueprint("home", __name__, url_prefix="/home")
|
||||||
|
api = Api(api_bp)
|
||||||
|
|
||||||
|
|
||||||
|
api.add_resource(RecentlyAdded, "/recents/added")
|
18
app/api/home/recents.py
Normal file
18
app/api/home/recents.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from flask_restful import Resource, reqparse
|
||||||
|
|
||||||
|
from app.lib.home.recents import get_recent_items
|
||||||
|
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
|
||||||
|
parser.add_argument("limit", type=int, required=False, default=7, location="args")
|
||||||
|
|
||||||
|
|
||||||
|
class RecentlyAdded(Resource):
|
||||||
|
def get(self):
|
||||||
|
cutoff = 14
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
limit = args["limit"]
|
||||||
|
print(limit)
|
||||||
|
|
||||||
|
return {"items": get_recent_items(cutoff)[:limit], "cutoff": cutoff}
|
@ -1,4 +1,4 @@
|
|||||||
from flask import Blueprint, request
|
from flask import Blueprint
|
||||||
from flask_restful import Api
|
from flask_restful import Api
|
||||||
|
|
||||||
from app.api.logger.tracks import LogTrack
|
from app.api.logger.tracks import LogTrack
|
||||||
|
150
app/lib/home/recents.py
Normal file
150
app/lib/home/recents.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from flask import g
|
||||||
|
from app.models.track import Track
|
||||||
|
from app.store.tracks import TrackStore
|
||||||
|
from app.store.albums import AlbumStore
|
||||||
|
from app.store.artists import ArtistStore
|
||||||
|
|
||||||
|
from app.serializers.track import serialize_track
|
||||||
|
from app.serializers.album import album_serializer
|
||||||
|
from app.serializers.artist import serialize_for_card
|
||||||
|
|
||||||
|
from itertools import groupby
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|
||||||
|
def timestamp_from_days_ago(days_ago):
|
||||||
|
current_datetime = datetime.now()
|
||||||
|
delta = timedelta(days=days_ago)
|
||||||
|
past_timestamp = current_datetime - delta
|
||||||
|
|
||||||
|
past_timestamp = int(past_timestamp.timestamp())
|
||||||
|
|
||||||
|
return past_timestamp
|
||||||
|
|
||||||
|
|
||||||
|
group_type = tuple[str, list[Track]]
|
||||||
|
|
||||||
|
|
||||||
|
def calc_based_on_percent(items: list[str], total: int):
|
||||||
|
"""
|
||||||
|
Checks if items is more than 85% of total items. Returns a boolean and the most common item.
|
||||||
|
"""
|
||||||
|
most_common = max(items, key=items.count)
|
||||||
|
most_common_count = items.count(most_common)
|
||||||
|
|
||||||
|
return most_common_count / total >= 0.85, most_common
|
||||||
|
|
||||||
|
|
||||||
|
def check_is_album_folder(group: group_type):
|
||||||
|
key, group_ = group
|
||||||
|
albumhashes = [t.albumhash for t in group_]
|
||||||
|
return calc_based_on_percent(albumhashes, len(group_))
|
||||||
|
|
||||||
|
|
||||||
|
def check_is_artist_folder(group: group_type):
|
||||||
|
key, group_ = group
|
||||||
|
artisthashes = "-".join(t.artist_hashes for t in group_).split("-")
|
||||||
|
return calc_based_on_percent(artisthashes, len(group_))
|
||||||
|
|
||||||
|
|
||||||
|
def check_is_track_folder(group: group_type):
|
||||||
|
key, group_ = group
|
||||||
|
|
||||||
|
# is more of a playlist
|
||||||
|
if len(group_) >= 3:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"type": "track",
|
||||||
|
"item": serialize_track(t, to_remove={"created_date"}),
|
||||||
|
}
|
||||||
|
for t in group_
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def check_folder_type(group_: group_type) -> str:
|
||||||
|
# check if all tracks in group have the same albumhash
|
||||||
|
# if so, return "album"
|
||||||
|
key, tracks = group_
|
||||||
|
|
||||||
|
if len(tracks) == 1:
|
||||||
|
return {
|
||||||
|
"type": "track",
|
||||||
|
"item": serialize_track(tracks[0], to_remove={"created_date"}),
|
||||||
|
}
|
||||||
|
|
||||||
|
is_album, albumhash = check_is_album_folder(group_)
|
||||||
|
if is_album:
|
||||||
|
album = AlbumStore.get_album_by_hash(albumhash)
|
||||||
|
return {
|
||||||
|
"type": "album",
|
||||||
|
"item": album_serializer(
|
||||||
|
album,
|
||||||
|
to_remove={
|
||||||
|
"genres",
|
||||||
|
"og_title",
|
||||||
|
"date",
|
||||||
|
"duration",
|
||||||
|
"count",
|
||||||
|
"albumartists_hashes",
|
||||||
|
"base_title",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
is_artist, artisthash = check_is_artist_folder(group_)
|
||||||
|
if is_artist:
|
||||||
|
artist = ArtistStore.get_artist_by_hash(artisthash)
|
||||||
|
artist = serialize_for_card(artist)
|
||||||
|
artist["trackcount"] = len(tracks)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"type": "artist",
|
||||||
|
"item": artist,
|
||||||
|
}
|
||||||
|
|
||||||
|
is_track_folder = check_is_track_folder(group_)
|
||||||
|
return (
|
||||||
|
is_track_folder
|
||||||
|
if is_track_folder
|
||||||
|
else {
|
||||||
|
"type": "folder",
|
||||||
|
"item": {
|
||||||
|
"path": key,
|
||||||
|
"count": len(tracks),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def group_track_by_folders(tracks: Track) -> (str, list[Track]):
|
||||||
|
tracks = sorted(tracks, key=lambda t: t.folder)
|
||||||
|
groups = groupby(tracks, lambda t: t.folder)
|
||||||
|
groups = ((k, list(g)) for k, g in groups)
|
||||||
|
|
||||||
|
# sort groups by last modified date
|
||||||
|
return sorted(groups, key=lambda g: os.path.getctime(g[0]), reverse=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_recent_items(cutoff_days: int):
|
||||||
|
timestamp = timestamp_from_days_ago(cutoff_days)
|
||||||
|
|
||||||
|
tracks = (t for t in TrackStore.tracks if t.created_date > timestamp)
|
||||||
|
tracks = sorted(tracks, key=lambda t: t.created_date)
|
||||||
|
|
||||||
|
groups = group_track_by_folders(tracks)
|
||||||
|
|
||||||
|
recent_items = []
|
||||||
|
|
||||||
|
for group in groups:
|
||||||
|
item = check_folder_type(group)
|
||||||
|
|
||||||
|
if item not in recent_items:
|
||||||
|
recent_items.append(item) if type(item) == dict else recent_items.extend(
|
||||||
|
item
|
||||||
|
)
|
||||||
|
|
||||||
|
return recent_items
|
@ -1,4 +1,5 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from app.settings import SessionVarKeys, get_flag
|
from app.settings import SessionVarKeys, get_flag
|
||||||
from app.utils.hashing import create_hash
|
from app.utils.hashing import create_hash
|
||||||
@ -47,6 +48,10 @@ class Track:
|
|||||||
|
|
||||||
og_title: str = ""
|
og_title: str = ""
|
||||||
og_album: str = ""
|
og_album: str = ""
|
||||||
|
created_date: float = 0.0
|
||||||
|
|
||||||
|
def set_created_date(self):
|
||||||
|
self.created_date = Path(self.filepath).stat().st_ctime
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.og_title = self.title
|
self.og_title = self.title
|
||||||
@ -117,6 +122,7 @@ class Track:
|
|||||||
self.genre = [g.strip() for g in self.genre]
|
self.genre = [g.strip() for g in self.genre]
|
||||||
|
|
||||||
self.recreate_hash()
|
self.recreate_hash()
|
||||||
|
self.set_created_date()
|
||||||
|
|
||||||
def recreate_hash(self):
|
def recreate_hash(self):
|
||||||
"""
|
"""
|
||||||
|
@ -3,7 +3,10 @@ from app.models import Album
|
|||||||
|
|
||||||
|
|
||||||
def album_serializer(album: Album, to_remove: set[str]) -> dict:
|
def album_serializer(album: Album, to_remove: set[str]) -> dict:
|
||||||
album_dict = asdict(album)
|
try:
|
||||||
|
album_dict = asdict(album)
|
||||||
|
except TypeError:
|
||||||
|
return {}
|
||||||
|
|
||||||
to_remove.update(key for key in album_dict.keys() if key.startswith("is_"))
|
to_remove.update(key for key in album_dict.keys() if key.startswith("is_"))
|
||||||
for key in to_remove:
|
for key in to_remove:
|
||||||
|
@ -4,7 +4,10 @@ from app.models.artist import Artist
|
|||||||
|
|
||||||
|
|
||||||
def serialize_for_card(artist: Artist):
|
def serialize_for_card(artist: Artist):
|
||||||
artist_dict = asdict(artist)
|
try:
|
||||||
|
artist_dict = asdict(artist)
|
||||||
|
except TypeError:
|
||||||
|
return {}
|
||||||
|
|
||||||
props_to_remove = {
|
props_to_remove = {
|
||||||
"is_favorite",
|
"is_favorite",
|
||||||
|
@ -8,7 +8,7 @@ def split_artists(src: str):
|
|||||||
"""
|
"""
|
||||||
Splits a string of artists into a list of artists.
|
Splits a string of artists into a list of artists.
|
||||||
"""
|
"""
|
||||||
separators: set = get_flag(SessionVarKeys.ARTIST_SEPARATORS)
|
separators: set = get_flag(SessionVarKeys.ARTIST_SEPARATORS)
|
||||||
for sep in separators:
|
for sep in separators:
|
||||||
src = src.replace(sep, ",")
|
src = src.replace(sep, ",")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user