add api docs for streaming routes

+ add trackhash schema
This commit is contained in:
mungai-njoroge
2024-03-04 02:22:25 +03:00
committed by Mungai Njoroge
parent 7d064a8562
commit fb635ff35f
7 changed files with 87 additions and 45 deletions
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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