add route to get all tracks in path

+ add routes to save album and artist as a playlist
This commit is contained in:
mungai-njoroge 2023-08-04 13:40:48 +03:00
parent efb6aae927
commit 655fd8bc22
7 changed files with 169 additions and 38 deletions

View File

@ -83,7 +83,7 @@ def get_album_tracks_and_info():
album.is_favorite = check_is_fav(albumhash, FavType.album) album.is_favorite = check_is_fav(albumhash, FavType.album)
return { return {
"tracks": [track_serializer(t, retain_disc=True) for t in tracks], "tracks": [track_serializer(t, remove_disc=False) for t in tracks],
"info": album, "info": album,
} }
@ -210,3 +210,5 @@ def get_similar_albums():
pass pass
return {"albums": [serialize_for_card(a) for a in albums[:limit]]} return {"albums": [serialize_for_card(a) for a in albums[:limit]]}

View File

@ -1,22 +1,21 @@
""" """
Contains all the artist(s) routes. Contains all the artist(s) routes.
""" """
from collections import deque
import random import random
from collections import deque
from flask import Blueprint, request from flask import Blueprint, request
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as fmdb from app.db.sqlite.lastfm.similar_artists import \
SQLiteLastFMSimilarArtists as fmdb
from app.models import Album, FavType, Track from app.models import Album, FavType, Track
from app.serializers.album import serialize_for_card_many from app.serializers.album import serialize_for_card_many
from app.serializers.track import serialize_tracks from app.serializers.track import serialize_tracks
from app.utils.remove_duplicates import remove_duplicates
from app.store.albums import AlbumStore from app.store.albums import AlbumStore
from app.store.tracks import TrackStore
from app.store.artists import ArtistStore from app.store.artists import ArtistStore
from app.store.tracks import TrackStore
from app.utils.remove_duplicates import remove_duplicates
api = Blueprint("artist", __name__, url_prefix="/") api = Blueprint("artist", __name__, url_prefix="/")
@ -159,7 +158,7 @@ def add_albums_to_cache(artisthash: str):
""" """
Fetches albums and adds them to the cache. Fetches albums and adds them to the cache.
""" """
tracks = TrackStore.get_tracks_by_artist(artisthash) tracks = TrackStore.get_tracks_by_artisthash(artisthash)
if len(tracks) == 0: if len(tracks) == 0:
return False return False
@ -197,7 +196,7 @@ def get_artist(artisthash: str):
if tracks_cached: if tracks_cached:
tracks = ArtistsCache.get_tracks(artisthash) tracks = ArtistsCache.get_tracks(artisthash)
else: else:
tracks = TrackStore.get_tracks_by_artist(artisthash) tracks = TrackStore.get_tracks_by_artisthash(artisthash)
albumhashes = set(t.albumhash for t in tracks) albumhashes = set(t.albumhash for t in tracks)
hashes_from_albums = set( hashes_from_albums = set(
a.albumhash for a in AlbumStore.get_albums_by_artisthash(artisthash) a.albumhash for a in AlbumStore.get_albums_by_artisthash(artisthash)
@ -291,7 +290,7 @@ def get_all_artist_tracks(artisthash: str):
""" """
Returns all artists by a given artist. Returns all artists by a given artist.
""" """
tracks = TrackStore.get_tracks_by_artist(artisthash) tracks = TrackStore.get_tracks_by_artisthash(artisthash)
return {"tracks": serialize_tracks(tracks)} return {"tracks": serialize_tracks(tracks)}

View File

@ -2,16 +2,18 @@
Contains all the folder routes. Contains all the folder routes.
""" """
import os import os
import psutil
from pathlib import Path from pathlib import Path
import psutil
from flask import Blueprint, request from flask import Blueprint, request
from showinfm import show_in_file_manager from showinfm import show_in_file_manager
from app import settings from app import settings
from app.lib.folderslib import GetFilesAndDirs, get_folders
from app.db.sqlite.settings import SettingsSQLMethods as db from app.db.sqlite.settings import SettingsSQLMethods as db
from app.utils.wintools import win_replace_slash, is_windows from app.lib.folderslib import GetFilesAndDirs, get_folders
from app.serializers.track import track_serializer
from app.store.tracks import TrackStore as store
from app.utils.wintools import is_windows, win_replace_slash
api = Blueprint("folder", __name__, url_prefix="") api = Blueprint("folder", __name__, url_prefix="")
@ -129,3 +131,19 @@ def open_in_file_manager():
show_in_file_manager(path) show_in_file_manager(path)
return {"success": True} return {"success": True}
@api.route("/folder/tracks/all")
def get_tracks_in_path():
path = request.args.get("path")
if path is None:
return {"error": "No path provided."}, 400
tracks = store.get_tracks_in_path(path)
tracks = sorted(tracks, key=lambda i: i.last_mod)
tracks = (track_serializer(t) for t in tracks if Path(t.filepath).exists())
return {
"tracks": list(tracks)[:300],
}

View File

@ -135,6 +135,31 @@ def create_playlist():
return {"playlist": playlist}, 201 return {"playlist": playlist}, 201
def get_path_trackhashes(path: str):
"""
Returns a list of trackhashes in a folder.
"""
tracks = TrackStore.get_tracks_in_path(path)
tracks = sorted(tracks, key=lambda t: t.last_mod)
return [t.trackhash for t in tracks]
def get_album_trackhashes(albumhash: str):
"""
Returns a list of trackhashes in an album.
"""
tracks = TrackStore.get_tracks_by_albumhash(albumhash)
return [t.trackhash for t in tracks]
def get_artist_trackhashes(artisthash: str):
"""
Returns a list of trackhashes for an artist.
"""
tracks = TrackStore.get_tracks_by_artisthash(artisthash)
return [t.trackhash for t in tracks]
@api.route("/playlist/<playlist_id>/add", methods=["POST"]) @api.route("/playlist/<playlist_id>/add", methods=["POST"])
def add_track_to_playlist(playlist_id: str): def add_track_to_playlist(playlist_id: str):
""" """
@ -145,9 +170,28 @@ def add_track_to_playlist(playlist_id: str):
if data is None: if data is None:
return {"error": "Track hash not provided"}, 400 return {"error": "Track hash not provided"}, 400
trackhash = data["track"] try:
itemtype = data["itemtype"]
except KeyError:
itemtype = None
insert_count = tracks_to_playlist(int(playlist_id), [trackhash]) try:
itemhash = data["itemhash"]
except KeyError:
itemhash = None
if itemtype == "track":
trackhashes = [itemhash]
elif itemtype == "folder":
trackhashes = get_path_trackhashes(itemhash)
elif itemtype == "album":
trackhashes = get_album_trackhashes(itemhash)
elif itemtype == "artist":
trackhashes = get_artist_trackhashes(itemhash)
else:
trackhashes = []
insert_count = tracks_to_playlist(int(playlist_id), trackhashes)
if insert_count == 0: if insert_count == 0:
return {"error": "Track already exists in playlist"}, 409 return {"error": "Track already exists in playlist"}, 409
@ -328,6 +372,10 @@ def remove_tracks_from_playlist(pid: int):
return {"msg": "Done"}, 200 return {"msg": "Done"}, 200
def playlist_exists(name: str) -> bool:
return count_playlist_by_name(name) > 0
@api.route("/playlist/save-folder", methods=["POST"]) @api.route("/playlist/save-folder", methods=["POST"])
def save_folder_as_folder(): def save_folder_as_folder():
data = request.get_json() data = request.get_json()
@ -342,17 +390,10 @@ def save_folder_as_folder():
if path is None or name is None: if path is None or name is None:
return msg return msg
p_count = count_playlist_by_name(name) if playlist_exists(name):
if p_count > 0:
return {"error": "Playlist already exists"}, 409 return {"error": "Playlist already exists"}, 409
tracks = TrackStore.get_tracks_in_path(path) trackhashes = get_path_trackhashes(path)
# sort tracks by last_mod
tracks = sorted(tracks, key=lambda t: t.last_mod)
trackhashes = [t.trackhash for t in tracks]
if len(trackhashes) == 0: if len(trackhashes) == 0:
return {"error": "No tracks found in folder"}, 404 return {"error": "No tracks found in folder"}, 404
@ -365,3 +406,67 @@ def save_folder_as_folder():
PL.update_last_updated(playlist.id) PL.update_last_updated(playlist.id)
return {"playlist_id": playlist.id}, 201 return {"playlist_id": playlist.id}, 201
@api.route("/playlist/save-album", methods=["POST"])
def save_album_as_playlist():
data = request.get_json()
msg = {"error": "'albumhash' and 'playlist_name' not provided"}, 400
if data is None:
return msg
albumhash = data.get("albumhash")
name = data.get("playlist_name")
if albumhash is None or name is None:
return msg
if playlist_exists(name):
return {"error": "Playlist already exists"}, 409
trackhashes = get_album_trackhashes(albumhash)
if len(trackhashes) == 0:
return {"error": "No tracks found in album"}, 404
playlist = insert_playlist(name)
if playlist is None:
return {"error": "Playlist could not be created"}, 500
tracks_to_playlist(playlist.id, trackhashes)
PL.update_last_updated(playlist.id)
return {"playlist_id": playlist.id}, 201
@api.route("/playlist/save-artist", methods=["POST"])
def save_artist_as_playlist():
data = request.get_json()
msg = {"error": "'artisthash' and 'playlist_name' not provided"}, 400
if data is None:
return msg
artisthash = data.get("artisthash")
name = data.get("playlist_name")
if artisthash is None or name is None:
return msg
if playlist_exists(name):
return {"error": "Playlist already exists"}, 409
trackhashes = get_artist_trackhashes(artisthash)
if len(trackhashes) == 0:
return {"error": "No tracks found in artist"}, 404
playlist = insert_playlist(name)
if playlist is None:
return {"error": "Playlist could not be created"}, 500
tracks_to_playlist(playlist.id, trackhashes)
PL.update_last_updated(playlist.id)
return {"playlist_id": playlist.id}, 201

View File

@ -96,8 +96,7 @@ class SQLitePlaylistMethods:
def add_item_to_json_list(playlist_id: int, field: str, items: set[str]): def add_item_to_json_list(playlist_id: int, field: str, items: set[str]):
""" """
Adds a string item to a json dumped list using a playlist id and field name. Adds a string item to a json dumped list using a playlist id and field name.
Takes the playlist ID, a field name, Takes the playlist ID, a field name, an item to add to the field.
an item to add to the field, and an error to raise if the item is already in the field.
""" """
sql = f"SELECT {field} FROM playlists WHERE id = ?" sql = f"SELECT {field} FROM playlists WHERE id = ?"
@ -121,6 +120,9 @@ class SQLitePlaylistMethods:
@classmethod @classmethod
def add_tracks_to_playlist(cls, playlist_id: int, trackhashes: list[str]): def add_tracks_to_playlist(cls, playlist_id: int, trackhashes: list[str]):
"""
Adds trackhashes to a playlist
"""
return cls.add_item_to_json_list(playlist_id, "trackhashes", trackhashes) return cls.add_item_to_json_list(playlist_id, "trackhashes", trackhashes)
@staticmethod @staticmethod

View File

@ -1,30 +1,35 @@
from dataclasses import asdict from dataclasses import asdict
from app.models.track import Track from app.models.track import Track
def track_serializer(track: Track, _remove: set = {}, retain_disc=False) -> dict: def track_serializer(track: Track, to_remove: set = {}, remove_disc=True) -> dict:
album_dict = asdict(track) album_dict = asdict(track)
to_remove = { props = {
"date", "date",
"genre", "genre",
"last_mod", "last_mod",
"og_title", "og_title",
"og_album", "og_album",
}.union(_remove) "copyright",
"disc",
"track",
}.union(to_remove)
if not retain_disc: if not remove_disc:
to_remove.union("disc", "track") props.remove("disc")
props.remove("track")
to_remove.update(key for key in album_dict.keys() if key.startswith("is_")) props.update(key for key in album_dict.keys() if key.startswith("is_"))
to_remove.remove('is_favorite') props.remove("is_favorite")
for key in to_remove: for key in props:
album_dict.pop(key, None) album_dict.pop(key, None)
return album_dict return album_dict
def serialize_tracks( def serialize_tracks(
tracks: list[Track], _remove: set = {}, retain_disc=False tracks: list[Track], _remove: set = {}, remove_disc=True
) -> list[dict]: ) -> list[dict]:
return [track_serializer(t, _remove, retain_disc) for t in tracks] return [track_serializer(t, _remove, remove_disc) for t in tracks]

View File

@ -160,7 +160,7 @@ class TrackStore:
return remove_duplicates(tracks) return remove_duplicates(tracks)
@classmethod @classmethod
def get_tracks_by_artist(cls, artisthash: str) -> list[Track]: def get_tracks_by_artisthash(cls, artisthash: str) -> list[Track]:
""" """
Returns all tracks matching the given artist. Duplicate tracks are removed. Returns all tracks matching the given artist. Duplicate tracks are removed.
""" """