mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
add api docs for streaming routes
+ add trackhash schema
This commit is contained in:
committed by
Mungai Njoroge
parent
7d064a8562
commit
fb635ff35f
+2
-1
@@ -29,6 +29,7 @@ from app.api import (
|
||||
getall,
|
||||
)
|
||||
|
||||
# TODO: Move this description to a separate file
|
||||
open_api_description = f"""
|
||||
The REST API exposed by your Swing Music server
|
||||
|
||||
@@ -65,7 +66,7 @@ def create_api():
|
||||
with app.app_context():
|
||||
app.register_api(album.api)
|
||||
app.register_api(artist.api)
|
||||
app.register_blueprint(send_file.api)
|
||||
app.register_api(send_file.api)
|
||||
app.register_blueprint(search.api)
|
||||
app.register_blueprint(folder.api)
|
||||
app.register_blueprint(playlist.api)
|
||||
|
||||
+15
-14
@@ -4,31 +4,32 @@ Contains all the album routes.
|
||||
|
||||
import random
|
||||
|
||||
from pydantic import Field
|
||||
from flask_openapi3 import Tag
|
||||
from flask_openapi3 import APIBlueprint
|
||||
from pydantic import BaseModel, Field
|
||||
from app.api.apischemas import AlbumHashSchema, AlbumLimitSchema, ArtistHashSchema
|
||||
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
|
||||
from app.lib.albumslib import sort_by_track_no
|
||||
from app.models import FavType, Track
|
||||
from app.serializers.album import serialize_for_card
|
||||
from app.serializers.track import serialize_track
|
||||
from app.settings import Defaults
|
||||
from app.models import FavType, Track
|
||||
from app.store.albums import AlbumStore
|
||||
from app.store.tracks import TrackStore
|
||||
from app.utils.hashing import create_hash
|
||||
from app.lib.albumslib import sort_by_track_no
|
||||
from app.serializers.album import serialize_for_card
|
||||
from app.serializers.track import serialize_track
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
|
||||
|
||||
get_albums_by_albumartist = adb.get_albums_by_albumartist
|
||||
check_is_fav = favdb.check_is_favorite
|
||||
|
||||
bp_tag = Tag(name="Album", description="Single album")
|
||||
api = APIBlueprint("album", __name__, url_prefix="", abp_tags=[bp_tag])
|
||||
api = APIBlueprint("album", __name__, url_prefix="/album", abp_tags=[bp_tag])
|
||||
|
||||
|
||||
@api.post("/album")
|
||||
# NOTE: Don't use "/" as it will cause redirects (failure)
|
||||
@api.post("")
|
||||
def get_album_tracks_and_info(body: AlbumHashSchema):
|
||||
"""
|
||||
Get album and tracks
|
||||
@@ -79,7 +80,7 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
|
||||
}
|
||||
|
||||
|
||||
@api.get("/album/<albumhash>/tracks")
|
||||
@api.get("/<albumhash>/tracks")
|
||||
def get_album_tracks(path: AlbumHashSchema):
|
||||
"""
|
||||
Get album tracks
|
||||
@@ -106,7 +107,7 @@ class GetMoreFromArtistsBody(AlbumLimitSchema):
|
||||
)
|
||||
|
||||
|
||||
@api.post("/album/from-artist")
|
||||
@api.post("/from-artist")
|
||||
def get_more_from_artist(body: GetMoreFromArtistsBody):
|
||||
"""
|
||||
Get more from artist
|
||||
@@ -152,7 +153,7 @@ class GetAlbumVersionsBody(ArtistHashSchema):
|
||||
)
|
||||
|
||||
|
||||
@api.post("/album/other-versions")
|
||||
@api.post("/other-versions")
|
||||
def get_album_versions(body: GetAlbumVersionsBody):
|
||||
"""
|
||||
Get other versions
|
||||
@@ -183,7 +184,7 @@ class GetSimilarAlbumsQuery(ArtistHashSchema, AlbumLimitSchema):
|
||||
pass
|
||||
|
||||
|
||||
@api.get("/album/similar")
|
||||
@api.get("/similar")
|
||||
def get_similar_albums(query: GetSimilarAlbumsQuery):
|
||||
"""
|
||||
Get similar albums
|
||||
|
||||
+17
-5
@@ -7,7 +7,6 @@ from pydantic import BaseModel, Field
|
||||
from app.settings import Defaults
|
||||
|
||||
|
||||
|
||||
class AlbumHashSchema(BaseModel):
|
||||
"""
|
||||
Extending this class will give you a model with the `albumhash` field
|
||||
@@ -34,6 +33,19 @@ class ArtistHashSchema(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class TrackHashSchema(BaseModel):
|
||||
"""
|
||||
Extending this class will give you a model with the `trackhash` field
|
||||
"""
|
||||
|
||||
trackhash: str = Field(
|
||||
description="The track hash",
|
||||
example=Defaults.API_TRACKHASH,
|
||||
min_length=Defaults.HASH_LENGTH,
|
||||
max_length=Defaults.HASH_LENGTH,
|
||||
)
|
||||
|
||||
|
||||
class GenericLimitSchema(BaseModel):
|
||||
"""
|
||||
Extending this class will give you a model with the `limit` field
|
||||
@@ -42,7 +54,7 @@ class GenericLimitSchema(BaseModel):
|
||||
limit: int = Field(
|
||||
description="The number of items to return",
|
||||
example=Defaults.API_CARD_LIMIT,
|
||||
default=Defaults.API_CARD_LIMIT
|
||||
default=Defaults.API_CARD_LIMIT,
|
||||
)
|
||||
|
||||
|
||||
@@ -55,7 +67,7 @@ class TrackLimitSchema(BaseModel):
|
||||
limit: int = Field(
|
||||
description="The number of tracks to return",
|
||||
example=Defaults.API_CARD_LIMIT,
|
||||
default=Defaults.API_CARD_LIMIT
|
||||
default=Defaults.API_CARD_LIMIT,
|
||||
)
|
||||
|
||||
|
||||
@@ -67,7 +79,7 @@ class AlbumLimitSchema(BaseModel):
|
||||
limit: int = Field(
|
||||
description="The number of albums to return",
|
||||
example=Defaults.API_CARD_LIMIT,
|
||||
default=Defaults.API_CARD_LIMIT
|
||||
default=Defaults.API_CARD_LIMIT,
|
||||
)
|
||||
|
||||
|
||||
@@ -79,5 +91,5 @@ class ArtistLimitSchema(BaseModel):
|
||||
limit: int = Field(
|
||||
description="The number of artists to return",
|
||||
example=Defaults.API_CARD_LIMIT,
|
||||
default=Defaults.API_CARD_LIMIT
|
||||
default=Defaults.API_CARD_LIMIT,
|
||||
)
|
||||
|
||||
+6
-7
@@ -6,9 +6,8 @@ import math
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
from flask import request
|
||||
from flask_openapi3 import APIBlueprint, Tag
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import Field
|
||||
from app.api.apischemas import AlbumLimitSchema, ArtistHashSchema, ArtistLimitSchema, TrackLimitSchema
|
||||
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
@@ -21,10 +20,10 @@ from app.store.artists import ArtistStore
|
||||
from app.store.tracks import TrackStore
|
||||
|
||||
bp_tag = Tag(name="Artist", description="Single artist")
|
||||
api = APIBlueprint("artist", __name__, url_prefix="/", abp_tags=[bp_tag])
|
||||
api = APIBlueprint("artist", __name__, url_prefix="/artist", abp_tags=[bp_tag])
|
||||
|
||||
|
||||
@api.get("/artist/<string:artisthash>")
|
||||
@api.get("/<string:artisthash>")
|
||||
def get_artist(path: ArtistHashSchema, query: TrackLimitSchema):
|
||||
"""
|
||||
Get artist data.
|
||||
@@ -88,7 +87,7 @@ class GetArtistAlbumsQuery(AlbumLimitSchema):
|
||||
)
|
||||
|
||||
|
||||
@api.get("/artist/<artisthash>/albums")
|
||||
@api.get("/<artisthash>/albums")
|
||||
def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
|
||||
return_all = query.all
|
||||
artisthash = path.artisthash
|
||||
@@ -175,7 +174,7 @@ def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
|
||||
}
|
||||
|
||||
|
||||
@api.get("/artist/<artisthash>/tracks")
|
||||
@api.get("/<artisthash>/tracks")
|
||||
def get_all_artist_tracks(path: ArtistHashSchema):
|
||||
"""
|
||||
Get all artist tracks
|
||||
@@ -187,7 +186,7 @@ def get_all_artist_tracks(path: ArtistHashSchema):
|
||||
return {"tracks": serialize_tracks(tracks)}
|
||||
|
||||
|
||||
@api.get("/artist/<artisthash>/similar")
|
||||
@api.get("/<artisthash>/similar")
|
||||
def get_similar_artists(path: ArtistHashSchema, query: ArtistLimitSchema):
|
||||
"""
|
||||
Returns similar artists.
|
||||
|
||||
+43
-15
@@ -1,30 +1,43 @@
|
||||
"""
|
||||
Contains all the track routes.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from flask import Blueprint, send_file, request
|
||||
from flask_openapi3 import APIBlueprint, Tag
|
||||
from pydantic import BaseModel, Field
|
||||
from app.api.apischemas import TrackHashSchema
|
||||
from app.lib.trackslib import get_silence_paddings
|
||||
|
||||
from app.store.tracks import TrackStore
|
||||
|
||||
api = Blueprint("track", __name__, url_prefix="/")
|
||||
bp_tag = Tag(name="File", description="Single artist")
|
||||
api = APIBlueprint("track", __name__, url_prefix="/file", abp_tags=[bp_tag])
|
||||
|
||||
|
||||
@api.route("/file/<trackhash>")
|
||||
def send_track_file(trackhash: str):
|
||||
class SendTrackFileQuery(BaseModel):
|
||||
filepath: str = Field(
|
||||
description="The filepath to play (if available)", default=None
|
||||
)
|
||||
|
||||
|
||||
@api.get("/<trackhash>")
|
||||
def send_track_file(path: TrackHashSchema, query: SendTrackFileQuery):
|
||||
"""
|
||||
Returns an audio file that matches the passed id to the client.
|
||||
Falls back to track hash if id is not found.
|
||||
Get file
|
||||
|
||||
Returns a playable audio file that corresponds to the given filepath. Falls back to track hash if filepath is not found.
|
||||
"""
|
||||
trackhash = path.trackhash
|
||||
filepath = query.filepath
|
||||
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 provide, try to send that
|
||||
if filepath is not None:
|
||||
try:
|
||||
track = TrackStore.get_tracks_by_filepaths([filepath])[0]
|
||||
@@ -37,9 +50,7 @@ def send_track_file(trackhash: str):
|
||||
audio_type = get_mime(filepath)
|
||||
return send_file(filepath, mimetype=audio_type)
|
||||
|
||||
if trackhash is None:
|
||||
return msg, 404
|
||||
|
||||
# Else, find file by trackhash
|
||||
tracks = TrackStore.get_tracks_by_trackhashes([trackhash])
|
||||
|
||||
for track in tracks:
|
||||
@@ -56,11 +67,28 @@ def send_track_file(trackhash: str):
|
||||
return msg, 404
|
||||
|
||||
|
||||
@api.route("/file/silence", methods=["POST"])
|
||||
def get_audio_silence():
|
||||
data = request.get_json()
|
||||
ending_file = data.get("end", None) # ending file's filepath
|
||||
starting_file = data.get("start", None) # starting file's filepath
|
||||
class GetAudioSilenceBody(BaseModel):
|
||||
ending_file: str = Field(
|
||||
description="The ending file's path",
|
||||
example="/home/cwilvx/Music/Made in Kenya/Sol generation/Bensoul - Salama.mp3",
|
||||
)
|
||||
starting_file: str = Field(
|
||||
description="The beginning file's path",
|
||||
example="/home/cwilvx/Music/Tidal/Albums/Bensoul - Qwarantunes/Bensoul - Peddi.m4a",
|
||||
)
|
||||
|
||||
|
||||
@api.post("/silence")
|
||||
def get_audio_silence(body: GetAudioSilenceBody):
|
||||
"""
|
||||
Get silence paddings
|
||||
|
||||
Returns the duration of silence at the end of the current ending track and the duration of silence at the beginning of the next track.
|
||||
|
||||
NOTE: Durations are in milliseconds.
|
||||
"""
|
||||
ending_file = body.ending_file # ending file's filepath
|
||||
starting_file = body.starting_file # starting file's filepath
|
||||
|
||||
if ending_file is None or starting_file is None:
|
||||
return {"msg": "No filepath provided"}, 400
|
||||
|
||||
Reference in New Issue
Block a user