mirror of
https://github.com/JuLi0n21/pwa-player.git
synced 2026-04-19 15:30:05 +00:00
the start of the go backend
This commit is contained in:
2
go-backend/.gitignore
vendored
Normal file
2
go-backend/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
data/*
|
||||||
|
.vscode/
|
||||||
316
go-backend/database.go
Normal file
316
go-backend/database.go
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/juli0n21/go-osu-parser/parser"
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrBeatmapCountNotMatch = errors.New("beatmap count not matching")
|
||||||
|
|
||||||
|
func initDB(connectionString string, osuDb *parser.OsuDB) (*sql.DB, error) {
|
||||||
|
|
||||||
|
dir := filepath.Dir(connectionString)
|
||||||
|
|
||||||
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create directory %s: %v", dir, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open("sqlite", connectionString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to open SQLite database %s: %v", connectionString, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = createDB(db); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = checkhealth(db, osuDb); err != nil {
|
||||||
|
if err = rebuildDb(db, osuDb); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDB(db *sql.DB) error {
|
||||||
|
_, err := db.Query(`
|
||||||
|
CREATE TABLE IF NOT EXISTS Beatmap (
|
||||||
|
BeatmapId INTEGER DEFAULT 0,
|
||||||
|
Artist TEXT DEFAULT '?????',
|
||||||
|
ArtistUnicode TEXT DEFAULT '?????',
|
||||||
|
Title TEXT DEFAULT '???????',
|
||||||
|
TitleUnicode TEXT DEFAULT '???????',
|
||||||
|
Creator TEXT DEFAULT '?????',
|
||||||
|
Difficulty TEXT DEFAULT '1',
|
||||||
|
AudioFileName TEXT DEFAULT 'unknown.mp3',
|
||||||
|
MD5Hash TEXT DEFAULT '00000000000000000000000000000000',
|
||||||
|
FileName TEXT DEFAULT 'unknown.osu',
|
||||||
|
RankedStatus TEXT DEFAULT Unknown,
|
||||||
|
LastModifiedTime DATETIME DEFAULT '0001-01-01 00:00:00',
|
||||||
|
TotalTime INTEGER DEFAULT 0,
|
||||||
|
AudioPreviewTime INTEGER DEFAULT 0,
|
||||||
|
BeatmapSetId INTEGER DEFAULT -1,
|
||||||
|
Source TEXT DEFAULT '',
|
||||||
|
Tags TEXT DEFAULT '',
|
||||||
|
LastPlayed DATETIME DEFAULT '0001-01-01 00:00:00',
|
||||||
|
FolderName TEXT DEFAULT 'Unknown Folder',
|
||||||
|
UNIQUE (Artist, Title, MD5Hash, Difficulty)
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkhealth(db *sql.DB, osuDb *parser.OsuDB) error {
|
||||||
|
|
||||||
|
rows, err := db.Query(`SELECT COUNT(*) FROM Beatmap GROUP BY BeatmapSetId;`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var count int
|
||||||
|
if err = rows.Scan(&count); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if count != int(osuDb.FolderCount) {
|
||||||
|
log.Println("Folder count missmatch rebuilding db...")
|
||||||
|
return ErrBeatmapCountNotMatch
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err = db.Query(`SELECT COUNT(*) FROM Beatmap;`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = rows.Scan(&count); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if count != int(osuDb.NumberOfBeatmaps) {
|
||||||
|
log.Println("Beatmap count missmatch rebuilding db...")
|
||||||
|
return ErrBeatmapCountNotMatch
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func rebuildDb(db *sql.DB, osuDb *parser.OsuDB) error {
|
||||||
|
|
||||||
|
if _, err := db.Query("DROP TABLE Beatmap"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createDB(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stmt, err := db.Prepare(`
|
||||||
|
INSERT INTO Beatmap (
|
||||||
|
BeatmapId, Artist, ArtistUnicode, Title, TitleUnicode, Creator,
|
||||||
|
Difficulty, AudioFileName, MD5Hash, FileName, RankedStatus,
|
||||||
|
LastModifiedTime, TotalTime, AudioPreviewTime, BeatmapSetId,
|
||||||
|
Source, Tags, LastPlayed, FolderName
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`)
|
||||||
|
// ON CONFLICT (Artist, Title, MD5Hash) DO NOTHING
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt = tx.Stmt(stmt)
|
||||||
|
|
||||||
|
for i, beatmap := range osuDb.Beatmaps {
|
||||||
|
//fmt.Println(i, beatmap.Artist, beatmap.SongTitle, beatmap.MD5Hash)
|
||||||
|
_, err := stmt.Exec(
|
||||||
|
beatmap.DifficultyID, beatmap.Artist, beatmap.ArtistUnicode,
|
||||||
|
beatmap.SongTitle, beatmap.SongTitleUnicode, beatmap.Creator,
|
||||||
|
beatmap.Difficulty, beatmap.AudioFileName, beatmap.MD5Hash,
|
||||||
|
beatmap.FileName, beatmap.RankedStatus, beatmap.LastModificationTime,
|
||||||
|
beatmap.TotalTime, beatmap.AudioPreviewStartTime, beatmap.BeatmapID,
|
||||||
|
beatmap.SongSource, beatmap.SongTags, beatmap.LastPlayed, beatmap.FolderName,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(i, "hash: ", beatmap.MD5Hash, "artist:", beatmap.Artist, "title:", beatmap.SongTitle, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBeatmapCount(db *sql.DB) int {
|
||||||
|
rows, err := db.Query("SELECT COUNT(*) FROM Beatmap")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var count int
|
||||||
|
if rows.Next() {
|
||||||
|
err = rows.Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRecent(db *sql.DB, limit, offset int) ([]Song, error) {
|
||||||
|
rows, err := db.Query("SELECT * FROM Songs ORDER BY LastPlayed DESC LIMIT ? OFFSET ?", limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return scanSongs(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSearch(db *sql.DB, q string, limit, offset int) (ActiveSearch, error) {
|
||||||
|
rows, err := db.Query("SELECT * FROM Songs WHERE Title LIKE ? OR Artist LIKE ? LIMIT ? OFFSET ?", "%"+q+"%", "%"+q+"%", limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return ActiveSearch{}, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
_, err = scanSongs(rows)
|
||||||
|
if err != nil {
|
||||||
|
return ActiveSearch{}, err
|
||||||
|
}
|
||||||
|
return ActiveSearch{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getArtists(db *sql.DB, q string, limit, offset int) ([]string, error) {
|
||||||
|
rows, err := db.Query("SELECT * FROM Songs WHERE Title LIKE ? OR Artist LIKE ? LIMIT ? OFFSET ?", "%"+q+"%", "%"+q+"%", limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
_, err = scanSongs(rows)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFavorites(db *sql.DB, q string, limit, offset int) ([]Song, error) {
|
||||||
|
rows, err := db.Query("SELECT * FROM Songs WHERE IsFavorite = 1 LIMIT ? OFFSET ?", limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return scanSongs(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCollection(db *sql.DB, index int) (Collection, error) {
|
||||||
|
row := db.QueryRow("SELECT * FROM Collections WHERE CollectionId = ?", index)
|
||||||
|
return scanCollection(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCollections(db *sql.DB, q string, limit, offset int) ([]Collection, error) {
|
||||||
|
//not correct
|
||||||
|
rows, err := db.Query("SELECT * FROM Collections WHERE name = ? LIMIT ? OFFSET ?", q, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return []Collection{}, err
|
||||||
|
}
|
||||||
|
return scanCollections(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSong(db *sql.DB, hash string) (Song, error) {
|
||||||
|
row := db.QueryRow("SELECT * FROM Songs WHERE MD5Hash = ?", hash)
|
||||||
|
return scanSong(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanSongs(rows *sql.Rows) ([]Song, error) {
|
||||||
|
|
||||||
|
var songs []Song
|
||||||
|
for rows.Next() {
|
||||||
|
var s Song
|
||||||
|
if err := rows.Scan(&s); err != nil {
|
||||||
|
return []Song{}, err
|
||||||
|
}
|
||||||
|
songs = append(songs, s)
|
||||||
|
}
|
||||||
|
return songs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanSong(row *sql.Row) (Song, error) {
|
||||||
|
|
||||||
|
var s Song
|
||||||
|
if err := row.Scan(&s); err != nil {
|
||||||
|
return Song{}, err
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanCollections(rows *sql.Rows) ([]Collection, error) {
|
||||||
|
|
||||||
|
var collection []Collection
|
||||||
|
for rows.Next() {
|
||||||
|
var c Collection
|
||||||
|
if err := rows.Scan(&c); err != nil {
|
||||||
|
return []Collection{}, err
|
||||||
|
}
|
||||||
|
collection = append(collection, c)
|
||||||
|
}
|
||||||
|
return collection, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanCollection(row *sql.Row) (Collection, error) {
|
||||||
|
|
||||||
|
var c Collection
|
||||||
|
if err := row.Scan(&c); err != nil {
|
||||||
|
return Collection{}, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanCollectionPreviews(rows *sql.Rows) ([]CollectionPreview, error) {
|
||||||
|
|
||||||
|
var collection []CollectionPreview
|
||||||
|
for rows.Next() {
|
||||||
|
var c CollectionPreview
|
||||||
|
if err := rows.Scan(&c); err != nil {
|
||||||
|
return []CollectionPreview{}, err
|
||||||
|
}
|
||||||
|
collection = append(collection, c)
|
||||||
|
}
|
||||||
|
return collection, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanCollectionPreview(row *sql.Row) (CollectionPreview, error) {
|
||||||
|
|
||||||
|
var c CollectionPreview
|
||||||
|
if err := row.Scan(&c); err != nil {
|
||||||
|
return CollectionPreview{}, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
21
go-backend/go.mod
Normal file
21
go-backend/go.mod
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module backend
|
||||||
|
|
||||||
|
go 1.23.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/juli0n21/go-osu-parser v0.0.6
|
||||||
|
modernc.org/sqlite v1.34.5
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
modernc.org/libc v1.55.3 // indirect
|
||||||
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
modernc.org/memory v1.8.0 // indirect
|
||||||
|
)
|
||||||
47
go-backend/go.sum
Normal file
47
go-backend/go.sum
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
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/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
|
||||||
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
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/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/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||||
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||||
|
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
|
||||||
|
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
|
||||||
|
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||||
|
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||||
|
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||||
|
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||||
|
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||||
|
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||||
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
|
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||||
|
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||||
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||||
|
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||||
|
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
|
||||||
|
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
|
||||||
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
187
go-backend/handlers.go
Normal file
187
go-backend/handlers.go
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/juli0n21/go-osu-parser/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func run(db *sql.DB, osuDb *parser.OsuDB) {
|
||||||
|
|
||||||
|
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "pong")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Login endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/songs/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getRecent(db, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/songs/recent", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getRecent(db, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
fmt.Fprintln(w, "Recent songs endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/songs/favorite", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getRecent(db, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
fmt.Fprintln(w, "Favorite songs endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/collections/{index}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getRecent(db, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
fmt.Fprintln(w, "Collections endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/collections/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getRecent(db, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
fmt.Fprintln(w, "Collection with index endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/audio/{hash}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Audio endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/search/active", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
q := r.URL.Query().Get("query")
|
||||||
|
if err != nil || q == "" {
|
||||||
|
fmt.Fprintln(w, errors.New("'query' is required for search"))
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getSearch(db, q, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
fmt.Fprintln(w, "Active search endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/search/artist", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
q := r.URL.Query().Get("query")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getArtists(db, q, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
fmt.Fprintln(w, "Artist search endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/search/collections", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
offset, err := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
q := r.URL.Query().Get("query")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent, err := getCollections(db, q, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(w, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, recent)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.HandleFunc("/api/v1/images/{filename}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Images endpoint")
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println("starting server on http://localhost:8080")
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
30
go-backend/main.go
Normal file
30
go-backend/main.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/juli0n21/go-osu-parser/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
filename := "/mnt/g/Anwendungen/osu!/osu!.db"
|
||||||
|
|
||||||
|
if err := godotenv.Load(); err != nil {
|
||||||
|
fmt.Println("Error loading .env file")
|
||||||
|
}
|
||||||
|
|
||||||
|
osuDb, err := parser.ParseOsuDB(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := initDB("./data/music.db", osuDb)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
run(db, osuDb)
|
||||||
|
}
|
||||||
35
go-backend/models.go
Normal file
35
go-backend/models.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Song struct {
|
||||||
|
MD5Hash string
|
||||||
|
Title string
|
||||||
|
Artist string
|
||||||
|
Creator string
|
||||||
|
Folder string
|
||||||
|
File string
|
||||||
|
Audio string
|
||||||
|
Mapper string
|
||||||
|
TotalTime time.Duration
|
||||||
|
Url string
|
||||||
|
Image string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CollectionPreview struct {
|
||||||
|
name string
|
||||||
|
image string
|
||||||
|
index int
|
||||||
|
items int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Collection struct {
|
||||||
|
name string
|
||||||
|
items int
|
||||||
|
Songs []Song
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActiveSearch struct {
|
||||||
|
artist string
|
||||||
|
Songs []Song
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user