mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-10 13:07:35 +00:00
break down the api blueprint into smaller blueprints
This commit is contained in:
parent
1908633f9d
commit
e889d0ef55
@ -3,12 +3,10 @@ from flask_cors import CORS
|
|||||||
|
|
||||||
from flask_caching import Cache
|
from flask_caching import Cache
|
||||||
|
|
||||||
config = {
|
config = {"CACHE_TYPE": "SimpleCache", "CACHE_DEFAULT_TIMEOUT": 300}
|
||||||
"CACHE_TYPE": "SimpleCache",
|
|
||||||
"CACHE_DEFAULT_TIMEOUT": 300
|
cache = Cache(config=config)
|
||||||
}
|
|
||||||
|
|
||||||
cache = Cache(config = config)
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@ -18,7 +16,13 @@ def create_app():
|
|||||||
cache.init_app(app)
|
cache.init_app(app)
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
from . import api
|
from app.api import artist, track, search, folder, album
|
||||||
app.register_blueprint(api.bp, url_prefix='/')
|
|
||||||
|
app.register_blueprint(album.album_bp, url_prefix="/")
|
||||||
|
app.register_blueprint(artist.artist_bp, url_prefix="/")
|
||||||
|
app.register_blueprint(track.track_bp, url_prefix="/")
|
||||||
|
app.register_blueprint(search.search_bp, url_prefix="/")
|
||||||
|
app.register_blueprint(folder.folder_bp, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import urllib
|
import urllib
|
||||||
from typing import List
|
from typing import List
|
||||||
from app import models, functions, helpers
|
from app import models, functions, helpers
|
||||||
from app import trackslib, api
|
from app import trackslib
|
||||||
|
from app import api
|
||||||
|
|
||||||
|
|
||||||
@helpers.background
|
@helpers.background
|
||||||
|
@ -1,307 +0,0 @@
|
|||||||
import os
|
|
||||||
import urllib
|
|
||||||
from typing import List
|
|
||||||
from flask import Blueprint, request, send_file
|
|
||||||
|
|
||||||
from app import functions, instances, helpers, cache, models, prep
|
|
||||||
from app import albumslib, searchlib
|
|
||||||
from app import trackslib
|
|
||||||
|
|
||||||
bp = Blueprint("api", __name__, url_prefix="")
|
|
||||||
functions.start_watchdog()
|
|
||||||
|
|
||||||
DB_TRACKS = instances.songs_instance.get_all_songs()
|
|
||||||
ALBUMS: List[models.Album] = []
|
|
||||||
TRACKS: List[models.Track] = []
|
|
||||||
|
|
||||||
home_dir = helpers.home_dir
|
|
||||||
|
|
||||||
|
|
||||||
@helpers.background
|
|
||||||
def initialize() -> None:
|
|
||||||
"""
|
|
||||||
Runs all the necessary setup functions.
|
|
||||||
"""
|
|
||||||
albumslib.create_everything()
|
|
||||||
prep.create_config_dir()
|
|
||||||
functions.reindex_tracks()
|
|
||||||
|
|
||||||
|
|
||||||
initialize()
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/")
|
|
||||||
def say_hi():
|
|
||||||
"""Returns some text for the default route"""
|
|
||||||
return "^ _ ^"
|
|
||||||
|
|
||||||
|
|
||||||
SEARCH_RESULTS = {
|
|
||||||
"tracks": [],
|
|
||||||
"albums": [],
|
|
||||||
"artists": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/search")
|
|
||||||
def search():
|
|
||||||
"""
|
|
||||||
Returns a list of songs, albums and artists that match the search query.
|
|
||||||
"""
|
|
||||||
query = request.args.get("q") or "Mexican girl"
|
|
||||||
|
|
||||||
albums = searchlib.get_search_albums(query)
|
|
||||||
artists_dicts = []
|
|
||||||
|
|
||||||
artist_tracks = searchlib.get_artists(query)
|
|
||||||
|
|
||||||
for song in artist_tracks:
|
|
||||||
for artist in song.artists:
|
|
||||||
if query.lower() in artist.lower():
|
|
||||||
|
|
||||||
artist_obj = {
|
|
||||||
"name": artist,
|
|
||||||
"image": helpers.check_artist_image(artist),
|
|
||||||
}
|
|
||||||
|
|
||||||
if artist_obj not in artists_dicts:
|
|
||||||
artists_dicts.append(artist_obj)
|
|
||||||
|
|
||||||
_tracks = searchlib.get_tracks(query)
|
|
||||||
tracks = [*_tracks, *artist_tracks]
|
|
||||||
|
|
||||||
SEARCH_RESULTS.clear()
|
|
||||||
SEARCH_RESULTS["tracks"] = tracks
|
|
||||||
SEARCH_RESULTS["albums"] = albums
|
|
||||||
SEARCH_RESULTS["artists"] = artists_dicts
|
|
||||||
|
|
||||||
return {
|
|
||||||
"data": [
|
|
||||||
{"tracks": tracks[:5], "more": len(tracks) > 5},
|
|
||||||
{"albums": albums[:6], "more": len(albums) > 6},
|
|
||||||
{"artists": artists_dicts[:6], "more": len(artists_dicts) > 6},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/search/loadmore")
|
|
||||||
def search_load_more():
|
|
||||||
"""
|
|
||||||
Returns more songs, albums or artists from a search query.
|
|
||||||
"""
|
|
||||||
type = request.args.get("type")
|
|
||||||
start = int(request.args.get("start"))
|
|
||||||
|
|
||||||
if type == "tracks":
|
|
||||||
return {
|
|
||||||
"tracks": SEARCH_RESULTS["tracks"][start : start + 5],
|
|
||||||
"more": len(SEARCH_RESULTS["tracks"]) > start + 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
elif type == "albums":
|
|
||||||
return {
|
|
||||||
"albums": SEARCH_RESULTS["albums"][start : start + 6],
|
|
||||||
"more": len(SEARCH_RESULTS["albums"]) > start + 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
elif type == "artists":
|
|
||||||
return {
|
|
||||||
"artists": SEARCH_RESULTS["artists"][start : start + 6],
|
|
||||||
"more": len(SEARCH_RESULTS["artists"]) > start + 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/populate")
|
|
||||||
def find_tracks():
|
|
||||||
"""call the populate function"""
|
|
||||||
functions.populate()
|
|
||||||
return "🎸"
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/album/artists", methods=["POST"])
|
|
||||||
def get_albumartists():
|
|
||||||
"""Returns a list of artists featured in a given album."""
|
|
||||||
data = request.get_json()
|
|
||||||
|
|
||||||
album = data["album"]
|
|
||||||
artist = data["artist"]
|
|
||||||
|
|
||||||
tracks = []
|
|
||||||
|
|
||||||
for track in TRACKS:
|
|
||||||
if track.album == album and track.albumartist == artist:
|
|
||||||
tracks.append(track)
|
|
||||||
|
|
||||||
artists = []
|
|
||||||
|
|
||||||
for track in tracks:
|
|
||||||
for artist in track.artists:
|
|
||||||
if artist not in artists:
|
|
||||||
artists.append(artist)
|
|
||||||
|
|
||||||
final_artists = []
|
|
||||||
for artist in artists:
|
|
||||||
artist_obj = {
|
|
||||||
"name": artist,
|
|
||||||
"image": helpers.check_artist_image(artist),
|
|
||||||
}
|
|
||||||
final_artists.append(artist_obj)
|
|
||||||
|
|
||||||
return {"artists": final_artists}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/populate/images")
|
|
||||||
def populate_images():
|
|
||||||
"""
|
|
||||||
Populates the artist images.
|
|
||||||
"""
|
|
||||||
functions.populate_images()
|
|
||||||
return "Done"
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/artist/<artist>")
|
|
||||||
@cache.cached()
|
|
||||||
def get_artist_data(artist: str):
|
|
||||||
"""Returns the artist's data, tracks and albums"""
|
|
||||||
artist = urllib.parse.unquote(artist)
|
|
||||||
artist_obj = instances.artist_instance.get_artists_by_name(artist)
|
|
||||||
|
|
||||||
def get_artist_tracks():
|
|
||||||
songs = instances.songs_instance.find_songs_by_artist(artist)
|
|
||||||
|
|
||||||
return songs
|
|
||||||
|
|
||||||
artist_songs = get_artist_tracks()
|
|
||||||
songs = helpers.remove_duplicates(artist_songs)
|
|
||||||
|
|
||||||
def get_artist_albums():
|
|
||||||
artist_albums = []
|
|
||||||
albums_with_count = []
|
|
||||||
|
|
||||||
albums = instances.songs_instance.find_songs_by_albumartist(artist)
|
|
||||||
|
|
||||||
for song in albums:
|
|
||||||
if song["album"] not in artist_albums:
|
|
||||||
artist_albums.append(song["album"])
|
|
||||||
|
|
||||||
for album in artist_albums:
|
|
||||||
count = 0
|
|
||||||
length = 0
|
|
||||||
|
|
||||||
for song in artist_songs:
|
|
||||||
if song["album"] == album:
|
|
||||||
count = count + 1
|
|
||||||
length = length + song["length"]
|
|
||||||
|
|
||||||
album_ = {"title": album, "count": count, "length": length}
|
|
||||||
|
|
||||||
albums_with_count.append(album_)
|
|
||||||
|
|
||||||
return albums_with_count
|
|
||||||
|
|
||||||
return {"artist": artist_obj, "songs": songs, "albums": get_artist_albums()}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/f/<folder>")
|
|
||||||
# @cache.cached()
|
|
||||||
def get_folder_tree(folder: str):
|
|
||||||
"""
|
|
||||||
Returns a list of all the folders and tracks in the given folder.
|
|
||||||
"""
|
|
||||||
req_dir = folder.replace("|", "/")
|
|
||||||
|
|
||||||
if folder == "home":
|
|
||||||
req_dir = home_dir
|
|
||||||
|
|
||||||
dir_content = os.scandir(os.path.join(home_dir, req_dir))
|
|
||||||
|
|
||||||
folders = []
|
|
||||||
files = []
|
|
||||||
|
|
||||||
for entry in dir_content:
|
|
||||||
if entry.is_dir() and not entry.name.startswith("."):
|
|
||||||
files_in_dir = helpers.run_fast_scandir(entry.path, [".flac", ".mp3"])[1]
|
|
||||||
|
|
||||||
if len(files_in_dir) != 0:
|
|
||||||
_dir = {
|
|
||||||
"name": entry.name,
|
|
||||||
"count": len(files_in_dir),
|
|
||||||
"path": entry.path.replace(home_dir, ""),
|
|
||||||
}
|
|
||||||
|
|
||||||
folders.append(_dir)
|
|
||||||
|
|
||||||
if entry.is_file():
|
|
||||||
if entry.name.endswith(".flac") or entry.name.endswith(".mp3"):
|
|
||||||
files.append(entry)
|
|
||||||
|
|
||||||
files.sort(key=lambda x: os.path.getmtime(x.path))
|
|
||||||
|
|
||||||
songs = []
|
|
||||||
|
|
||||||
for entry in files:
|
|
||||||
for track in TRACKS:
|
|
||||||
if track.filepath == entry.path:
|
|
||||||
songs.append(track)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"files": helpers.remove_duplicates(songs),
|
|
||||||
"folders": sorted(folders, key=lambda i: i["name"]),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/albums")
|
|
||||||
def get_albums():
|
|
||||||
"""returns all the albums"""
|
|
||||||
albums = []
|
|
||||||
|
|
||||||
for song in DB_TRACKS:
|
|
||||||
al_obj = {"name": song["album"], "artist": song["artists"]}
|
|
||||||
|
|
||||||
if al_obj not in albums:
|
|
||||||
albums.append(al_obj)
|
|
||||||
|
|
||||||
return {"albums": albums}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/album/tracks", methods=["POST"])
|
|
||||||
def get_album_tracks():
|
|
||||||
"""Returns all the tracks in the given album."""
|
|
||||||
data = request.get_json()
|
|
||||||
|
|
||||||
album = data["album"]
|
|
||||||
artist = data["artist"]
|
|
||||||
|
|
||||||
songs = trackslib.get_album_tracks(album, artist)
|
|
||||||
album = albumslib.find_album(album, artist)
|
|
||||||
|
|
||||||
return {"songs": songs, "info": album}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/album/<title>/<artist>/bio")
|
|
||||||
@cache.cached()
|
|
||||||
def get_album_bio(title, artist):
|
|
||||||
"""Returns the album bio for the given album."""
|
|
||||||
bio = functions.get_album_bio(title, artist)
|
|
||||||
return {"bio": bio}, 200
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/file/<trackid>")
|
|
||||||
def send_track_file(trackid):
|
|
||||||
"""
|
|
||||||
Returns an audio file that matches the passed id to the client.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
filepath = instances.songs_instance.get_song_by_id(trackid)["filepath"]
|
|
||||||
return send_file(filepath, mimetype="audio/mp3")
|
|
||||||
except FileNotFoundError:
|
|
||||||
return "File not found", 404
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/sample")
|
|
||||||
def get_sample_track():
|
|
||||||
"""
|
|
||||||
Returns a sample track object.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return instances.songs_instance.get_song_by_album("Legends Never Die", "Juice WRLD")
|
|
23
server/app/api/__init__.py
Normal file
23
server/app/api/__init__.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
from app import models, instances
|
||||||
|
from app import functions, helpers, albumslib, prep
|
||||||
|
|
||||||
|
|
||||||
|
DB_TRACKS = instances.songs_instance.get_all_songs()
|
||||||
|
ALBUMS: List[models.Album] = []
|
||||||
|
TRACKS: List[models.Track] = []
|
||||||
|
|
||||||
|
|
||||||
|
@helpers.background
|
||||||
|
def initialize() -> None:
|
||||||
|
"""
|
||||||
|
Runs all the necessary setup functions.
|
||||||
|
"""
|
||||||
|
functions.start_watchdog()
|
||||||
|
albumslib.create_everything()
|
||||||
|
prep.create_config_dir()
|
||||||
|
functions.reindex_tracks()
|
||||||
|
|
||||||
|
|
||||||
|
initialize()
|
80
server/app/api/album.py
Normal file
80
server/app/api/album.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
from flask import Blueprint, request
|
||||||
|
from app import api
|
||||||
|
from app import helpers, cache
|
||||||
|
from app import albumslib, functions, trackslib
|
||||||
|
|
||||||
|
album_bp = Blueprint("album", __name__, url_prefix="")
|
||||||
|
|
||||||
|
|
||||||
|
@album_bp.route("/")
|
||||||
|
def say_hi():
|
||||||
|
"""Returns some text for the default route"""
|
||||||
|
return "^ _ ^"
|
||||||
|
|
||||||
|
|
||||||
|
@album_bp.route("/albums")
|
||||||
|
def get_albums():
|
||||||
|
"""returns all the albums"""
|
||||||
|
albums = []
|
||||||
|
|
||||||
|
for song in api.DB_TRACKS:
|
||||||
|
al_obj = {"name": song["album"], "artist": song["artists"]}
|
||||||
|
|
||||||
|
if al_obj not in albums:
|
||||||
|
albums.append(al_obj)
|
||||||
|
|
||||||
|
return {"albums": albums}
|
||||||
|
|
||||||
|
|
||||||
|
@album_bp.route("/album/tracks", methods=["POST"])
|
||||||
|
def get_album_tracks():
|
||||||
|
"""Returns all the tracks in the given album."""
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
album = data["album"]
|
||||||
|
artist = data["artist"]
|
||||||
|
|
||||||
|
songs = trackslib.get_album_tracks(album, artist)
|
||||||
|
album = albumslib.find_album(album, artist)
|
||||||
|
|
||||||
|
return {"songs": songs, "info": album}
|
||||||
|
|
||||||
|
|
||||||
|
@album_bp.route("/album/<title>/<artist>/bio")
|
||||||
|
@cache.cached()
|
||||||
|
def get_album_bio(title, artist):
|
||||||
|
"""Returns the album bio for the given album."""
|
||||||
|
bio = functions.get_album_bio(title, artist)
|
||||||
|
return {"bio": bio}, 200
|
||||||
|
|
||||||
|
|
||||||
|
@album_bp.route("/album/artists", methods=["POST"])
|
||||||
|
def get_albumartists():
|
||||||
|
"""Returns a list of artists featured in a given album."""
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
album = data["album"]
|
||||||
|
artist = data["artist"]
|
||||||
|
|
||||||
|
tracks = []
|
||||||
|
|
||||||
|
for track in api.TRACKS:
|
||||||
|
if track.album == album and track.albumartist == artist:
|
||||||
|
tracks.append(track)
|
||||||
|
|
||||||
|
artists = []
|
||||||
|
|
||||||
|
for track in tracks:
|
||||||
|
for artist in track.artists:
|
||||||
|
if artist not in artists:
|
||||||
|
artists.append(artist)
|
||||||
|
|
||||||
|
final_artists = []
|
||||||
|
for artist in artists:
|
||||||
|
artist_obj = {
|
||||||
|
"name": artist,
|
||||||
|
"image": helpers.check_artist_image(artist),
|
||||||
|
}
|
||||||
|
final_artists.append(artist_obj)
|
||||||
|
|
||||||
|
return {"artists": final_artists}
|
27
server/app/api/all.py
Normal file
27
server/app/api/all.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import os
|
||||||
|
import urllib
|
||||||
|
from typing import List
|
||||||
|
from flask import request, send_file
|
||||||
|
|
||||||
|
from app import functions, instances, helpers, cache, models, prep
|
||||||
|
from app import albumslib, searchlib
|
||||||
|
from app import trackslib
|
||||||
|
from app import api
|
||||||
|
|
||||||
|
|
||||||
|
home_dir = helpers.home_dir
|
||||||
|
|
||||||
|
# @api.bp.route("/populate")
|
||||||
|
# def find_tracks():
|
||||||
|
# """call the populate function"""
|
||||||
|
# functions.populate()
|
||||||
|
# return "🎸"
|
||||||
|
|
||||||
|
|
||||||
|
# @api.bp.route("/populate/images")
|
||||||
|
# def populate_images():
|
||||||
|
# """
|
||||||
|
# Populates the artist images.
|
||||||
|
# """
|
||||||
|
# functions.populate_images()
|
||||||
|
# return "Done"
|
51
server/app/api/artist.py
Normal file
51
server/app/api/artist.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
from flask import Blueprint
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from app import instances
|
||||||
|
from app import helpers
|
||||||
|
|
||||||
|
artist_bp = Blueprint("artist", __name__, url_prefix="/")
|
||||||
|
from app import cache
|
||||||
|
|
||||||
|
|
||||||
|
@artist_bp.route("/artist/<artist>")
|
||||||
|
@cache.cached()
|
||||||
|
def get_artist_data(artist: str):
|
||||||
|
"""Returns the artist's data, tracks and albums"""
|
||||||
|
artist = urllib.parse.unquote(artist)
|
||||||
|
artist_obj = instances.artist_instance.get_artists_by_name(artist)
|
||||||
|
|
||||||
|
def get_artist_tracks():
|
||||||
|
songs = instances.songs_instance.find_songs_by_artist(artist)
|
||||||
|
|
||||||
|
return songs
|
||||||
|
|
||||||
|
artist_songs = get_artist_tracks()
|
||||||
|
songs = helpers.remove_duplicates(artist_songs)
|
||||||
|
|
||||||
|
def get_artist_albums():
|
||||||
|
artist_albums = []
|
||||||
|
albums_with_count = []
|
||||||
|
|
||||||
|
albums = instances.songs_instance.find_songs_by_albumartist(artist)
|
||||||
|
|
||||||
|
for song in albums:
|
||||||
|
if song["album"] not in artist_albums:
|
||||||
|
artist_albums.append(song["album"])
|
||||||
|
|
||||||
|
for album in artist_albums:
|
||||||
|
count = 0
|
||||||
|
length = 0
|
||||||
|
|
||||||
|
for song in artist_songs:
|
||||||
|
if song["album"] == album:
|
||||||
|
count = count + 1
|
||||||
|
length = length + song["length"]
|
||||||
|
|
||||||
|
album_ = {"title": album, "count": count, "length": length}
|
||||||
|
|
||||||
|
albums_with_count.append(album_)
|
||||||
|
|
||||||
|
return albums_with_count
|
||||||
|
|
||||||
|
return {"artist": artist_obj, "songs": songs, "albums": get_artist_albums()}
|
55
server/app/api/folder.py
Normal file
55
server/app/api/folder.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import os
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
from app import api
|
||||||
|
|
||||||
|
folder_bp = Blueprint("folder", __name__, url_prefix="/")
|
||||||
|
from app import helpers
|
||||||
|
|
||||||
|
|
||||||
|
@folder_bp.route("/f/<folder>")
|
||||||
|
# @cache.cached()
|
||||||
|
def get_folder_tree(folder: str):
|
||||||
|
"""
|
||||||
|
Returns a list of all the folders and tracks in the given folder.
|
||||||
|
"""
|
||||||
|
req_dir = folder.replace("|", "/")
|
||||||
|
|
||||||
|
if folder == "home":
|
||||||
|
req_dir = helpers.home_dir
|
||||||
|
|
||||||
|
dir_content = os.scandir(os.path.join(helpers.home_dir, req_dir))
|
||||||
|
|
||||||
|
folders = []
|
||||||
|
files = []
|
||||||
|
|
||||||
|
for entry in dir_content:
|
||||||
|
if entry.is_dir() and not entry.name.startswith("."):
|
||||||
|
files_in_dir = helpers.run_fast_scandir(entry.path, [".flac", ".mp3"])[1]
|
||||||
|
|
||||||
|
if len(files_in_dir) != 0:
|
||||||
|
_dir = {
|
||||||
|
"name": entry.name,
|
||||||
|
"count": len(files_in_dir),
|
||||||
|
"path": entry.path.replace(helpers.home_dir, ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
folders.append(_dir)
|
||||||
|
|
||||||
|
if entry.is_file():
|
||||||
|
if entry.name.endswith(".flac") or entry.name.endswith(".mp3"):
|
||||||
|
files.append(entry)
|
||||||
|
|
||||||
|
files.sort(key=lambda x: os.path.getmtime(x.path))
|
||||||
|
|
||||||
|
songs = []
|
||||||
|
|
||||||
|
for entry in files:
|
||||||
|
for track in api.TRACKS:
|
||||||
|
if track.filepath == entry.path:
|
||||||
|
songs.append(track)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"files": helpers.remove_duplicates(songs),
|
||||||
|
"folders": sorted(folders, key=lambda i: i["name"]),
|
||||||
|
}
|
35
server/app/api/playlist.py
Normal file
35
server/app/api/playlist.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from flask import Blueprint, request
|
||||||
|
from app import instances
|
||||||
|
|
||||||
|
playlist_bp = Blueprint("playlist", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
|
@playlist_bp.route("/playlist/new")
|
||||||
|
def create_playlist():
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
playlist = {
|
||||||
|
"name": data["name"],
|
||||||
|
"description": data["description"],
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.playlist_instance.insert_playlist(playlist)
|
||||||
|
return 200
|
||||||
|
|
||||||
|
@playlist_bp.route("/playlist/<playlist_id>")
|
||||||
|
def get_playlist(playlist_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@playlist_bp.route("/playlist/tracks/get", methods=["POST"])
|
||||||
|
def add_tracks_to_playlist():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@playlist_bp.route("/playlist/tracks/remove", methods=["POST"])
|
||||||
|
def remove_single_track():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@playlist_bp.route("/playlist/<playlist_id>/update/desc", methods=["POST"])
|
||||||
|
def update_playlist():
|
||||||
|
pass
|
||||||
|
|
80
server/app/api/search.py
Normal file
80
server/app/api/search.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
from flask import Blueprint, request
|
||||||
|
|
||||||
|
from app import searchlib
|
||||||
|
from app import helpers
|
||||||
|
|
||||||
|
search_bp = Blueprint("search", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
SEARCH_RESULTS = {
|
||||||
|
"tracks": [],
|
||||||
|
"albums": [],
|
||||||
|
"artists": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@search_bp.route("/search")
|
||||||
|
def search():
|
||||||
|
"""
|
||||||
|
Returns a list of songs, albums and artists that match the search query.
|
||||||
|
"""
|
||||||
|
query = request.args.get("q") or "Mexican girl"
|
||||||
|
|
||||||
|
albums = searchlib.get_search_albums(query)
|
||||||
|
artists_dicts = []
|
||||||
|
|
||||||
|
artist_tracks = searchlib.get_artists(query)
|
||||||
|
|
||||||
|
for song in artist_tracks:
|
||||||
|
for artist in song.artists:
|
||||||
|
if query.lower() in artist.lower():
|
||||||
|
|
||||||
|
artist_obj = {
|
||||||
|
"name": artist,
|
||||||
|
"image": helpers.check_artist_image(artist),
|
||||||
|
}
|
||||||
|
|
||||||
|
if artist_obj not in artists_dicts:
|
||||||
|
artists_dicts.append(artist_obj)
|
||||||
|
|
||||||
|
_tracks = searchlib.get_tracks(query)
|
||||||
|
tracks = [*_tracks, *artist_tracks]
|
||||||
|
|
||||||
|
SEARCH_RESULTS.clear()
|
||||||
|
SEARCH_RESULTS["tracks"] = tracks
|
||||||
|
SEARCH_RESULTS["albums"] = albums
|
||||||
|
SEARCH_RESULTS["artists"] = artists_dicts
|
||||||
|
|
||||||
|
return {
|
||||||
|
"data": [
|
||||||
|
{"tracks": tracks[:5], "more": len(tracks) > 5},
|
||||||
|
{"albums": albums[:6], "more": len(albums) > 6},
|
||||||
|
{"artists": artists_dicts[:6], "more": len(artists_dicts) > 6},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@search_bp.route("/search/loadmore")
|
||||||
|
def search_load_more():
|
||||||
|
"""
|
||||||
|
Returns more songs, albums or artists from a search query.
|
||||||
|
"""
|
||||||
|
type = request.args.get("type")
|
||||||
|
start = int(request.args.get("start"))
|
||||||
|
|
||||||
|
if type == "tracks":
|
||||||
|
return {
|
||||||
|
"tracks": SEARCH_RESULTS["tracks"][start : start + 5],
|
||||||
|
"more": len(SEARCH_RESULTS["tracks"]) > start + 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
elif type == "albums":
|
||||||
|
return {
|
||||||
|
"albums": SEARCH_RESULTS["albums"][start : start + 6],
|
||||||
|
"more": len(SEARCH_RESULTS["albums"]) > start + 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
elif type == "artists":
|
||||||
|
return {
|
||||||
|
"artists": SEARCH_RESULTS["artists"][start : start + 6],
|
||||||
|
"more": len(SEARCH_RESULTS["artists"]) > start + 6,
|
||||||
|
}
|
26
server/app/api/track.py
Normal file
26
server/app/api/track.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from flask import Blueprint, send_file
|
||||||
|
|
||||||
|
from app import instances
|
||||||
|
|
||||||
|
track_bp = Blueprint("track", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
|
@track_bp.route("/file/<trackid>")
|
||||||
|
def send_track_file(trackid):
|
||||||
|
"""
|
||||||
|
Returns an audio file that matches the passed id to the client.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
filepath = instances.songs_instance.get_song_by_id(trackid)["filepath"]
|
||||||
|
return send_file(filepath, mimetype="audio/mp3")
|
||||||
|
except FileNotFoundError:
|
||||||
|
return "File not found", 404
|
||||||
|
|
||||||
|
|
||||||
|
@track_bp.route("/sample")
|
||||||
|
def get_sample_track():
|
||||||
|
"""
|
||||||
|
Returns a sample track object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return instances.songs_instance.get_song_by_album("Legends Never Die", "Juice WRLD")
|
@ -20,8 +20,9 @@ from PIL import Image
|
|||||||
|
|
||||||
from app import helpers
|
from app import helpers
|
||||||
from app import instances
|
from app import instances
|
||||||
from app import api, settings, watchdoge, models, trackslib
|
from app import settings, watchdoge, models, trackslib
|
||||||
from app import albumslib
|
from app import albumslib
|
||||||
|
from app import api
|
||||||
|
|
||||||
|
|
||||||
def reindex_tracks():
|
def reindex_tracks():
|
||||||
@ -371,6 +372,8 @@ def get_all_albums() -> List[models.Album]:
|
|||||||
albums: List[models.Album] = []
|
albums: List[models.Album] = []
|
||||||
|
|
||||||
for track in api.DB_TRACKS:
|
for track in api.DB_TRACKS:
|
||||||
albums.append(albumslib.create_album(track))
|
xx = albumslib.create_album(track)
|
||||||
|
if xx not in albums:
|
||||||
|
albums.append(xx)
|
||||||
|
|
||||||
return albums
|
return albums
|
||||||
|
@ -114,6 +114,6 @@ def check_artist_image(image: str) -> str:
|
|||||||
img_name = image.replace("/", "::") + ".webp"
|
img_name = image.replace("/", "::") + ".webp"
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(app_dir, "images", "artists", img_name)):
|
if not os.path.exists(os.path.join(app_dir, "images", "artists", img_name)):
|
||||||
return "http://0.0.0.0:8900/images/artists/0.webp"
|
return "http://10.5.8.182:8900/images/artists/0.webp"
|
||||||
else:
|
else:
|
||||||
return ("http://0.0.0.0:8900/images/artists/" + img_name,)
|
return ("http://10.5.8.182:8900/images/artists/" + img_name,)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from app.models import AllSongs, Artists, TrackColors, Albums
|
from app.models import AllSongs, Artists, TrackColors, Albums, Playlists
|
||||||
|
|
||||||
songs_instance = AllSongs()
|
songs_instance = AllSongs()
|
||||||
artist_instance = Artists()
|
artist_instance = Artists()
|
||||||
track_color_instance = TrackColors()
|
track_color_instance = TrackColors()
|
||||||
album_instance = Albums()
|
album_instance = Albums()
|
||||||
|
playlist_instance = Playlists()
|
@ -314,6 +314,47 @@ class Albums(Mongo):
|
|||||||
return convert_one(album)
|
return convert_one(album)
|
||||||
|
|
||||||
|
|
||||||
|
class Playlists(Mongo):
|
||||||
|
"""
|
||||||
|
The class for all playlist-related database operations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Playlists, self).__init__("PLAYLISTS")
|
||||||
|
self.collection = self.db["PLAYLISTS"]
|
||||||
|
|
||||||
|
def insert_playlist(self, playlist: dict) -> None:
|
||||||
|
"""
|
||||||
|
Inserts a new playlist object into the database.
|
||||||
|
"""
|
||||||
|
return self.collection.update_one(
|
||||||
|
{"name": playlist["name"]},
|
||||||
|
{"$set": playlist},
|
||||||
|
upsert=True,
|
||||||
|
).upserted_id
|
||||||
|
|
||||||
|
def get_all_playlists(self) -> list:
|
||||||
|
"""
|
||||||
|
Returns all the playlists in the database.
|
||||||
|
"""
|
||||||
|
playlists = self.collection.find()
|
||||||
|
return convert_many(playlists)
|
||||||
|
|
||||||
|
def get_playlist_by_id(self, id: str) -> dict:
|
||||||
|
"""
|
||||||
|
Returns a single playlist matching the id in the query params.
|
||||||
|
"""
|
||||||
|
playlist = self.collection.find_one({"_id": ObjectId(id)})
|
||||||
|
return convert_one(playlist)
|
||||||
|
|
||||||
|
def get_playlist_by_name(self, name: str) -> dict:
|
||||||
|
"""
|
||||||
|
Returns a single playlist matching the name in the query params.
|
||||||
|
"""
|
||||||
|
playlist = self.collection.find_one({"name": name})
|
||||||
|
return convert_one(playlist)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Album:
|
class Album:
|
||||||
"""
|
"""
|
||||||
@ -334,5 +375,7 @@ class Album:
|
|||||||
self.count = tags["count"]
|
self.count = tags["count"]
|
||||||
self.duration = tags["duration"]
|
self.duration = tags["duration"]
|
||||||
self.date = tags["date"]
|
self.date = tags["date"]
|
||||||
self.artistimage = "http://0.0.0.0:8900/images/artists/" + tags["artistimage"]
|
self.artistimage = "http://10.5.8.182:8900/images/artists/" + tags["artistimage"]
|
||||||
self.image = "http://0.0.0.0:8900/images/thumbnails/" + tags["image"]
|
self.image = "http://10.5.8.182:8900/images/thumbnails/" + tags["image"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
from app import models, api, albumslib, helpers
|
from app import models, albumslib, helpers
|
||||||
|
from app import api
|
||||||
|
|
||||||
|
|
||||||
def get_tracks(query: str) -> List[models.Track]:
|
def get_tracks(query: str) -> List[models.Track]:
|
||||||
|
@ -2,8 +2,9 @@ import os
|
|||||||
from trace import Trace
|
from trace import Trace
|
||||||
from typing import List
|
from typing import List
|
||||||
from app import models, instances
|
from app import models, instances
|
||||||
from app import albumslib, api
|
from app import albumslib
|
||||||
from app.helpers import remove_duplicates
|
from app.helpers import remove_duplicates
|
||||||
|
from app import api
|
||||||
|
|
||||||
def create_all_tracks() -> List[models.Track]:
|
def create_all_tracks() -> List[models.Track]:
|
||||||
"""
|
"""
|
||||||
@ -29,7 +30,7 @@ def create_all_tracks() -> List[models.Track]:
|
|||||||
|
|
||||||
|
|
||||||
def get_album_tracks(albumname, artist):
|
def get_album_tracks(albumname, artist):
|
||||||
"""Returns all tracks matching an album"""
|
"""Returns api tracks matching an album"""
|
||||||
_tracks: List[models.Track] = []
|
_tracks: List[models.Track] = []
|
||||||
|
|
||||||
for track in api.TRACKS:
|
for track in api.TRACKS:
|
||||||
|
@ -6,8 +6,9 @@ from watchdog.observers import Observer
|
|||||||
from watchdog.events import PatternMatchingEventHandler
|
from watchdog.events import PatternMatchingEventHandler
|
||||||
|
|
||||||
from app import instances, functions
|
from app import instances, functions
|
||||||
from app import api, models
|
from app import models
|
||||||
from app import albumslib
|
from app import albumslib
|
||||||
|
from app import api
|
||||||
|
|
||||||
|
|
||||||
class OnMyWatch:
|
class OnMyWatch:
|
||||||
@ -49,7 +50,6 @@ def add_track(filepath: str) -> None:
|
|||||||
api.TRACKS.append(models.Track(track))
|
api.TRACKS.append(models.Track(track))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def remove_track(filepath: str) -> None:
|
def remove_track(filepath: str) -> None:
|
||||||
"""
|
"""
|
||||||
Removes a track from the music dict.
|
Removes a track from the music dict.
|
||||||
|
@ -23,7 +23,7 @@ const tabs = useTabStore();
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.tabs {
|
.tabs {
|
||||||
padding: $small;
|
padding: $small;
|
||||||
height: 4rem;
|
height: 4.25rem;
|
||||||
|
|
||||||
.cont {
|
.cont {
|
||||||
background-color: $primary;
|
background-color: $primary;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
let base_uri = "http://0.0.0.0:9876";
|
let base_uri = "http://10.5.8.182:9876/";
|
||||||
|
|
||||||
const getTracksAndDirs = async (path) => {
|
const getTracksAndDirs = async (path) => {
|
||||||
let url;
|
let url;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const url = "http://0.0.0.0:9876/search/loadmore";
|
const url = "http://10.5.8.182:9876/search/loadmore";
|
||||||
|
|
||||||
async function loadMoreTracks(start) {
|
async function loadMoreTracks(start) {
|
||||||
const response = await axios.get(url, {
|
const response = await axios.get(url, {
|
||||||
|
@ -9,7 +9,7 @@ const current = ref(state.current);
|
|||||||
const next = ref({
|
const next = ref({
|
||||||
title: "The next song",
|
title: "The next song",
|
||||||
artists: ["... blah blah blah"],
|
artists: ["... blah blah blah"],
|
||||||
image: "http://0.0.0.0:8900/images/defaults/4.webp",
|
image: "http://10.5.8.182:8900/images/defaults/4.webp",
|
||||||
_id: {
|
_id: {
|
||||||
$oid: "",
|
$oid: "",
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,7 @@ const current_time = ref(0);
|
|||||||
|
|
||||||
const playing = ref(state.is_playing);
|
const playing = ref(state.is_playing);
|
||||||
|
|
||||||
const url = "http://0.0.0.0:9876/file/";
|
const url = "http://10.5.8.182:9876//file/";
|
||||||
|
|
||||||
const playAudio = (trackid) => {
|
const playAudio = (trackid) => {
|
||||||
const elem = document.getElementById('progress');
|
const elem = document.getElementById('progress');
|
||||||
|
@ -8,7 +8,7 @@ const queue = ref(
|
|||||||
Array<i.Track>({
|
Array<i.Track>({
|
||||||
title: "Nothing played yet",
|
title: "Nothing played yet",
|
||||||
artists: ["... blah blah blah"],
|
artists: ["... blah blah blah"],
|
||||||
image: "http://0.0.0.0:8900/images/thumbnails/4.webp",
|
image: "http://10.5.8.182:8900/images/thumbnails/4.webp",
|
||||||
trackid: "",
|
trackid: "",
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -19,14 +19,14 @@ const folder_list = ref([]);
|
|||||||
const current = ref(<i.Track>{
|
const current = ref(<i.Track>{
|
||||||
title: "Nothing played yet",
|
title: "Nothing played yet",
|
||||||
artists: ["... blah blah blah"],
|
artists: ["... blah blah blah"],
|
||||||
image: "http://0.0.0.0:8900/images/thumbnails/4.webp",
|
image: "http://10.5.8.182:8900/images/thumbnails/4.webp",
|
||||||
trackid: "",
|
trackid: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const prev = ref(<i.Track>{
|
const prev = ref(<i.Track>{
|
||||||
title: "Nothing played yet",
|
title: "Nothing played yet",
|
||||||
artists: ["... blah blah blah"],
|
artists: ["... blah blah blah"],
|
||||||
image: "http://0.0.0.0:8900/images/thumbnails/4.webp",
|
image: "http://10.5.8.182:8900/images/thumbnails/4.webp",
|
||||||
trackid: "",
|
trackid: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ const album = reactive({
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const is_playing = ref(false);
|
const is_playing = ref(false);
|
||||||
const settings = reactive({
|
const settings = reactive({
|
||||||
uri: "http://0.0.0.0:9876",
|
uri: "http://10.5.8.182:9876",
|
||||||
});
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user