add method and route to search across tracks, albums and artists.

+ break models into separate files
+ same for the utils and setup
This commit is contained in:
geoffrey45
2023-03-09 13:08:50 +03:00
parent d39c0ea2f8
commit e3ec9db989
55 changed files with 1113 additions and 1137 deletions
-1
View File
@@ -17,7 +17,6 @@ def create_api():
CORS(app)
with app.app_context():
app.register_blueprint(album.api)
app.register_blueprint(artist.api)
app.register_blueprint(track.api)
+9 -27
View File
@@ -6,13 +6,12 @@ from dataclasses import asdict
from flask import Blueprint, request
from app import utils
from app.db.sqlite.albums import SQLiteAlbumMethods as adb
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.store import Store
from app.models import FavType, Track
from app.utils.remove_duplicates import remove_duplicates
get_album_by_id = adb.get_album_by_id
get_albums_by_albumartist = adb.get_albums_by_albumartist
check_is_fav = favdb.check_is_favorite
@@ -20,8 +19,10 @@ api = Blueprint("album", __name__, url_prefix="")
@api.route("/album", methods=["POST"])
def get_album():
"""Returns all the tracks in the given album."""
def get_album_tracks_and_info():
"""
Returns all the tracks in the given album
"""
data = request.get_json()
error_msg = {"msg": "No hash provided"}
@@ -58,7 +59,7 @@ def get_album():
return list(genres)
album.genres = get_album_genres(tracks)
tracks = utils.remove_duplicates(tracks)
tracks = remove_duplicates(tracks)
album.count = len(tracks)
album.get_date_from_tracks(tracks)
@@ -83,7 +84,7 @@ def get_album():
@api.route("/album/<albumhash>/tracks", methods=["GET"])
def get_album_tracks(albumhash: str):
"""
Returns all the tracks in the given album.
Returns all the tracks in the given album, sorted by disc and track number.
"""
tracks = Store.get_tracks_by_albumhash(albumhash)
tracks = [asdict(t) for t in tracks]
@@ -104,11 +105,11 @@ def get_artist_albums():
if data is None:
return {"msg": "No albumartist provided"}
albumartists: str = data["albumartists"] # type: ignore
albumartists: str = data["albumartists"]
limit: int = data.get("limit")
exclude: str = data.get("exclude")
albumartists: list[str] = albumartists.split(",") # type: ignore
albumartists: list[str] = albumartists.split(",")
albums = [
{
@@ -121,22 +122,3 @@ def get_artist_albums():
albums = [a for a in albums if len(a["albums"]) > 0]
return {"data": albums}
# @album_bp.route("/album/bio", methods=["POST"])
# def get_album_bio():
# """Returns the album bio for the given album."""
# data = request.get_json()
# album_hash = data["hash"]
# err_msg = {"bio": "No bio found"}
# album = instances.album_instance.find_album_by_hash(album_hash)
# if album is None:
# return err_msg, 404
# bio = FetchAlbumBio(album["title"], album["artist"])()
# if bio is None:
# return err_msg, 404
# return {"bio": bio}
+1 -1
View File
@@ -8,7 +8,7 @@ from flask import Blueprint, request
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.store import Store
from app.models import Album, FavType, Track
from app.utils import remove_duplicates
from app.utils.remove_duplicates import remove_duplicates
api = Blueprint("artist", __name__, url_prefix="/")
+1 -1
View File
@@ -3,7 +3,7 @@ from flask import Blueprint, request
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.store import Store
from app.models import FavType
from app.utils import UseBisection
from app.utils.bisection import UseBisection
api = Blueprint("favorite", __name__, url_prefix="/")
+3 -2
View File
@@ -10,8 +10,9 @@ from flask import Blueprint, request
from app import settings
from app.lib.folderslib import GetFilesAndDirs
from app.db.sqlite.settings import SettingsSQLMethods as db
from app.models import Folder
from app.utils import create_folder_hash, is_windows, win_replace_slash
from app.models.folder import Folder
from app.utils.hashing import create_folder_hash
from app.utils.wintools import win_replace_slash, is_windows
api = Blueprint("folder", __name__, url_prefix="/")
+2 -1
View File
@@ -11,7 +11,8 @@ from app import models, serializer
from app.db.sqlite.playlists import SQLitePlaylistMethods
from app.db.store import Store
from app.lib import playlistlib
from app.utils import create_new_date, remove_duplicates
from app.utils.generators import create_new_date
from app.utils.remove_duplicates import remove_duplicates
api = Blueprint("playlist", __name__, url_prefix="/")
+27 -33
View File
@@ -2,16 +2,15 @@
Contains all the search routes.
"""
from unidecode import unidecode
from flask import Blueprint, request
from app import models, utils
from app import models
from app.db.store import Store
from app.lib import searchlib
from unidecode import unidecode
api = Blueprint("search", __name__, url_prefix="/")
SEARCH_COUNT = 12
"""The max amount of items to return per request"""
@@ -28,48 +27,36 @@ class SearchResults:
artists: list[models.Artist] = []
class DoSearch:
"""Class containing the methods that perform searching."""
class Search:
def __init__(self, query: str) -> None:
"""
:param :str:`query`: the search query.
"""
self.tracks: list[models.Track] = []
self.query = unidecode(query)
SearchResults.query = self.query
def search_tracks(self):
"""Calls :class:`SearchTracks` which returns the tracks that fuzzily match
"""
Calls :class:`SearchTracks` which returns the tracks that fuzzily match
the search terms. Then adds them to the `SearchResults` store.
"""
self.tracks = Store.tracks
tracks = searchlib.SearchTracks(self.tracks, self.query)()
tracks = searchlib.SearchTracks(self.query)()
if len(tracks) == 0:
return []
tracks = utils.remove_duplicates(tracks)
SearchResults.tracks = tracks
return tracks
def search_artists(self):
"""Calls :class:`SearchArtists` which returns the artists that fuzzily match
the search term. Then adds them to the `SearchResults` store.
"""
artists = [a.name for a in Store.artists]
artists = searchlib.SearchArtists(Store.artists, self.query)()
artists = searchlib.SearchArtists(self.query)()
SearchResults.artists = artists
return artists
def search_albums(self):
"""Calls :class:`SearchAlbums` which returns the albums that fuzzily match
the search term. Then adds them to the `SearchResults` store.
"""
albums = Store.albums
albums = searchlib.SearchAlbums(albums, self.query)()
albums = searchlib.SearchAlbums(self.query)()
SearchResults.albums = albums
return albums
@@ -86,6 +73,10 @@ class DoSearch:
# return playlists
def get_top_results(self):
finder = searchlib.SearchAll()
return finder.search(self.query)
def search_all(self):
"""Calls all the search methods."""
self.search_tracks()
@@ -104,7 +95,7 @@ def search_tracks():
if not query:
return {"error": "No query provided"}, 400
tracks = DoSearch(query).search_tracks()
tracks = Search(query).search_tracks()
return {
"tracks": tracks[:SEARCH_COUNT],
@@ -122,7 +113,7 @@ def search_albums():
if not query:
return {"error": "No query provided"}, 400
tracks = DoSearch(query).search_albums()
tracks = Search(query).search_albums()
return {
"albums": tracks[:SEARCH_COUNT],
@@ -140,7 +131,7 @@ def search_artists():
if not query:
return {"error": "No query provided"}, 400
artists = DoSearch(query).search_artists()
artists = Search(query).search_artists()
return {
"artists": artists[:SEARCH_COUNT],
@@ -176,14 +167,17 @@ def get_top_results():
if not query:
return {"error": "No query provided"}, 400
DoSearch(query).search_all()
results = Search(query).get_top_results()
max_results = 2
# max_results = 2
# return {
# "tracks": SearchResults.tracks[:max_results],
# "albums": SearchResults.albums[:max_results],
# "artists": SearchResults.artists[:max_results],
# "playlists": SearchResults.playlists[:max_results],
# }
return {
"tracks": SearchResults.tracks[:max_results],
"albums": SearchResults.albums[:max_results],
"artists": SearchResults.artists[:max_results],
"playlists": SearchResults.playlists[:max_results],
"results": results
}
@@ -198,20 +192,20 @@ def search_load_more():
if s_type == "tracks":
t = SearchResults.tracks
return {
"tracks": t[index : index + SEARCH_COUNT],
"tracks": t[index: index + SEARCH_COUNT],
"more": len(t) > index + SEARCH_COUNT,
}
elif s_type == "albums":
a = SearchResults.albums
return {
"albums": a[index : index + SEARCH_COUNT],
"albums": a[index: index + SEARCH_COUNT],
"more": len(a) > index + SEARCH_COUNT,
}
elif s_type == "artists":
a = SearchResults.artists
return {
"artists": a[index : index + SEARCH_COUNT],
"artists": a[index: index + SEARCH_COUNT],
"more": len(a) > index + SEARCH_COUNT,
}
+2 -1
View File
@@ -4,9 +4,10 @@ from app import settings
from app.logger import log
from app.lib import populate
from app.db.store import Store
from app.utils import background, get_random_str
from app.lib.watchdogg import Watcher as WatchDog
from app.db.sqlite.settings import SettingsSQLMethods as sdb
from app.utils.generators import get_random_str
from app.utils.threading import background
api = Blueprint("settings", __name__, url_prefix="/")
+25 -12
View File
@@ -1,7 +1,9 @@
"""
Contains all the track routes.
"""
from flask import Blueprint, send_file
import os
from flask import Blueprint, send_file, request
from app.db.store import Store
@@ -15,20 +17,31 @@ def send_track_file(trackhash: str):
Falls back to track hash if id is not found.
"""
msg = {"msg": "File Not Found"}
def get_mime(filename: str) -> str:
ext = filename.rsplit(".", maxsplit=1)[-1]
return f"audio/{ext}"
filepath = request.args.get("filepath")
if filepath is not None and os.path.exists(filepath):
audio_type = get_mime(filepath)
return send_file(filepath, mimetype=audio_type)
if trackhash is None:
return msg, 404
try:
track = Store.get_tracks_by_trackhashes([trackhash])[0]
except IndexError:
track = None
tracks = Store.get_tracks_by_trackhashes([trackhash])
if track is None:
return msg, 404
for track in tracks:
if track is None:
return msg, 404
audio_type = track.filepath.rsplit(".", maxsplit=1)[-1]
audio_type = get_mime(track.filepath)
try:
return send_file(track.filepath, mimetype=f"audio/{audio_type}")
except FileNotFoundError:
return msg, 404
try:
return send_file(track.filepath, mimetype=audio_type)
except FileNotFoundError:
return msg, 404
return msg, 404