mirror of
https://github.com/JuLi0n21/pwa-player.git
synced 2026-04-19 15:30:05 +00:00
use grpc and grpc gateway
This commit is contained in:
@@ -15,6 +15,8 @@ PROTOC_GEN_OPENAPIV2 ?= protoc-gen-openapiv2
|
|||||||
all: generate
|
all: generate
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
|
cp ../osu_music.proto proto/osu_music.proto
|
||||||
|
|
||||||
$(PROTOC) \
|
$(PROTOC) \
|
||||||
-I $(PROTO_DIR) \
|
-I $(PROTO_DIR) \
|
||||||
-I $(GOOGLEAPIS_DIR) \
|
-I $(GOOGLEAPIS_DIR) \
|
||||||
@@ -27,4 +29,4 @@ generate:
|
|||||||
clean:
|
clean:
|
||||||
rm -rf $(OUT_DIR)
|
rm -rf $(OUT_DIR)
|
||||||
|
|
||||||
.PHONY: all generate clean
|
.PHONY: all generate clean
|
||||||
|
|||||||
@@ -1,683 +0,0 @@
|
|||||||
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
|
||||||
package docs
|
|
||||||
|
|
||||||
import "github.com/swaggo/swag"
|
|
||||||
|
|
||||||
const docTemplate = `{
|
|
||||||
"schemes": {{ marshal .Schemes }},
|
|
||||||
"swagger": "2.0",
|
|
||||||
"info": {
|
|
||||||
"description": "{{escape .Description}}",
|
|
||||||
"title": "{{.Title}}",
|
|
||||||
"contact": {},
|
|
||||||
"version": "{{.Version}}"
|
|
||||||
},
|
|
||||||
"host": "{{.Host}}",
|
|
||||||
"basePath": "{{.BasePath}}",
|
|
||||||
"paths": {
|
|
||||||
"/audio/{filepath}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves a song file from the server based on the provided encoded filepath",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"files"
|
|
||||||
],
|
|
||||||
"summary": "Retrieves a song file by its encoded path",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Base64 encoded file path",
|
|
||||||
"name": "filepath",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "The requested song file",
|
|
||||||
"schema": {
|
|
||||||
"type": "file"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "File Not Found",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/collection": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves a collection of songs using the provided index.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a collection of songs by index",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"description": "Index",
|
|
||||||
"name": "index",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Index",
|
|
||||||
"name": "name",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid parameter",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/image/{filepath}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves an image file from the server based on the provided encoded filepath",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"files"
|
|
||||||
],
|
|
||||||
"summary": "Retrieves an image file by its encoded path",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Base64 encoded file path",
|
|
||||||
"name": "filepath",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "The requested image file",
|
|
||||||
"schema": {
|
|
||||||
"type": "file"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "File Not Found",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/login": {
|
|
||||||
"get": {
|
|
||||||
"description": "Redirects users to an external authentication page",
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"summary": "Redirect to login page",
|
|
||||||
"responses": {
|
|
||||||
"307": {
|
|
||||||
"description": "Temporary Redirect",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/ping": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a pong response if the server is running",
|
|
||||||
"tags": [
|
|
||||||
"health"
|
|
||||||
],
|
|
||||||
"summary": "Check server health",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "pong",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/search/active": {
|
|
||||||
"get": {
|
|
||||||
"description": "Searches active records in the database based on the query parameter",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"search"
|
|
||||||
],
|
|
||||||
"summary": "Searches active records based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit the number of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset for pagination",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Active search result",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/main.ActiveSearch"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/search/artist": {
|
|
||||||
"get": {
|
|
||||||
"description": "Searches for artists in the database based on the query parameter",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"search"
|
|
||||||
],
|
|
||||||
"summary": "Searches for artists based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit the number of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset for pagination",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "List of artists",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/main.Artist"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/search/collections": {
|
|
||||||
"get": {
|
|
||||||
"description": "Searches collections in the database based on the query parameter",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"search"
|
|
||||||
],
|
|
||||||
"summary": "Searches collections based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit the number of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset for pagination",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "List of collections",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Collection"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/song/{hash}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves a song using its unique hash identifier.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a song by its hash",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Song hash",
|
|
||||||
"name": "hash",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid parameter",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Song not found",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/songs/artist": {
|
|
||||||
"get": {
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Returns all the Songs of a specific Artist",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Artist Name",
|
|
||||||
"name": "artist",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/songs/favorites": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves favorite songs filtered by a query with pagination support.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a list of favorite songs based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid parameter",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/songs/recents": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves recent songs with pagination support.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a list of recent songs",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"definitions": {
|
|
||||||
"main.ActiveSearch": {
|
|
||||||
"description": "ActiveSearch holds search results for a given artist",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"artist": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Ed Sheeran"
|
|
||||||
},
|
|
||||||
"songs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"main.Artist": {
|
|
||||||
"description": "Artist holds search results for a given artist",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"artist": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Miku"
|
|
||||||
},
|
|
||||||
"count": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 21
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"main.Collection": {
|
|
||||||
"description": "Collection holds a list of songs",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"items": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 15
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Best of 2023"
|
|
||||||
},
|
|
||||||
"songs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"main.Song": {
|
|
||||||
"description": "Song represents a song with metadata",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"artist": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Ed Sheeran"
|
|
||||||
},
|
|
||||||
"audio": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "audio.mp3"
|
|
||||||
},
|
|
||||||
"beatmap_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 123456
|
|
||||||
},
|
|
||||||
"creator": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "JohnDoe"
|
|
||||||
},
|
|
||||||
"file": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "beatmap.osu"
|
|
||||||
},
|
|
||||||
"folder": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "osu/Songs/123456"
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "cover.jpg"
|
|
||||||
},
|
|
||||||
"md5_hash": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "abcd1234efgh5678"
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Shape of You"
|
|
||||||
},
|
|
||||||
"total_time": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 240
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
|
||||||
var SwaggerInfo = &swag.Spec{
|
|
||||||
Version: "",
|
|
||||||
Host: "",
|
|
||||||
BasePath: "",
|
|
||||||
Schemes: []string{},
|
|
||||||
Title: "",
|
|
||||||
Description: "",
|
|
||||||
InfoInstanceName: "swagger",
|
|
||||||
SwaggerTemplate: docTemplate,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
|
||||||
}
|
|
||||||
@@ -1,656 +0,0 @@
|
|||||||
{
|
|
||||||
"swagger": "2.0",
|
|
||||||
"info": {
|
|
||||||
"contact": {}
|
|
||||||
},
|
|
||||||
"paths": {
|
|
||||||
"/audio/{filepath}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves a song file from the server based on the provided encoded filepath",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"files"
|
|
||||||
],
|
|
||||||
"summary": "Retrieves a song file by its encoded path",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Base64 encoded file path",
|
|
||||||
"name": "filepath",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "The requested song file",
|
|
||||||
"schema": {
|
|
||||||
"type": "file"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "File Not Found",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/collection": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves a collection of songs using the provided index.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a collection of songs by index",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"description": "Index",
|
|
||||||
"name": "index",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Index",
|
|
||||||
"name": "name",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid parameter",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/image/{filepath}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves an image file from the server based on the provided encoded filepath",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"files"
|
|
||||||
],
|
|
||||||
"summary": "Retrieves an image file by its encoded path",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Base64 encoded file path",
|
|
||||||
"name": "filepath",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "The requested image file",
|
|
||||||
"schema": {
|
|
||||||
"type": "file"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "File Not Found",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/login": {
|
|
||||||
"get": {
|
|
||||||
"description": "Redirects users to an external authentication page",
|
|
||||||
"tags": [
|
|
||||||
"auth"
|
|
||||||
],
|
|
||||||
"summary": "Redirect to login page",
|
|
||||||
"responses": {
|
|
||||||
"307": {
|
|
||||||
"description": "Temporary Redirect",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/ping": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a pong response if the server is running",
|
|
||||||
"tags": [
|
|
||||||
"health"
|
|
||||||
],
|
|
||||||
"summary": "Check server health",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "pong",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/search/active": {
|
|
||||||
"get": {
|
|
||||||
"description": "Searches active records in the database based on the query parameter",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"search"
|
|
||||||
],
|
|
||||||
"summary": "Searches active records based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit the number of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset for pagination",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Active search result",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/main.ActiveSearch"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/search/artist": {
|
|
||||||
"get": {
|
|
||||||
"description": "Searches for artists in the database based on the query parameter",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"search"
|
|
||||||
],
|
|
||||||
"summary": "Searches for artists based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit the number of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset for pagination",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "List of artists",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/main.Artist"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/search/collections": {
|
|
||||||
"get": {
|
|
||||||
"description": "Searches collections in the database based on the query parameter",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"search"
|
|
||||||
],
|
|
||||||
"summary": "Searches collections based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit the number of results",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset for pagination",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "List of collections",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Collection"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/song/{hash}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves a song using its unique hash identifier.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a song by its hash",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Song hash",
|
|
||||||
"name": "hash",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid parameter",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Song not found",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/songs/artist": {
|
|
||||||
"get": {
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Returns all the Songs of a specific Artist",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Artist Name",
|
|
||||||
"name": "artist",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/songs/favorites": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves favorite songs filtered by a query with pagination support.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a list of favorite songs based on a query",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Search query",
|
|
||||||
"name": "query",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid parameter",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/songs/recents": {
|
|
||||||
"get": {
|
|
||||||
"description": "Retrieves recent songs with pagination support.",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"songs"
|
|
||||||
],
|
|
||||||
"summary": "Get a list of recent songs",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 10,
|
|
||||||
"description": "Limit",
|
|
||||||
"name": "limit",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"default": 0,
|
|
||||||
"description": "Offset",
|
|
||||||
"name": "offset",
|
|
||||||
"in": "query"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"definitions": {
|
|
||||||
"main.ActiveSearch": {
|
|
||||||
"description": "ActiveSearch holds search results for a given artist",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"artist": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Ed Sheeran"
|
|
||||||
},
|
|
||||||
"songs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"main.Artist": {
|
|
||||||
"description": "Artist holds search results for a given artist",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"artist": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Miku"
|
|
||||||
},
|
|
||||||
"count": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 21
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"main.Collection": {
|
|
||||||
"description": "Collection holds a list of songs",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"items": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 15
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Best of 2023"
|
|
||||||
},
|
|
||||||
"songs": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/main.Song"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"main.Song": {
|
|
||||||
"description": "Song represents a song with metadata",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"artist": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Ed Sheeran"
|
|
||||||
},
|
|
||||||
"audio": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "audio.mp3"
|
|
||||||
},
|
|
||||||
"beatmap_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 123456
|
|
||||||
},
|
|
||||||
"creator": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "JohnDoe"
|
|
||||||
},
|
|
||||||
"file": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "beatmap.osu"
|
|
||||||
},
|
|
||||||
"folder": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "osu/Songs/123456"
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "cover.jpg"
|
|
||||||
},
|
|
||||||
"md5_hash": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "abcd1234efgh5678"
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Shape of You"
|
|
||||||
},
|
|
||||||
"total_time": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 240
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,441 +0,0 @@
|
|||||||
definitions:
|
|
||||||
main.ActiveSearch:
|
|
||||||
description: ActiveSearch holds search results for a given artist
|
|
||||||
properties:
|
|
||||||
artist:
|
|
||||||
example: Ed Sheeran
|
|
||||||
type: string
|
|
||||||
songs:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
main.Artist:
|
|
||||||
description: Artist holds search results for a given artist
|
|
||||||
properties:
|
|
||||||
artist:
|
|
||||||
example: Miku
|
|
||||||
type: string
|
|
||||||
count:
|
|
||||||
example: 21
|
|
||||||
type: integer
|
|
||||||
type: object
|
|
||||||
main.Collection:
|
|
||||||
description: Collection holds a list of songs
|
|
||||||
properties:
|
|
||||||
items:
|
|
||||||
example: 15
|
|
||||||
type: integer
|
|
||||||
name:
|
|
||||||
example: Best of 2023
|
|
||||||
type: string
|
|
||||||
songs:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
main.Song:
|
|
||||||
description: Song represents a song with metadata
|
|
||||||
properties:
|
|
||||||
artist:
|
|
||||||
example: Ed Sheeran
|
|
||||||
type: string
|
|
||||||
audio:
|
|
||||||
example: audio.mp3
|
|
||||||
type: string
|
|
||||||
beatmap_id:
|
|
||||||
example: 123456
|
|
||||||
type: integer
|
|
||||||
creator:
|
|
||||||
example: JohnDoe
|
|
||||||
type: string
|
|
||||||
file:
|
|
||||||
example: beatmap.osu
|
|
||||||
type: string
|
|
||||||
folder:
|
|
||||||
example: osu/Songs/123456
|
|
||||||
type: string
|
|
||||||
image:
|
|
||||||
example: cover.jpg
|
|
||||||
type: string
|
|
||||||
md5_hash:
|
|
||||||
example: abcd1234efgh5678
|
|
||||||
type: string
|
|
||||||
title:
|
|
||||||
example: Shape of You
|
|
||||||
type: string
|
|
||||||
total_time:
|
|
||||||
example: 240
|
|
||||||
type: integer
|
|
||||||
type: object
|
|
||||||
info:
|
|
||||||
contact: {}
|
|
||||||
paths:
|
|
||||||
/audio/{filepath}:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Retrieves a song file from the server based on the provided encoded
|
|
||||||
filepath
|
|
||||||
parameters:
|
|
||||||
- description: Base64 encoded file path
|
|
||||||
in: path
|
|
||||||
name: filepath
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The requested song file
|
|
||||||
schema:
|
|
||||||
type: file
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"404":
|
|
||||||
description: File Not Found
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Retrieves a song file by its encoded path
|
|
||||||
tags:
|
|
||||||
- files
|
|
||||||
/collection:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Retrieves a collection of songs using the provided index.
|
|
||||||
parameters:
|
|
||||||
- description: Index
|
|
||||||
in: query
|
|
||||||
name: index
|
|
||||||
type: integer
|
|
||||||
- description: Index
|
|
||||||
in: query
|
|
||||||
name: name
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
type: array
|
|
||||||
"400":
|
|
||||||
description: Invalid parameter
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Get a collection of songs by index
|
|
||||||
tags:
|
|
||||||
- songs
|
|
||||||
/image/{filepath}:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Retrieves an image file from the server based on the provided encoded
|
|
||||||
filepath
|
|
||||||
parameters:
|
|
||||||
- description: Base64 encoded file path
|
|
||||||
in: path
|
|
||||||
name: filepath
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: The requested image file
|
|
||||||
schema:
|
|
||||||
type: file
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"404":
|
|
||||||
description: File Not Found
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Retrieves an image file by its encoded path
|
|
||||||
tags:
|
|
||||||
- files
|
|
||||||
/login:
|
|
||||||
get:
|
|
||||||
description: Redirects users to an external authentication page
|
|
||||||
responses:
|
|
||||||
"307":
|
|
||||||
description: Temporary Redirect
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Redirect to login page
|
|
||||||
tags:
|
|
||||||
- auth
|
|
||||||
/ping:
|
|
||||||
get:
|
|
||||||
description: Returns a pong response if the server is running
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: pong
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Check server health
|
|
||||||
tags:
|
|
||||||
- health
|
|
||||||
/search/active:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Searches active records in the database based on the query parameter
|
|
||||||
parameters:
|
|
||||||
- description: Search query
|
|
||||||
in: query
|
|
||||||
name: query
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- default: 10
|
|
||||||
description: Limit the number of results
|
|
||||||
in: query
|
|
||||||
name: limit
|
|
||||||
type: integer
|
|
||||||
- default: 0
|
|
||||||
description: Offset for pagination
|
|
||||||
in: query
|
|
||||||
name: offset
|
|
||||||
type: integer
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Active search result
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/main.ActiveSearch'
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Searches active records based on a query
|
|
||||||
tags:
|
|
||||||
- search
|
|
||||||
/search/artist:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Searches for artists in the database based on the query parameter
|
|
||||||
parameters:
|
|
||||||
- description: Search query
|
|
||||||
in: query
|
|
||||||
name: query
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- default: 10
|
|
||||||
description: Limit the number of results
|
|
||||||
in: query
|
|
||||||
name: limit
|
|
||||||
type: integer
|
|
||||||
- default: 0
|
|
||||||
description: Offset for pagination
|
|
||||||
in: query
|
|
||||||
name: offset
|
|
||||||
type: integer
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: List of artists
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/main.Artist'
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Searches for artists based on a query
|
|
||||||
tags:
|
|
||||||
- search
|
|
||||||
/search/collections:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Searches collections in the database based on the query parameter
|
|
||||||
parameters:
|
|
||||||
- description: Search query
|
|
||||||
in: query
|
|
||||||
name: query
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- default: 10
|
|
||||||
description: Limit the number of results
|
|
||||||
in: query
|
|
||||||
name: limit
|
|
||||||
type: integer
|
|
||||||
- default: 0
|
|
||||||
description: Offset for pagination
|
|
||||||
in: query
|
|
||||||
name: offset
|
|
||||||
type: integer
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: List of collections
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Collection'
|
|
||||||
type: array
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Searches collections based on a query
|
|
||||||
tags:
|
|
||||||
- search
|
|
||||||
/song/{hash}:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Retrieves a song using its unique hash identifier.
|
|
||||||
parameters:
|
|
||||||
- description: Song hash
|
|
||||||
in: path
|
|
||||||
name: hash
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
"400":
|
|
||||||
description: Invalid parameter
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"404":
|
|
||||||
description: Song not found
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Get a song by its hash
|
|
||||||
tags:
|
|
||||||
- songs
|
|
||||||
/songs/artist:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
parameters:
|
|
||||||
- description: Artist Name
|
|
||||||
in: query
|
|
||||||
name: artist
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
type: array
|
|
||||||
"400":
|
|
||||||
description: Bad Request
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Returns all the Songs of a specific Artist
|
|
||||||
tags:
|
|
||||||
- songs
|
|
||||||
/songs/favorites:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Retrieves favorite songs filtered by a query with pagination support.
|
|
||||||
parameters:
|
|
||||||
- description: Search query
|
|
||||||
in: query
|
|
||||||
name: query
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- default: 10
|
|
||||||
description: Limit
|
|
||||||
in: query
|
|
||||||
name: limit
|
|
||||||
type: integer
|
|
||||||
- default: 0
|
|
||||||
description: Offset
|
|
||||||
in: query
|
|
||||||
name: offset
|
|
||||||
type: integer
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
type: array
|
|
||||||
"400":
|
|
||||||
description: Invalid parameter
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Get a list of favorite songs based on a query
|
|
||||||
tags:
|
|
||||||
- songs
|
|
||||||
/songs/recents:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Retrieves recent songs with pagination support.
|
|
||||||
parameters:
|
|
||||||
- default: 10
|
|
||||||
description: Limit
|
|
||||||
in: query
|
|
||||||
name: limit
|
|
||||||
type: integer
|
|
||||||
- default: 0
|
|
||||||
description: Offset
|
|
||||||
in: query
|
|
||||||
name: offset
|
|
||||||
type: integer
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/main.Song'
|
|
||||||
type: array
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
summary: Get a list of recent songs
|
|
||||||
tags:
|
|
||||||
- songs
|
|
||||||
swagger: "2.0"
|
|
||||||
580
grpc-backend/gen/swagger/osu_music.swagger.json
Normal file
580
grpc-backend/gen/swagger/osu_music.swagger.json
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"title": "osu_music.proto",
|
||||||
|
"version": "version not set"
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "MusicBackend"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/api/v1/artist/{artist}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Artist",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1ArtistResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "artist",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/collections": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Collections",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1CollectionResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/favorites": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Favorite",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1FavoriteResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "query",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/recent": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Recent",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1RecentResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/search": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Search",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SearchSharedResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "query",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/search/artists": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_SearchArtists",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SearchArtistResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "query",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/search/collections": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_SearchCollections",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SearchCollectionResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "query",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/song/{hash}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Song",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1SongResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "hash",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ping": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MusicBackend_Ping",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1PingResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "ping",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MusicBackend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"apiv1Artist": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"artist": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apiv1Song": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"beatmapId": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"md5Hash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"artist": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"creator": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"folder": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"audio": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"totalTime": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "===== models ====="
|
||||||
|
},
|
||||||
|
"protobufAny": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"@type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": {}
|
||||||
|
},
|
||||||
|
"rpcStatus": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/protobufAny"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1ArtistResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"songs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/apiv1Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1CollectionPreview": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1CollectionResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"songs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/apiv1Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1FavoriteResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"songs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/apiv1Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1PingResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"pong": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1RecentResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"songs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/apiv1Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1SearchArtistResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Artists": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/apiv1Artist"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1SearchCollectionResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"collections": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/v1CollectionPreview"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1SearchSharedResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"artist": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"songs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/apiv1Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1SongResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"song": {
|
||||||
|
"$ref": "#/definitions/apiv1Song"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@ require (
|
|||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/juli0n21/go-osu-parser v0.0.8
|
github.com/juli0n21/go-osu-parser v0.0.8
|
||||||
github.com/swaggo/http-swagger v1.3.4
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237
|
||||||
google.golang.org/grpc v1.72.1
|
google.golang.org/grpc v1.72.1
|
||||||
google.golang.org/protobuf v1.36.6
|
google.golang.org/protobuf v1.36.6
|
||||||
@@ -16,28 +15,16 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
|
||||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
|
||||||
github.com/go-openapi/spec v0.20.6 // indirect
|
|
||||||
github.com/go-openapi/swag v0.19.15 // indirect
|
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
|
||||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
|
|
||||||
github.com/swaggo/swag v1.8.1 // indirect
|
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/net v0.37.0 // indirect
|
golang.org/x/net v0.37.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
golang.org/x/tools v0.31.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
|
||||||
modernc.org/libc v1.62.1 // indirect
|
modernc.org/libc v1.62.1 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.9.1 // indirect
|
modernc.org/memory v1.9.1 // indirect
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
|
||||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
|
||||||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
|
||||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
|
||||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
|
||||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
|
||||||
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
|
|
||||||
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
|
||||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
@@ -34,45 +16,14 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5uk
|
|||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
|
||||||
github.com/juli0n21/go-osu-parser v0.0.8 h1:aQtuhAniGvpUw446arhq/3aUOK9YvZEkL7aYUGlViAo=
|
github.com/juli0n21/go-osu-parser v0.0.8 h1:aQtuhAniGvpUw446arhq/3aUOK9YvZEkL7aYUGlViAo=
|
||||||
github.com/juli0n21/go-osu-parser v0.0.8/go.mod h1:oLLWnZReOMW4i5aNva/zvXsFqzdQigrbjyxOSs0cx+0=
|
github.com/juli0n21/go-osu-parser v0.0.8/go.mod h1:oLLWnZReOMW4i5aNva/zvXsFqzdQigrbjyxOSs0cx+0=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
|
||||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
|
||||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc=
|
|
||||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
|
|
||||||
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
|
|
||||||
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
|
|
||||||
github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=
|
|
||||||
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||||
@@ -89,21 +40,15 @@ golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE
|
|||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
||||||
@@ -114,18 +59,6 @@ google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
|||||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
|
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
|
||||||
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||||
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
|
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
_ "backend/docs"
|
|
||||||
v1 "backend/gen"
|
v1 "backend/gen"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
httpSwagger "github.com/swaggo/http-swagger"
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/juli0n21/go-osu-parser/parser"
|
"github.com/juli0n21/go-osu-parser/parser"
|
||||||
)
|
)
|
||||||
@@ -34,36 +33,15 @@ type Server struct {
|
|||||||
v1.UnimplementedMusicBackendServer
|
v1.UnimplementedMusicBackendServer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) registerRoutes() http.Handler {
|
func (s *Server) registerRoutes() *http.ServeMux {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
mux.HandleFunc("/api/v1/ping", s.ping)
|
|
||||||
mux.HandleFunc("/api/v1/login", s.login)
|
|
||||||
|
|
||||||
mux.HandleFunc("/api/v1/song/{hash}/", s.song)
|
|
||||||
mux.HandleFunc("/api/v1/songs/recent", s.recents)
|
|
||||||
mux.HandleFunc("/api/v1/songs/favorites", s.favorites)
|
|
||||||
mux.HandleFunc("/api/v1/songs/artist", s.aristsSongs)
|
|
||||||
|
|
||||||
mux.HandleFunc("/api/v1/collection", s.collection)
|
|
||||||
mux.HandleFunc("/api/v1/search/collections", s.collectionSearch)
|
|
||||||
|
|
||||||
mux.HandleFunc("/api/v1/search/active", s.activeSearch)
|
|
||||||
mux.HandleFunc("/api/v1/search/artist", s.artistSearch)
|
|
||||||
|
|
||||||
mux.HandleFunc("/api/v1/audio/{filepath}", s.songFile)
|
mux.HandleFunc("/api/v1/audio/{filepath}", s.songFile)
|
||||||
mux.HandleFunc("/api/v1/image/{filepath}", s.imageFile)
|
mux.HandleFunc("/api/v1/image/{filepath}", s.imageFile)
|
||||||
|
|
||||||
mux.HandleFunc("/api/v1/callback", s.callback)
|
mux.HandleFunc("/api/v1/callback", s.callback)
|
||||||
mux.Handle("/swagger/", httpSwagger.WrapHandler)
|
|
||||||
|
|
||||||
return corsMiddleware(logRequests(mux))
|
return mux
|
||||||
}
|
|
||||||
|
|
||||||
func run(s *Server) {
|
|
||||||
mux := s.registerRoutes()
|
|
||||||
fmt.Println("starting server on http://localhost" + s.Port)
|
|
||||||
log.Fatal(http.ListenAndServe(s.Port, mux))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func logRequests(next http.Handler) http.Handler {
|
func logRequests(next http.Handler) http.Handler {
|
||||||
@@ -88,273 +66,161 @@ func corsMiddleware(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ping godoc
|
func (s *Server) Ping(ctx context.Context, req *v1.PingRequest) (*v1.PingResponse, error) {
|
||||||
//
|
return &v1.PingResponse{Pong: "pong"}, nil
|
||||||
// @Summary Check server health
|
|
||||||
// @Description Returns a pong response if the server is running
|
|
||||||
// @Tags health
|
|
||||||
// @Success 200 {string} string "pong"
|
|
||||||
// @Router /ping [get]
|
|
||||||
func (s *Server) ping(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "pong")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// login godoc
|
|
||||||
//
|
|
||||||
// @Summary Redirect to login page
|
|
||||||
// @Description Redirects users to an external authentication page
|
|
||||||
// @Tags auth
|
|
||||||
// @Success 307 {string} string "Temporary Redirect"
|
|
||||||
// @Router /login [get]
|
|
||||||
func (s *Server) login(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) login(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "https://proxy.illegalesachen.download/login", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "https://proxy.illegalesachen.download/login", http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
// song godoc
|
func (s *Server) Song(ctx context.Context, req *v1.SongRequest) (*v1.SongResponse, error) {
|
||||||
//
|
|
||||||
// @Summary Get a song by its hash
|
|
||||||
// @Description Retrieves a song using its unique hash identifier.
|
|
||||||
// @Tags songs
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param hash path string true "Song hash"
|
|
||||||
// @Success 200 {object} Song
|
|
||||||
// @Failure 400 {string} string "Invalid parameter"
|
|
||||||
// @Failure 404 {string} string "Song not found"
|
|
||||||
// @Router /song/{hash} [get]
|
|
||||||
func (s *Server) song(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
hash := r.PathValue("hash")
|
hash := req.Hash
|
||||||
if hash == "" {
|
if hash == "" {
|
||||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
return nil, status.Errorf(codes.InvalidArgument, "hash is required and cant be empty")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
song, err := getSong(s.Db, hash)
|
song, err := getSong(s.Db, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
http.Error(w, "beatmap not found by hash", http.StatusNotFound)
|
return nil, status.Errorf(codes.NotFound, "beatmap not found by hash")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeJSON(w, song, http.StatusOK)
|
return &v1.SongResponse{
|
||||||
|
Song: song.toProto(),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// recents godoc
|
func (s *Server) Recent(ctx context.Context, req *v1.RecentRequest) (*v1.RecentResponse, error) {
|
||||||
//
|
|
||||||
// @Summary Get a list of recent songs
|
limit := defaultLimit(int(req.Limit))
|
||||||
// @Description Retrieves recent songs with pagination support.
|
offset := int(req.Offset)
|
||||||
// @Tags songs
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param limit query int false "Limit" default(10)
|
|
||||||
// @Param offset query int false "Offset" default(0)
|
|
||||||
// @Success 200 {array} Song
|
|
||||||
// @Failure 500 {string} string "Internal server error"
|
|
||||||
// @Router /songs/recents [get]
|
|
||||||
func (s *Server) recents(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
limit, offset := pagination(r)
|
|
||||||
recent, err := getRecent(s.Db, limit, offset)
|
recent, err := getRecent(s.Db, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return nil, status.Errorf(codes.Internal, "failed to get recents")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
writeJSON(w, recent, http.StatusOK)
|
|
||||||
|
return &v1.RecentResponse{
|
||||||
|
Songs: toProtoSongs(recent),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// favorites godoc
|
func (s *Server) Favorite(ctx context.Context, req *v1.FavoriteRequest) (*v1.FavoriteResponse, error) {
|
||||||
//
|
|
||||||
// @Summary Get a list of favorite songs based on a query
|
|
||||||
// @Description Retrieves favorite songs filtered by a query with pagination support.
|
|
||||||
// @Tags songs
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param query query string true "Search query"
|
|
||||||
// @Param limit query int false "Limit" default(10)
|
|
||||||
// @Param offset query int false "Offset" default(0)
|
|
||||||
// @Success 200 {array} Song
|
|
||||||
// @Failure 400 {string} string "Invalid parameter"
|
|
||||||
// @Failure 500 {string} string "Internal server error"
|
|
||||||
// @Router /songs/favorites [get]
|
|
||||||
func (s *Server) favorites(w http.ResponseWriter, r *http.Request) {
|
|
||||||
query := r.URL.Query().Get("query")
|
|
||||||
if query == "" {
|
|
||||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
limit, offset := pagination(r)
|
|
||||||
|
limit := defaultLimit(int(req.Limit))
|
||||||
favorites, err := getFavorites(s.Db, query, limit, offset)
|
offset := int(req.Offset)
|
||||||
|
favorites, err := getFavorites(s.Db, req.Query, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return nil, status.Errorf(codes.Internal, "failed to get favorites")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
writeJSON(w, favorites, http.StatusOK)
|
|
||||||
|
return &v1.FavoriteResponse{
|
||||||
|
Songs: toProtoSongs(favorites),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// collection godoc
|
func (s *Server) Collections(ctx context.Context, req *v1.CollectionRequest) (*v1.CollectionResponse, error) {
|
||||||
//
|
|
||||||
// @Summary Get a collection of songs by index
|
limit := defaultLimit(int(req.Limit))
|
||||||
// @Description Retrieves a collection of songs using the provided index.
|
offset := int(req.Offset)
|
||||||
// @Tags songs
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
name := req.Name
|
||||||
// @Param index query int false "Index"
|
|
||||||
// @Param name query string false "Index"
|
|
||||||
// @Success 200 {array} Song
|
|
||||||
// @Failure 400 {string} string "Invalid parameter"
|
|
||||||
// @Failure 500 {string} string "Internal server error"
|
|
||||||
// @Router /collection [get]
|
|
||||||
func (s *Server) collection(w http.ResponseWriter, r *http.Request) {
|
|
||||||
limit, offset := pagination(r)
|
|
||||||
name := r.URL.Query().Get("name")
|
|
||||||
if name != "" {
|
if name != "" {
|
||||||
c, err := getCollectionByName(s.Db, limit, offset, name)
|
c, err := getCollectionByName(s.Db, limit, offset, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
fmt.Println(err)
|
||||||
return
|
return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to fetch collection with name: %s", name))
|
||||||
}
|
}
|
||||||
writeJSON(w, c, http.StatusOK)
|
return &v1.CollectionResponse{
|
||||||
return
|
Songs: toProtoSongs(c.Songs),
|
||||||
|
Items: int32(c.Items),
|
||||||
|
Name: c.Name,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
index, err := strconv.Atoi(r.URL.Query().Get("index"))
|
c, err := getCollection(s.Db, limit, offset, int(req.Index))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
fmt.Println(err)
|
||||||
return
|
return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to fetch collection with index: %d", req.Index))
|
||||||
} else {
|
|
||||||
c, err := getCollection(s.Db, limit, offset, index)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeJSON(w, c, http.StatusOK)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
return &v1.CollectionResponse{
|
||||||
|
Songs: toProtoSongs(c.Songs),
|
||||||
|
Items: int32(c.Items),
|
||||||
|
Name: c.Name,
|
||||||
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Searches collections based on a query
|
func (s *Server) Search(ctx context.Context, req *v1.SearchSharedRequest) (*v1.SearchSharedResponse, error) {
|
||||||
// @Description Searches collections in the database based on the query parameter
|
q := req.Query
|
||||||
// @Tags search
|
if q == "" {
|
||||||
// @Accept json
|
return nil, status.Error(codes.InvalidArgument, "query cant be empty")
|
||||||
// @Produce json
|
}
|
||||||
// @Param query query string true "Search query"
|
|
||||||
// @Param limit query int false "Limit the number of results" default(10)
|
|
||||||
// @Param offset query int false "Offset for pagination" default(0)
|
|
||||||
// @Success 200 {array} Collection "List of collections"
|
|
||||||
// @Failure 400 {object} string "Bad Request"
|
|
||||||
// @Failure 500 {object} string "Internal Server Error"
|
|
||||||
// @Router /search/collections [get]
|
|
||||||
func (s *Server) collectionSearch(w http.ResponseWriter, r *http.Request) {
|
|
||||||
q := r.URL.Query().Get("query")
|
|
||||||
|
|
||||||
limit, offset := pagination(r)
|
|
||||||
|
limit := defaultLimit(int(req.Limit))
|
||||||
|
offset := int(req.Offset)
|
||||||
|
|
||||||
|
|
||||||
|
search, err := getSearch(s.Db, q, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return nil, status.Error(codes.Internal, "failed to fetch search")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &v1.SearchSharedResponse{
|
||||||
|
Artist: search.Artist,
|
||||||
|
Songs: toProtoSongs(search.Songs),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) SearchCollections(ctx context.Context, req *v1.SearchCollectionRequest) (*v1.SearchCollectionResponse, error) {
|
||||||
|
q := req.Query
|
||||||
|
if q == "" {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "query is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
limit := defaultLimit(int(req.Limit))
|
||||||
|
offset := int(req.Offset)
|
||||||
|
|
||||||
|
|
||||||
preview, err := getCollections(s.Db, q, limit, offset)
|
preview, err := getCollections(s.Db, q, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return nil, status.Errorf(codes.Internal, "failed to search for collections")
|
||||||
return
|
|
||||||
}
|
|
||||||
writeJSON(w, preview, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Summary Returns all the Songs of a specific Artist
|
|
||||||
// @Tags songs
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param artist query string true "Artist Name"
|
|
||||||
// @Success 200 {array} Song
|
|
||||||
// @Failure 400 {object} string "Bad Request"
|
|
||||||
// @Failure 500 {object} string "Internal Server Error"
|
|
||||||
// @Router /songs/artist [get]
|
|
||||||
func (s *Server) aristsSongs(w http.ResponseWriter, r *http.Request) {
|
|
||||||
artist := r.URL.Query().Get("artist")
|
|
||||||
if artist == "" {
|
|
||||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeJSON(w, []Song{}, http.StatusOK)
|
return &v1.SearchCollectionResponse{
|
||||||
|
Collections: toProtoCollectionPreview(preview),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Searches active records based on a query
|
func (s *Server) SearchArtists(ctx context.Context, req *v1.SearchArtistRequest) (*v1.SearchArtistResponse, error) {
|
||||||
// @Description Searches active records in the database based on the query parameter
|
q := req.Query
|
||||||
// @Tags search
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param query query string true "Search query"
|
|
||||||
// @Param limit query int false "Limit the number of results" default(10)
|
|
||||||
// @Param offset query int false "Offset for pagination" default(0)
|
|
||||||
// @Success 200 {object} ActiveSearch "Active search result"
|
|
||||||
// @Failure 400 {object} string "Bad Request"
|
|
||||||
// @Failure 500 {object} string "Internal Server Error"
|
|
||||||
// @Router /search/active [get]
|
|
||||||
func (s *Server) activeSearch(w http.ResponseWriter, r *http.Request) {
|
|
||||||
q := r.URL.Query().Get("query")
|
|
||||||
if q == "" {
|
if q == "" {
|
||||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
return nil, status.Error(codes.InvalidArgument, "query is required")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
limit := defaultLimit(int(req.Limit))
|
||||||
limit, offset := pagination(r)
|
offset := int(req.Offset)
|
||||||
|
|
||||||
recent, err := getSearch(s.Db, q, limit, offset)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeJSON(w, recent, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Summary Searches for artists based on a query
|
|
||||||
// @Description Searches for artists in the database based on the query parameter
|
|
||||||
// @Tags search
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param query query string true "Search query"
|
|
||||||
// @Param limit query int false "Limit the number of results" default(10)
|
|
||||||
// @Param offset query int false "Offset for pagination" default(0)
|
|
||||||
// @Success 200 {object} Artist "List of artists"
|
|
||||||
// @Failure 400 {object} string "Bad Request"
|
|
||||||
// @Failure 500 {object} string "Internal Server Error"
|
|
||||||
// @Router /search/artist [get]
|
|
||||||
func (s *Server) artistSearch(w http.ResponseWriter, r *http.Request) {
|
|
||||||
q := r.URL.Query().Get("query")
|
|
||||||
if q == "" {
|
|
||||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
limit, offset := pagination(r)
|
|
||||||
|
|
||||||
a, err := getArtists(s.Db, q, limit, offset)
|
a, err := getArtists(s.Db, q, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return nil, status.Error(codes.Internal, "failed to search artists")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
writeJSON(w, a, http.StatusOK)
|
return &v1.SearchArtistResponse{
|
||||||
|
Artists: toProtoArtist(a),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Retrieves a song file by its encoded path
|
|
||||||
// @Description Retrieves a song file from the server based on the provided encoded filepath
|
|
||||||
// @Tags files
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param filepath path string true "Base64 encoded file path"
|
|
||||||
// @Success 200 {file} File "The requested song file"
|
|
||||||
// @Failure 400 {object} string "Bad Request"
|
|
||||||
// @Failure 404 {object} string "File Not Found"
|
|
||||||
// @Router /audio/{filepath} [get]
|
|
||||||
func (s *Server) songFile(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) songFile(w http.ResponseWriter, r *http.Request) {
|
||||||
f := r.PathValue("filepath")
|
f := r.PathValue("filepath")
|
||||||
if f == "" {
|
if f == "" {
|
||||||
@@ -387,16 +253,6 @@ func (s *Server) songFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.ServeContent(w, r, stat.Name(), stat.ModTime(), file)
|
http.ServeContent(w, r, stat.Name(), stat.ModTime(), file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Retrieves an image file by its encoded path
|
|
||||||
// @Description Retrieves an image file from the server based on the provided encoded filepath
|
|
||||||
// @Tags files
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param filepath path string true "Base64 encoded file path"
|
|
||||||
// @Success 200 {file} File "The requested image file"
|
|
||||||
// @Failure 400 {object} string "Bad Request"
|
|
||||||
// @Failure 404 {object} string "File Not Found"
|
|
||||||
// @Router /image/{filepath} [get]
|
|
||||||
func (s *Server) imageFile(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) imageFile(w http.ResponseWriter, r *http.Request) {
|
||||||
f := r.PathValue("filepath")
|
f := r.PathValue("filepath")
|
||||||
if f == "" {
|
if f == "" {
|
||||||
@@ -423,24 +279,9 @@ func (s *Server) callback(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeJSON(w http.ResponseWriter, v any, status int) {
|
func defaultLimit(limit int) int {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
if limit <= 0 || limit > 100 {
|
||||||
w.WriteHeader(status)
|
return 100
|
||||||
if err := json.NewEncoder(w).Encode(v); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
http.Error(w, "Failed to encode JSON response", http.StatusInternalServerError)
|
|
||||||
}
|
}
|
||||||
}
|
return limit
|
||||||
|
|
||||||
func pagination(r *http.Request) (int, int) {
|
|
||||||
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
|
||||||
if err != nil || limit <= 0 || limit > 100 {
|
|
||||||
limit = 100
|
|
||||||
}
|
|
||||||
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
|
||||||
if err != nil || offset < 0 {
|
|
||||||
offset = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return limit, offset
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ func main() {
|
|||||||
Env: envMap,
|
Env: envMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run gRPC + grpc-gateway servers
|
|
||||||
if err := runGrpcAndGateway(s, port); err != nil {
|
if err := runGrpcAndGateway(s, port); err != nil {
|
||||||
log.Fatalf("Failed to run servers: %v", err)
|
log.Fatalf("Failed to run servers: %v", err)
|
||||||
}
|
}
|
||||||
@@ -169,15 +168,15 @@ func sendUrl(endpoint, cookie string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runGrpcAndGateway(s *Server, port string) error {
|
func runGrpcAndGateway(s *Server, port string) error {
|
||||||
grpcPort := ":9090" // gRPC server port
|
grpcPort := ":9090"
|
||||||
httpPort := port // REST gateway port (e.g. ":8080")
|
httpPort := port
|
||||||
|
|
||||||
grpcLis, err := net.Listen("tcp", grpcPort)
|
grpcLis, err := net.Listen("tcp", grpcPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to listen on %s: %w", grpcPort, err)
|
return fmt.Errorf("failed to listen on %s: %w", grpcPort, err)
|
||||||
}
|
}
|
||||||
grpcServer := grpc.NewServer()
|
grpcServer := grpc.NewServer()
|
||||||
v1.RegisterMusicBackendServer(grpcServer, s) // Register your service implementation
|
v1.RegisterMusicBackendServer(grpcServer, s)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
@@ -191,20 +190,25 @@ func runGrpcAndGateway(s *Server, port string) error {
|
|||||||
return fmt.Errorf("failed to register grpc-gateway: %w", err)
|
return fmt.Errorf("failed to register grpc-gateway: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := &http.ServeMux{}
|
||||||
|
|
||||||
mux.Handle("/api/v1/", gwMux)
|
mux.HandleFunc("/callback/", s.callback)
|
||||||
|
mux.HandleFunc("api/v1/audio/{filepath}", s.songFile)
|
||||||
mux.HandleFunc("/files", s.songFile)
|
mux.HandleFunc("api/v1/image/{filepath}", s.imageFile)
|
||||||
|
|
||||||
fileServer := http.FileServer(http.Dir("gen/swagger"))
|
fileServer := http.FileServer(http.Dir("gen/swagger"))
|
||||||
mux.Handle("/swagger/", http.StripPrefix("/swagger/", fileServer))
|
mux.Handle("/swagger/", http.StripPrefix("/swagger/", fileServer))
|
||||||
|
|
||||||
httpServer := &http.Server{
|
httpServer := &http.Server{
|
||||||
Addr: httpPort,
|
Addr: httpPort,
|
||||||
Handler: mux,
|
Handler: corsMiddleware(logRequests(mux)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("HTTP %s %s", r.Method, r.URL.Path)
|
||||||
|
gwMux.ServeHTTP(w, r)
|
||||||
|
}))
|
||||||
|
|
||||||
stop := make(chan os.Signal, 1)
|
stop := make(chan os.Signal, 1)
|
||||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import v1 "backend/gen"
|
||||||
|
|
||||||
// Song represents a song entity
|
// Song represents a song entity
|
||||||
// @Description Song represents a song with metadata
|
// @Description Song represents a song with metadata
|
||||||
type Song struct {
|
type Song struct {
|
||||||
@@ -15,6 +17,30 @@ type Song struct {
|
|||||||
Image string `json:"image" example:"cover.jpg"`
|
Image string `json:"image" example:"cover.jpg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (song Song) toProto() *v1.Song {
|
||||||
|
return &v1.Song{
|
||||||
|
BeatmapId: int32(song.BeatmapID),
|
||||||
|
Md5Hash: song.MD5Hash,
|
||||||
|
Title: song.Title,
|
||||||
|
Artist: song.Artist,
|
||||||
|
Creator: song.Creator,
|
||||||
|
Folder: song.Folder,
|
||||||
|
File: song.File,
|
||||||
|
Audio: song.Audio,
|
||||||
|
TotalTime: song.TotalTime,
|
||||||
|
Image: song.Image,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toProtoSongs(local []Song) []*v1.Song {
|
||||||
|
songs := make([]*v1.Song, len(local))
|
||||||
|
for i, s := range local {
|
||||||
|
songs[i] = s.toProto()
|
||||||
|
}
|
||||||
|
|
||||||
|
return songs
|
||||||
|
}
|
||||||
|
|
||||||
// CollectionPreview represents a preview of a song collection
|
// CollectionPreview represents a preview of a song collection
|
||||||
// @Description CollectionPreview contains summary data of a song collection
|
// @Description CollectionPreview contains summary data of a song collection
|
||||||
type CollectionPreview struct {
|
type CollectionPreview struct {
|
||||||
@@ -23,6 +49,23 @@ type CollectionPreview struct {
|
|||||||
Items int `json:"items" example:"10"`
|
Items int `json:"items" example:"10"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c CollectionPreview) toProto() *v1.CollectionPreview {
|
||||||
|
return &v1.CollectionPreview{
|
||||||
|
Name: c.Name,
|
||||||
|
Image: c.Image,
|
||||||
|
Items: int32(c.Items),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toProtoCollectionPreview(local []CollectionPreview) []*v1.CollectionPreview {
|
||||||
|
collection := make([]*v1.CollectionPreview, len(local))
|
||||||
|
for i, c := range local {
|
||||||
|
collection[i] = c.toProto()
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
// Collection represents a full song collection
|
// Collection represents a full song collection
|
||||||
// @Description Collection holds a list of songs
|
// @Description Collection holds a list of songs
|
||||||
type Collection struct {
|
type Collection struct {
|
||||||
@@ -44,3 +87,19 @@ type Artist struct {
|
|||||||
Artist string `json:"artist" example:"Miku"`
|
Artist string `json:"artist" example:"Miku"`
|
||||||
Count int `json:"count" example:"21"`
|
Count int `json:"count" example:"21"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a Artist) toProto() *v1.Artist {
|
||||||
|
return &v1.Artist{
|
||||||
|
Artist: a.Artist,
|
||||||
|
Items: int32(a.Count),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toProtoArtist(local []Artist) []*v1.Artist {
|
||||||
|
artists := make([]*v1.Artist, len(local))
|
||||||
|
for i, a := range local {
|
||||||
|
artists[i] = a.toProto()
|
||||||
|
}
|
||||||
|
|
||||||
|
return artists
|
||||||
|
}
|
||||||
|
|||||||
46
grpc-backend/proto/file_specs.json
Normal file
46
grpc-backend/proto/file_specs.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"paths": {
|
||||||
|
"/api/v1/audio/{filepath}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Serve audio files (base64-encoded path)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "filepath",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Base64-encoded file path"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Audio file content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/image/{filepath}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Serve image files (base64-encoded path)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "filepath",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Base64-encoded file path"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Image file content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,49 +9,49 @@ import "google/api/annotations.proto";
|
|||||||
service MusicBackend {
|
service MusicBackend {
|
||||||
rpc Collections(CollectionRequest) returns (CollectionResponse) {
|
rpc Collections(CollectionRequest) returns (CollectionResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/collections"
|
get: "/api/v1/collections"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Song(SongRequest) returns (SongResponse){
|
rpc Song(SongRequest) returns (SongResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/song/{hash}"
|
get: "/api/v1/song/{hash}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Artist(ArtistRequest) returns (ArtistResponse){
|
rpc Artist(ArtistRequest) returns (ArtistResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/artist/{artist}"
|
get: "/api/v1/artist/{artist}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Favorite(FavoriteRequest) returns (FavoriteResponse){
|
rpc Favorite(FavoriteRequest) returns (FavoriteResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/favorites"
|
get: "/api/v1/favorites"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Recent(RecentRequest) returns (RecentResponse){
|
rpc Recent(RecentRequest) returns (RecentResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/recent"
|
get: "/api/v1/recent"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc Search(SearchSharedRequest) returns (SearchSharedResponse) {
|
rpc Search(SearchSharedRequest) returns (SearchSharedResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/search"
|
get: "/api/v1/search"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc SearchArtists(SearchArtistRequest) returns (SearchArtistResponse) {
|
rpc SearchArtists(SearchArtistRequest) returns (SearchArtistResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/search/artists"
|
get: "/api/v1/search/artists"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc SearchCollections(SearchCollectionRequest) returns (SearchCollectionResponse) {
|
rpc SearchCollections(SearchCollectionRequest) returns (SearchCollectionResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/search/collections"
|
get: "/api/v1/search/collections"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Ping(PingRequest) returns (PingResponse) {
|
rpc Ping(PingRequest) returns (PingResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/ping"
|
get: "/ping"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +59,8 @@ service MusicBackend {
|
|||||||
message CollectionRequest {
|
message CollectionRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
int32 index = 2;
|
int32 index = 2;
|
||||||
|
int32 limit = 3;
|
||||||
|
int32 offset = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CollectionResponse {
|
message CollectionResponse {
|
||||||
@@ -73,7 +75,7 @@ message SongRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SongResponse {
|
message SongResponse {
|
||||||
repeated Song songs = 1;
|
Song song = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ArtistRequest {
|
message ArtistRequest {
|
||||||
@@ -122,6 +124,10 @@ message SearchArtistRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SearchArtistResponse {
|
message SearchArtistResponse {
|
||||||
|
repeated Artist Artists = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Artist {
|
||||||
string artist = 1;
|
string artist = 1;
|
||||||
int32 items = 2;
|
int32 items = 2;
|
||||||
}
|
}
|
||||||
@@ -133,11 +139,15 @@ message SearchCollectionRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SearchCollectionResponse {
|
message SearchCollectionResponse {
|
||||||
|
repeated CollectionPreview collections = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CollectionPreview {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
string image = 2;
|
string image = 2;
|
||||||
int32 items = 3;
|
int32 items = 3;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
//===== status =====
|
//===== status =====
|
||||||
message PingRequest {
|
message PingRequest {
|
||||||
string ping = 1;
|
string ping = 1;
|
||||||
@@ -159,4 +169,4 @@ message Song {
|
|||||||
string audio = 8;
|
string audio = 8;
|
||||||
int64 total_time = 9;
|
int64 total_time = 9;
|
||||||
string image = 10;
|
string image = 10;
|
||||||
}
|
}
|
||||||
@@ -9,49 +9,49 @@ import "google/api/annotations.proto";
|
|||||||
service MusicBackend {
|
service MusicBackend {
|
||||||
rpc Collections(CollectionRequest) returns (CollectionResponse) {
|
rpc Collections(CollectionRequest) returns (CollectionResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/collections"
|
get: "/api/v1/collections"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Song(SongRequest) returns (SongResponse){
|
rpc Song(SongRequest) returns (SongResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/song/{hash}"
|
get: "/api/v1/song/{hash}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Artist(ArtistRequest) returns (ArtistResponse){
|
rpc Artist(ArtistRequest) returns (ArtistResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/artist{artist}"
|
get: "/api/v1/artist/{artist}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Favorite(FavoriteRequest) returns (FavoriteResponse){
|
rpc Favorite(FavoriteRequest) returns (FavoriteResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/favorites"
|
get: "/api/v1/favorites"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Recent(RecentRequest) returns (RecentResponse){
|
rpc Recent(RecentRequest) returns (RecentResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/recent"
|
get: "/api/v1/recent"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc Search(SearchSharedRequest) returns (SearchSharedResponse) {
|
rpc Search(SearchSharedRequest) returns (SearchSharedResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/search"
|
get: "/api/v1/search"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc SearchArtists(SearchArtistRequest) returns (SearchArtistResponse) {
|
rpc SearchArtists(SearchArtistRequest) returns (SearchArtistResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/search/artists"
|
get: "/api/v1/search/artists"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc SearchCollections(SearchCollectionRequest) returns (SearchCollectionResponse) {
|
rpc SearchCollections(SearchCollectionRequest) returns (SearchCollectionResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/v1/search/collections"
|
get: "/api/v1/search/collections"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc Ping(PingRequest) returns (PingResponse) {
|
rpc Ping(PingRequest) returns (PingResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/ping"
|
get: "/ping"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +59,8 @@ service MusicBackend {
|
|||||||
message CollectionRequest {
|
message CollectionRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
int32 index = 2;
|
int32 index = 2;
|
||||||
|
int32 limit = 3;
|
||||||
|
int32 offset = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CollectionResponse {
|
message CollectionResponse {
|
||||||
@@ -73,7 +75,7 @@ message SongRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SongResponse {
|
message SongResponse {
|
||||||
repeated Song songs = 1;
|
Song song = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ArtistRequest {
|
message ArtistRequest {
|
||||||
@@ -112,7 +114,7 @@ message SearchSharedRequest {
|
|||||||
|
|
||||||
message SearchSharedResponse {
|
message SearchSharedResponse {
|
||||||
string artist = 1;
|
string artist = 1;
|
||||||
repeated Song = 2;
|
repeated Song songs = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SearchArtistRequest {
|
message SearchArtistRequest {
|
||||||
@@ -122,6 +124,10 @@ message SearchArtistRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SearchArtistResponse {
|
message SearchArtistResponse {
|
||||||
|
repeated Artist Artists = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Artist {
|
||||||
string artist = 1;
|
string artist = 1;
|
||||||
int32 items = 2;
|
int32 items = 2;
|
||||||
}
|
}
|
||||||
@@ -133,11 +139,15 @@ message SearchCollectionRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SearchCollectionResponse {
|
message SearchCollectionResponse {
|
||||||
|
repeated CollectionPreview collections = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CollectionPreview {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
string image = 2;
|
string image = 2;
|
||||||
int32 items = 3;
|
int32 items = 3;
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
//===== status =====
|
//===== status =====
|
||||||
message PingRequest {
|
message PingRequest {
|
||||||
string ping = 1;
|
string ping = 1;
|
||||||
@@ -159,4 +169,4 @@ message Song {
|
|||||||
string audio = 8;
|
string audio = 8;
|
||||||
int64 total_time = 9;
|
int64 total_time = 9;
|
||||||
string image = 10;
|
string image = 10;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user