mirror of
https://github.com/JuLi0n21/pwa-player.git
synced 2026-04-19 23:40:05 +00:00
add collection sugar
This commit is contained in:
@@ -419,13 +419,78 @@ func getCollection(db *sql.DB, limit, offset, index int) (Collection, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getCollections(db *sql.DB, q string, limit, offset int) ([]Collection, error) {
|
||||
//not correct
|
||||
rows, err := db.Query("SELECT Name, FROM Collections WHERE name = ? LIMIT ? OFFSET ?", q, limit, offset)
|
||||
func getCollectionByName(db *sql.DB, limit, offset int, name string) (Collection, error) {
|
||||
rows, err := db.Query(`
|
||||
SELECT
|
||||
c.Name, b.BeatmapId, b.MD5Hash, b.Title, b.Artist,
|
||||
b.Creator, b.Folder, b.File, b.Audio, b.TotalTime
|
||||
FROM Collection c
|
||||
Join Beatmap b ON c.MD5Hash = b.MD5Hash
|
||||
WHERE c.Name = ?
|
||||
LIMIT ?
|
||||
OFFSET ?;`, name, limit, offset)
|
||||
if err != nil {
|
||||
return []Collection{}, err
|
||||
return Collection{}, err
|
||||
}
|
||||
return scanCollections(rows)
|
||||
defer rows.Close()
|
||||
|
||||
var c Collection
|
||||
for rows.Next() {
|
||||
s := Song{}
|
||||
if err := rows.Scan(&c.Name, &s.BeatmapID, &s.MD5Hash, &s.Title, &s.Artist, &s.Creator, &s.Folder, &s.File, &s.Audio, &s.TotalTime); err != nil {
|
||||
return Collection{}, err
|
||||
}
|
||||
|
||||
s.Image = extractImageFromFile(fileName, s.Folder, s.File)
|
||||
|
||||
c.Songs = append(c.Songs, s)
|
||||
}
|
||||
|
||||
row := db.QueryRow(`SELECT COUNT(*) FROM Collection WHERE Name = ?`, c.Name)
|
||||
var count string
|
||||
row.Scan(&count)
|
||||
|
||||
if i, err := strconv.Atoi(count); err == nil {
|
||||
c.Items = i
|
||||
} else {
|
||||
return Collection{}, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getCollections(db *sql.DB, q string, limit, offset int) ([]CollectionPreview, error) {
|
||||
rows, err := db.Query(`
|
||||
SELECT
|
||||
c.Name, COUNT(b.MD5Hash), b.Folder, b.File
|
||||
FROM Collection c
|
||||
Join Beatmap b ON c.MD5Hash = b.MD5Hash
|
||||
WHERE c.Name LIKE ?
|
||||
GROUP BY c.NAME
|
||||
LIMIT ?
|
||||
OFFSET ?;`, "%"+q+"%", limit, offset)
|
||||
if err != nil {
|
||||
return []CollectionPreview{}, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var collections []CollectionPreview
|
||||
for rows.Next() {
|
||||
var c CollectionPreview
|
||||
var folder, file, count string
|
||||
if err := rows.Scan(&c.Name, &count, &folder, &file); err != nil {
|
||||
return []CollectionPreview{}, err
|
||||
}
|
||||
|
||||
if i, err := strconv.Atoi(count); err == nil {
|
||||
c.Items = i
|
||||
}
|
||||
c.Image = extractImageFromFile(fileName, folder, file)
|
||||
|
||||
collections = append(collections, c)
|
||||
}
|
||||
|
||||
return collections, nil
|
||||
}
|
||||
|
||||
func getSong(db *sql.DB, hash string) (Song, error) {
|
||||
@@ -472,14 +537,18 @@ func scanSong(row *sql.Row) (Song, error) {
|
||||
}
|
||||
|
||||
func extractImageFromFile(osuRoot, folder, file string) string {
|
||||
bm, err := parser.ParseOsuFile(fmt.Sprintf("%sSongs/%s/%s", osuRoot, folder, file))
|
||||
bm, err := parser.ParseOsuFile(filepath.Join(osuRoot, "Songs", folder, file))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return "404.png"
|
||||
}
|
||||
|
||||
if len(bm.Events) > 1 && len(bm.Events[0].EventParams) > 1 {
|
||||
return fmt.Sprintf("%s/%s", folder, strings.Trim(bm.Events[0].EventParams[0], "\""))
|
||||
if bm.Version > 3 {
|
||||
if len(bm.Events) > 0 && len(bm.Events[0].EventParams) > 0 {
|
||||
return fmt.Sprintf(`%s/%s`, folder, strings.Trim(bm.Events[0].EventParams[0], "\""))
|
||||
}
|
||||
} else {
|
||||
fmt.Println(bm.Events)
|
||||
}
|
||||
|
||||
return "404.png"
|
||||
|
||||
@@ -77,8 +77,13 @@ const docTemplate = `{
|
||||
"type": "integer",
|
||||
"description": "Index",
|
||||
"name": "index",
|
||||
"in": "query",
|
||||
"required": true
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Index",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -106,66 +111,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/collections": {
|
||||
"get": {
|
||||
"description": "Retrieves collections from the database with pagination based on the query parameter",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"search"
|
||||
],
|
||||
"summary": "Retrieves collections based on a query",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Search query",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/image/{filepath}": {
|
||||
"get": {
|
||||
"description": "Retrieves an image file from the server based on the provided encoded filepath",
|
||||
|
||||
@@ -71,8 +71,13 @@
|
||||
"type": "integer",
|
||||
"description": "Index",
|
||||
"name": "index",
|
||||
"in": "query",
|
||||
"required": true
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Index",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -100,66 +105,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/collections": {
|
||||
"get": {
|
||||
"description": "Retrieves collections from the database with pagination based on the query parameter",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"search"
|
||||
],
|
||||
"summary": "Retrieves collections based on a query",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Search query",
|
||||
"name": "query",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/image/{filepath}": {
|
||||
"get": {
|
||||
"description": "Retrieves an image file from the server based on the provided encoded filepath",
|
||||
|
||||
@@ -105,8 +105,11 @@ paths:
|
||||
- description: Index
|
||||
in: query
|
||||
name: index
|
||||
required: true
|
||||
type: integer
|
||||
- description: Index
|
||||
in: query
|
||||
name: name
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -127,47 +130,6 @@ paths:
|
||||
summary: Get a collection of songs by index
|
||||
tags:
|
||||
- songs
|
||||
/collections:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Retrieves collections from the database with pagination based on
|
||||
the query parameter
|
||||
parameters:
|
||||
- description: Search query
|
||||
in: query
|
||||
name: query
|
||||
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: Retrieves collections based on a query
|
||||
tags:
|
||||
- search
|
||||
/image/{filepath}:
|
||||
get:
|
||||
consumes:
|
||||
|
||||
@@ -4,7 +4,7 @@ go 1.23.5
|
||||
|
||||
require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/juli0n21/go-osu-parser v0.0.6
|
||||
github.com/juli0n21/go-osu-parser v0.0.8
|
||||
github.com/swaggo/http-swagger v1.3.4
|
||||
github.com/swaggo/swag v1.16.4
|
||||
modernc.org/sqlite v1.34.5
|
||||
|
||||
@@ -20,8 +20,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
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.6 h1:r5BTNrEDUHsF0ZFCvx0vfRcjU2IRvT3va4O1r3dm7og=
|
||||
github.com/juli0n21/go-osu-parser v0.0.6/go.mod h1:oLLWnZReOMW4i5aNva/zvXsFqzdQigrbjyxOSs0cx+0=
|
||||
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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
|
||||
@@ -38,7 +38,6 @@ func (s *Server) registerRoutes() {
|
||||
http.HandleFunc("/api/v1/songs/favorites", s.favorites)
|
||||
|
||||
http.HandleFunc("/api/v1/collection", s.collection)
|
||||
http.HandleFunc("/api/v1/collections", s.collections)
|
||||
http.HandleFunc("/api/v1/search/collections", s.collectionSearch)
|
||||
|
||||
http.HandleFunc("/api/v1/search/active", s.activeSearch)
|
||||
@@ -46,7 +45,7 @@ func (s *Server) registerRoutes() {
|
||||
|
||||
http.HandleFunc("/api/v1/audio/{filepath}", s.songFile)
|
||||
http.HandleFunc("/api/v1/image/{filepath}", s.imageFile)
|
||||
http.Handle("/swagger-ui", httpSwagger.WrapHandler)
|
||||
http.Handle("/swagger/", httpSwagger.WrapHandler)
|
||||
}
|
||||
|
||||
func run(s *Server) {
|
||||
@@ -100,7 +99,7 @@ func (s *Server) song(w http.ResponseWriter, r *http.Request) {
|
||||
song, err := getSong(s.Db, hash)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusNotFound)
|
||||
http.Error(w, "beatmap not found by hash", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -170,58 +169,39 @@ func (s *Server) favorites(w http.ResponseWriter, r *http.Request) {
|
||||
// @Tags songs
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param index query int true "Index"
|
||||
// @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 != "" {
|
||||
c, err := getCollectionByName(s.Db, limit, offset, name)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
writeJSON(w, c, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
index, err := strconv.Atoi(r.URL.Query().Get("index"))
|
||||
if err != nil {
|
||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
limit, offset := pagination(r)
|
||||
|
||||
recent, err := getCollection(s.Db, limit, offset, index)
|
||||
} else {
|
||||
c, err := getCollection(s.Db, limit, offset, index)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
writeJSON(w, recent, http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Retrieves collections based on a query
|
||||
// @Description Retrieves collections from the database with pagination based on the query parameter
|
||||
// @Tags search
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param query query string false "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 /collections [get]
|
||||
func (s *Server) collections(w http.ResponseWriter, r *http.Request) {
|
||||
query := r.URL.Query().Get("query")
|
||||
if query == "" {
|
||||
http.Error(w, ErrRequiredParameterNotPresent.Error(), http.StatusBadRequest)
|
||||
writeJSON(w, c, http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
limit, offset := pagination(r)
|
||||
|
||||
recent, err := getCollections(s.Db, query, limit, offset)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
writeJSON(w, recent, http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Searches collections based on a query
|
||||
@@ -238,22 +218,16 @@ func (s *Server) collections(w http.ResponseWriter, r *http.Request) {
|
||||
// @Router /search/collections [get]
|
||||
func (s *Server) collectionSearch(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)
|
||||
|
||||
recent, err := getCollections(s.Db, q, limit, offset)
|
||||
preview, err := getCollections(s.Db, q, limit, offset)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
writeJSON(w, recent, http.StatusOK)
|
||||
writeJSON(w, preview, http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Searches active records based on a query
|
||||
|
||||
@@ -18,9 +18,8 @@ type Song struct {
|
||||
// CollectionPreview represents a preview of a song collection
|
||||
// @Description CollectionPreview contains summary data of a song collection
|
||||
type CollectionPreview struct {
|
||||
Name string `json:"name" example:"Favorite Songs"`
|
||||
Name string `json:"name" example:"Collection Name"`
|
||||
Image string `json:"image" example:"cover.jpg"`
|
||||
Index int `json:"index" example:"1"`
|
||||
Items int `json:"items" example:"10"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user