attach favorites to logged in user

This commit is contained in:
cwilvx
2024-05-25 15:12:44 +03:00
parent 300c8eb30b
commit 0b8a5e92f5
14 changed files with 128 additions and 38 deletions
+1
View File
@@ -4,6 +4,7 @@ Contains all the album routes.
import random
from flask_jwt_extended import current_user
from pydantic import Field
from flask_openapi3 import Tag
from flask_openapi3 import APIBlueprint
+1
View File
@@ -6,6 +6,7 @@ import math
import random
from datetime import datetime
from flask_jwt_extended import current_user
from flask_openapi3 import APIBlueprint, Tag
from pydantic import Field
from app.api.apischemas import AlbumLimitSchema, ArtistHashSchema, ArtistLimitSchema, TrackLimitSchema
+9 -5
View File
@@ -1,5 +1,6 @@
from typing import List, TypeVar
from flask_jwt_extended import current_user
from flask_openapi3 import Tag
from flask_openapi3 import APIBlueprint
from pydantic import BaseModel, Field
@@ -10,7 +11,7 @@ from app.settings import Defaults
from app.utils.bisection import use_bisection
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.serializers.track import serialize_track, serialize_tracks
from app.serializers.artist import serialize_for_card as serialize_artist
from app.serializers.artist import serialize_for_card as serialize_artist, serialize_for_cards
from app.serializers.album import serialize_for_card, serialize_for_card_many
from app.store.albums import AlbumStore
@@ -98,7 +99,9 @@ def get_favorite_tracks(query: GenericLimitSchema):
Get favorite tracks
"""
limit = query.limit
tracks = favdb.get_fav_tracks()
userid = current_user['id']
tracks = favdb.get_fav_tracks(userid)
trackhashes = [t[1] for t in tracks]
trackhashes.reverse()
src_tracks = sorted(TrackStore.tracks, key=lambda x: x.trackhash)
@@ -118,6 +121,7 @@ def get_favorite_artists(query: GenericLimitSchema):
Get favorite artists
"""
limit = query.limit
artists = favdb.get_fav_artists()
artisthashes = [a[1] for a in artists]
artisthashes.reverse()
@@ -266,9 +270,9 @@ def get_all_favorites(query: GetAllFavoritesQuery):
return {
"recents": recents[:album_limit],
"tracks": tracks[:track_limit],
"albums": albums[:album_limit],
"artists": artists[:artist_limit],
"tracks": serialize_tracks(tracks[:track_limit]),
"albums": serialize_for_card_many(albums[:album_limit]),
"artists": serialize_for_cards(artists[:artist_limit]),
"count": count,
}
+1
View File
@@ -1,3 +1,4 @@
from flask_jwt_extended import current_user
from flask_openapi3 import Tag
from flask_openapi3 import APIBlueprint
+37 -19
View File
@@ -1,4 +1,6 @@
from datetime import datetime
from flask_jwt_extended import current_user
from app.models import FavType
from .utils import SQLiteManager
@@ -11,12 +13,14 @@ class SQLiteFavoriteMethods:
"""
Checks if an item is favorited.
"""
sql = """SELECT * FROM favorites WHERE hash = ? AND type = ?"""
userid = current_user["id"]
sql = """SELECT * FROM favorites WHERE hash = ? AND type = ? AND userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (itemhash, fav_type))
items = cur.fetchall()
cur.execute(sql, (itemhash, fav_type, userid))
item = cur.fetchone()
cur.close()
return len(items) > 0
return item is not None
@classmethod
def insert_one_favorite(cls, fav_type: str, fav_hash: str):
@@ -27,10 +31,11 @@ class SQLiteFavoriteMethods:
if cls.check_is_favorite(fav_hash, fav_type):
return
sql = """INSERT INTO favorites(type, hash, timestamp) VALUES(?,?,?)"""
current_timestamp = datetime.now().timestamp()
sql = """INSERT INTO favorites(type, hash, timestamp, userid) VALUES(?,?,?,?)"""
current_timestamp = int(datetime.now().timestamp())
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (fav_type, fav_hash, current_timestamp))
userid = current_user["id"]
cur.execute(sql, (fav_type, fav_hash, current_timestamp, userid))
cur.close()
@classmethod
@@ -38,55 +43,67 @@ class SQLiteFavoriteMethods:
"""
Returns a list of all favorites.
"""
sql = """SELECT * FROM favorites"""
sql = """SELECT * FROM favorites WHERE userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql)
userid = current_user["id"]
cur.execute(sql, (userid,))
favs = cur.fetchall()
cur.close()
return [fav for fav in favs if fav[1] != ""]
@classmethod
def get_favorites(cls, fav_type: str) -> list[tuple]:
def get_favorites(cls, fav_type: str, userid: int = None) -> list[tuple]:
"""
Returns a list of favorite tracks.
If userid is None, all favorites are returned.
"""
sql = """SELECT * FROM favorites WHERE type = ?"""
params = (fav_type,)
if not userid:
sql += " AND userid = ?"
params = (fav_type, userid)
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (fav_type,))
cur.execute(sql, params)
all_favs = cur.fetchall()
cur.close()
return all_favs
@classmethod
def get_fav_tracks(cls) -> list[tuple]:
def get_fav_tracks(cls, userid: int = None) -> list[tuple]:
"""
Returns a list of favorite tracks.
"""
return cls.get_favorites(FavType.track)
return cls.get_favorites(FavType.track, userid)
@classmethod
def get_fav_albums(cls) -> list[tuple]:
"""
Returns a list of favorite albums.
"""
return cls.get_favorites(FavType.album)
userid = current_user["id"]
return cls.get_favorites(FavType.album, userid)
@classmethod
def get_fav_artists(cls) -> list[tuple]:
"""
Returns a list of favorite artists.
"""
return cls.get_favorites(FavType.artist)
userid = current_user["id"]
return cls.get_favorites(FavType.artist, userid)
@classmethod
def delete_favorite(cls, fav_type: str, fav_hash: str):
"""
Deletes a favorite from the database.
"""
sql = """DELETE FROM favorites WHERE hash = ? AND type = ?"""
sql = """DELETE FROM favorites WHERE hash = ? AND type = ? AND userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (fav_hash, fav_type))
userid = current_user["id"]
cur.execute(sql, (fav_hash, fav_type, userid))
cur.close()
@classmethod
@@ -94,10 +111,11 @@ class SQLiteFavoriteMethods:
"""
Returns the number of favorite tracks.
"""
sql = """SELECT COUNT(*) FROM favorites WHERE type = ?"""
sql = """SELECT COUNT(*) FROM favorites WHERE type = ? AND userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (FavType.track,))
userid = current_user["id"]
cur.execute(sql, (FavType.track, userid))
count = cur.fetchone()[0]
cur.close()
return count
+3 -1
View File
@@ -16,7 +16,9 @@ CREATE TABLE IF NOT EXISTS favorites (
id integer PRIMARY KEY,
hash text not null,
type text not null,
timestamp integer not null default 0
timestamp integer not null default 0,
userid integer not null,
foreign key (userid) references users(id) on delete cascade
);
CREATE TABLE IF NOT EXISTS settings (
+1
View File
@@ -1,6 +1,7 @@
"""
This library contains all the functions related to the search functionality.
"""
from typing import Any, Generator, List, TypeVar
from rapidfuzz import process, utils
+2 -1
View File
@@ -58,7 +58,8 @@ def apply_migrations():
try:
migration.migrate()
log.info("Applied migration: %s", migration.__name__)
except:
except Exception as e:
log.error("Failed to run migration: %s", migration.__name__)
log.error(e)
MigrationManager.set_index(len(all_migrations))
+22
View File
@@ -73,3 +73,25 @@ class _3MoveScrobbleToUserId1(Migration):
with SQLiteManager(userdata_db=True) as cur:
cur.execute("UPDATE track_logger SET userid = 1 WHERE userid = 0")
cur.close()
class _4AddUserIdToFavoritesTable(Migration):
"""
Adds a userid column to the favorites table.
"""
@staticmethod
def migrate():
# check if userid column exists
exists_sql = "select count(*) from pragma_table_info('favorites') where name = 'userid'"
sql = "ALTER TABLE favorites ADD userid INTEGER NOT NULL DEFAULT 1 REFERENCES users(id) ON DELETE CASCADE"
with SQLiteManager(userdata_db=True) as cur:
data = cur.execute(exists_sql)
data = data.fetchone()
if data[0] == 1:
return# INFO: column already exists
cur.executescript(sql)
+17 -3
View File
@@ -1,7 +1,10 @@
from dataclasses import dataclass
from dataclasses import dataclass, field
import os
from pathlib import Path
from flask_jwt_extended import current_user
from app.settings import SessionVarKeys, get_flag
from app.utils.hashing import create_hash
from app.utils.parsers import (
@@ -40,11 +43,22 @@ class Track:
image: str = ""
artist_hashes: str = ""
is_favorite: bool = False
fav_userids: list = field(default_factory=list)
"""
A string of user ids separated by commas.
"""
# is_favorite: bool = False
@property
def is_favorite(self):
return current_user['id'] in self.fav_userids
# temporary attributes
_pos: int = 0 # for sorting tracks by disc and track number
_ati: str = "" # (album track identifier) for removing duplicates when merging album versions
_ati: str = (
"" # (album track identifier) for removing duplicates when merging album versions
)
og_title: str = ""
og_album: str = ""
+4
View File
@@ -5,6 +5,9 @@ from app.models.track import Track
def serialize_track(track: Track, to_remove: set = {}, remove_disc=True) -> dict:
album_dict = asdict(track)
# is_favorite @property is not included in asdict
album_dict["is_favorite"] = track.is_favorite
props = {
"date",
"genre",
@@ -16,6 +19,7 @@ def serialize_track(track: Track, to_remove: set = {}, remove_disc=True) -> dict
"track",
"artist_hashes",
"created_date",
"fav_userids",
}.union(to_remove)
if not remove_disc:
+26 -6
View File
@@ -1,5 +1,6 @@
# from tqdm import tqdm
from flask_jwt_extended import current_user
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.sqlite.tracks import SQLiteTrackMethods as trackdb
from app.models import Track
@@ -25,15 +26,32 @@ class TrackStore:
cls.tracks = CustomList(trackdb.get_all_tracks())
fav_hashes = favdb.get_fav_tracks()
fav_hashes = " ".join([t[1] for t in fav_hashes])
favs = favdb.get_fav_tracks()
records = dict()
for fav in favs:
if fav[1] not in records:
# if trackhash not in dict, add it
# and set the value to a set containing the userid
records[fav[1]] = {fav[4]}
# if trackhash is in dict, add the userid to the set
records[fav[1]].add(fav[4])
for track in cls.tracks:
if instance_key != TRACKS_LOAD_KEY:
return
if track.trackhash in fav_hashes:
track.is_favorite = True
try:
track.fav_userids = list(records[track.trackhash])
except KeyError:
track.fav_userids = []
# if track.trackhash in fav_hashes:
# fav = [t for t in favs if t["hash"] == track.trackhash][0]
# print(fav)
# track.favorite_data = [i["userid"] for i in fav]
print("Done!")
@@ -99,7 +117,8 @@ class TrackStore:
for track in cls.tracks:
if track.trackhash == trackhash:
track.is_favorite = True
if current_user["id"] not in track.fav_userids:
track.fav_userids.append(current_user["id"])
@classmethod
def remove_track_from_fav(cls, trackhash: str):
@@ -109,7 +128,8 @@ class TrackStore:
for track in cls.tracks:
if track.trackhash == trackhash:
track.is_favorite = False
if current_user["id"] in track.fav_userids:
track.fav_userids.remove(current_user["id"])
@classmethod
def append_track_artists(