updating go-backend

This commit is contained in:
2025-03-17 23:35:52 +01:00
parent 2afbf31ed6
commit 1772044261
4 changed files with 223 additions and 83 deletions

View File

@@ -1,2 +1,3 @@
data/* data/*
.vscode/ .vscode/
.env

View File

@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
@@ -17,12 +18,12 @@ import (
var ErrBeatmapCountNotMatch = errors.New("beatmap count not matching") var ErrBeatmapCountNotMatch = errors.New("beatmap count not matching")
var osuDB *parser.OsuDB var osuDB *parser.OsuDB
var fileName string var osuRoot string
func initDB(connectionString string, osuDb *parser.OsuDB, osuRoot string) (*sql.DB, error) { func initDB(connectionString string, osuDb *parser.OsuDB, osuroot string) (*sql.DB, error) {
osuDB = osuDb osuDB = osuDb
fileName = osuRoot osuRoot = osuroot
dir := filepath.Dir(connectionString) dir := filepath.Dir(connectionString)
@@ -57,7 +58,7 @@ func initDB(connectionString string, osuDb *parser.OsuDB, osuRoot string) (*sql.
return nil, err return nil, err
} }
collectionDB, err := parser.ParseCollectionsDB(osuRoot + "collection.db") collectionDB, err := parser.ParseCollectionsDB(path.Join(osuRoot, "collection.db"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -411,7 +412,7 @@ func getCollection(db *sql.DB, limit, offset, index int) (Collection, error) {
return Collection{}, err return Collection{}, err
} }
s.Image = extractImageFromFile(fileName, s.Folder, s.File) s.Image = extractImageFromFile(osuRoot, s.Folder, s.File)
c.Songs = append(c.Songs, s) c.Songs = append(c.Songs, s)
} }
@@ -449,7 +450,7 @@ func getCollectionByName(db *sql.DB, limit, offset int, name string) (Collection
return Collection{}, err return Collection{}, err
} }
s.Image = extractImageFromFile(fileName, s.Folder, s.File) s.Image = extractImageFromFile(osuRoot, s.Folder, s.File)
c.Songs = append(c.Songs, s) c.Songs = append(c.Songs, s)
} }
@@ -493,7 +494,7 @@ func getCollections(db *sql.DB, q string, limit, offset int) ([]CollectionPrevie
if i, err := strconv.Atoi(count); err == nil { if i, err := strconv.Atoi(count); err == nil {
c.Items = i c.Items = i
} }
c.Image = extractImageFromFile(fileName, folder, file) c.Image = extractImageFromFile(osuRoot, folder, file)
collections = append(collections, c) collections = append(collections, c)
} }
@@ -517,7 +518,7 @@ func scanSongs(rows *sql.Rows) ([]Song, error) {
return []Song{}, err return []Song{}, err
} }
bm, err := parser.ParseOsuFile(fmt.Sprintf("%sSongs/%s/%s", fileName, s.Folder, s.File)) bm, err := parser.ParseOsuFile(fmt.Sprintf("%sSongs/%s/%s", osuRoot, s.Folder, s.File))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.Image = fmt.Sprintf("404.png") s.Image = fmt.Sprintf("404.png")
@@ -539,7 +540,7 @@ func scanSong(row *sql.Row) (Song, error) {
return Song{}, err return Song{}, err
} }
s.Image = extractImageFromFile(fileName, s.Folder, s.File) s.Image = extractImageFromFile(osuRoot, s.Folder, s.File)
return s, nil return s, nil
} }

View File

@@ -13,6 +13,7 @@ import (
_ "backend/docs" _ "backend/docs"
"github.com/joho/godotenv"
httpSwagger "github.com/swaggo/http-swagger" httpSwagger "github.com/swaggo/http-swagger"
"github.com/juli0n21/go-osu-parser/parser" "github.com/juli0n21/go-osu-parser/parser"
@@ -27,6 +28,7 @@ type Server struct {
OsuDir string OsuDir string
Db *sql.DB Db *sql.DB
OsuDb *parser.OsuDB OsuDb *parser.OsuDB
Env map[string]string
} }
func (s *Server) registerRoutes() { func (s *Server) registerRoutes() {
@@ -46,6 +48,8 @@ func (s *Server) registerRoutes() {
http.HandleFunc("/api/v1/audio/{filepath}", s.songFile) http.HandleFunc("/api/v1/audio/{filepath}", s.songFile)
http.HandleFunc("/api/v1/image/{filepath}", s.imageFile) http.HandleFunc("/api/v1/image/{filepath}", s.imageFile)
http.HandleFunc("/api/v1/callback", s.callback)
http.Handle("/swagger/", httpSwagger.WrapHandler) http.Handle("/swagger/", httpSwagger.WrapHandler)
} }
@@ -205,18 +209,18 @@ func (s *Server) collection(w http.ResponseWriter, r *http.Request) {
} }
// @Summary Searches collections based on a query // @Summary Searches collections based on a query
// @Description Searches collections in the database based on the query parameter // @Description Searches collections in the database based on the query parameter
// @Tags search // @Tags search
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param query query string true "Search query" // @Param query query string true "Search query"
// @Param limit query int false "Limit the number of results" default(10) // @Param limit query int false "Limit the number of results" default(10)
// @Param offset query int false "Offset for pagination" default(0) // @Param offset query int false "Offset for pagination" default(0)
// @Success 200 {array} Collection "List of collections" // @Success 200 {array} Collection "List of collections"
// @Failure 400 {object} string "Bad Request" // @Failure 400 {object} string "Bad Request"
// @Failure 500 {object} string "Internal Server Error" // @Failure 500 {object} string "Internal Server Error"
// @Router /search/collections [get] // @Router /search/collections [get]
func (s *Server) collectionSearch(w http.ResponseWriter, r *http.Request) { func (s *Server) collectionSearch(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query().Get("query") q := r.URL.Query().Get("query")
@@ -231,15 +235,15 @@ func (s *Server) collectionSearch(w http.ResponseWriter, r *http.Request) {
writeJSON(w, preview, http.StatusOK) writeJSON(w, preview, http.StatusOK)
} }
// @Summary Returns all the Songs of a specific Artist // @Summary Returns all the Songs of a specific Artist
// @Tags songs // @Tags songs
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param artist query string true "Artist Name" // @Param artist query string true "Artist Name"
// @Success 200 {array} Song // @Success 200 {array} Song
// @Failure 400 {object} string "Bad Request" // @Failure 400 {object} string "Bad Request"
// @Failure 500 {object} string "Internal Server Error" // @Failure 500 {object} string "Internal Server Error"
// @Router /songs/artist [get] // @Router /songs/artist [get]
func (s *Server) aristsSongs(w http.ResponseWriter, r *http.Request) { func (s *Server) aristsSongs(w http.ResponseWriter, r *http.Request) {
artist := r.URL.Query().Get("artist") artist := r.URL.Query().Get("artist")
if artist == "" { if artist == "" {
@@ -250,18 +254,18 @@ func (s *Server) aristsSongs(w http.ResponseWriter, r *http.Request) {
writeJSON(w, []Song{}, http.StatusOK) writeJSON(w, []Song{}, http.StatusOK)
} }
// @Summary Searches active records based on a query // @Summary Searches active records based on a query
// @Description Searches active records in the database based on the query parameter // @Description Searches active records in the database based on the query parameter
// @Tags search // @Tags search
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param query query string true "Search query" // @Param query query string true "Search query"
// @Param limit query int false "Limit the number of results" default(10) // @Param limit query int false "Limit the number of results" default(10)
// @Param offset query int false "Offset for pagination" default(0) // @Param offset query int false "Offset for pagination" default(0)
// @Success 200 {object} ActiveSearch "Active search result" // @Success 200 {object} ActiveSearch "Active search result"
// @Failure 400 {object} string "Bad Request" // @Failure 400 {object} string "Bad Request"
// @Failure 500 {object} string "Internal Server Error" // @Failure 500 {object} string "Internal Server Error"
// @Router /search/active [get] // @Router /search/active [get]
func (s *Server) activeSearch(w http.ResponseWriter, r *http.Request) { func (s *Server) activeSearch(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query().Get("query") q := r.URL.Query().Get("query")
if q == "" { if q == "" {
@@ -281,18 +285,18 @@ func (s *Server) activeSearch(w http.ResponseWriter, r *http.Request) {
writeJSON(w, recent, http.StatusOK) writeJSON(w, recent, http.StatusOK)
} }
// @Summary Searches for artists based on a query // @Summary Searches for artists based on a query
// @Description Searches for artists in the database based on the query parameter // @Description Searches for artists in the database based on the query parameter
// @Tags search // @Tags search
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param query query string true "Search query" // @Param query query string true "Search query"
// @Param limit query int false "Limit the number of results" default(10) // @Param limit query int false "Limit the number of results" default(10)
// @Param offset query int false "Offset for pagination" default(0) // @Param offset query int false "Offset for pagination" default(0)
// @Success 200 {object} Artist "List of artists" // @Success 200 {object} Artist "List of artists"
// @Failure 400 {object} string "Bad Request" // @Failure 400 {object} string "Bad Request"
// @Failure 500 {object} string "Internal Server Error" // @Failure 500 {object} string "Internal Server Error"
// @Router /search/artist [get] // @Router /search/artist [get]
func (s *Server) artistSearch(w http.ResponseWriter, r *http.Request) { func (s *Server) artistSearch(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query().Get("query") q := r.URL.Query().Get("query")
if q == "" { if q == "" {
@@ -312,16 +316,16 @@ func (s *Server) artistSearch(w http.ResponseWriter, r *http.Request) {
writeJSON(w, a, http.StatusOK) writeJSON(w, a, http.StatusOK)
} }
// @Summary Retrieves a song file by its encoded path // @Summary Retrieves a song file by its encoded path
// @Description Retrieves a song file from the server based on the provided encoded filepath // @Description Retrieves a song file from the server based on the provided encoded filepath
// @Tags files // @Tags files
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param filepath path string true "Base64 encoded file path" // @Param filepath path string true "Base64 encoded file path"
// @Success 200 {file} File "The requested song file" // @Success 200 {file} File "The requested song file"
// @Failure 400 {object} string "Bad Request" // @Failure 400 {object} string "Bad Request"
// @Failure 404 {object} string "File Not Found" // @Failure 404 {object} string "File Not Found"
// @Router /audio/{filepath} [get] // @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 == "" {
@@ -354,16 +358,16 @@ 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 // @Summary Retrieves an image file by its encoded path
// @Description Retrieves an image file from the server based on the provided encoded filepath // @Description Retrieves an image file from the server based on the provided encoded filepath
// @Tags files // @Tags files
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param filepath path string true "Base64 encoded file path" // @Param filepath path string true "Base64 encoded file path"
// @Success 200 {file} File "The requested image file" // @Success 200 {file} File "The requested image file"
// @Failure 400 {object} string "Bad Request" // @Failure 400 {object} string "Bad Request"
// @Failure 404 {object} string "File Not Found" // @Failure 404 {object} string "File Not Found"
// @Router /image/{filepath} [get] // @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 == "" {
@@ -381,6 +385,15 @@ func (s *Server) imageFile(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, s.OsuDir+"Songs/"+string(filename)) http.ServeFile(w, r, s.OsuDir+"Songs/"+string(filename))
} }
func (s *Server) callback(w http.ResponseWriter, r *http.Request) {
cookie := r.URL.Query().Get("COOKIE")
if cookie != "" {
s.Env["COOKIE"] = cookie
godotenv.Write(s.Env, ".env")
}
}
func writeJSON(w http.ResponseWriter, v any, status int) { func writeJSON(w http.ResponseWriter, v any, status int) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status) w.WriteHeader(status)

View File

@@ -1,8 +1,17 @@
package main package main
import ( import (
"bufio"
"bytes"
"encoding/json"
"fmt" "fmt"
"log" "log"
"net/http"
"os"
"os/exec"
"path"
"regexp"
"strings"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/juli0n21/go-osu-parser/parser" "github.com/juli0n21/go-osu-parser/parser"
@@ -12,32 +21,148 @@ import (
// @version 1.0 // @version 1.0
// @description Server Hosting ur own osu files over a simple Api // @description Server Hosting ur own osu files over a simple Api
// @host localhost:8080 // @host localhost:8080
// @BasePath /api/v1/ // @BasePath /api/v1/
func main() { func main() {
filename := "/mnt/g/Anwendungen/osu!/osu!.db" envMap, err := godotenv.Read(".env")
osuRoot := "/mnt/g/Anwendungen/osu!/" if err != nil {
fmt.Println("Error reading .env file")
if err := godotenv.Load(); err != nil {
fmt.Println("Error loading .env file")
} }
if envMap["OSU_PATH"] == "" {
fmt.Println("Osu Path not found! Please paste the full path to your osu! folder.")
fmt.Println("Osu Path not found pls paste the full Path to ur osu! folder \n it should start with 'C://' and can be opened from the Settings menu!)\n path: ")
fmt.Scanln(&osuRoot)
osuRoot = strings.TrimSpace(osuRoot)
envMap["OSU_PATH"] = osuRoot
godotenv.Write(envMap, ".env")
}
osuRoot := envMap["OSU_PATH"]
cookie := envMap["COOKIE"]
port := GetEnv(envMap["PORT"], ":8080")
filename := path.Join(osuRoot, "osu!.db")
osuDb, err := parser.ParseOsuDB(filename) osuDb, err := parser.ParseOsuDB(filename)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if cookie == "" {
fmt.Println("No Authentication found please follow the link to log in!\n http://proxy.illegalesachen.download/login")
}
url, err := StartCloudflared(port)
if err != nil {
log.Fatalf("Cloudflared service couldnt be started: %v", err)
}
if err = sendUrl(url, cookie); err != nil {
log.Fatalf("Couldnt Update Endpoint url with Proxy: %v", err)
}
db, err := initDB("./data/music.db", osuDb, osuRoot) db, err := initDB("./data/music.db", osuDb, osuRoot)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
s := &Server{ s := &Server{
Port: ":8080", Port: port,
Db: db, Db: db,
OsuDir: osuRoot, OsuDir: osuRoot,
Env: envMap,
} }
run(s) run(s)
} }
func GetEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok && value != "" {
return value
}
return fallback
}
func StartCloudflared(port string) (string, error) {
cmd := exec.Command("cloudflared", "tunnel", "--url", fmt.Sprintf("http://localhost%s", port))
stderr, err := cmd.StderrPipe()
if err != nil {
return "", fmt.Errorf("Error creating StderrPipe: %v", err)
}
if err := cmd.Start(); err != nil {
return "", fmt.Errorf("Error starting command: %v", err)
}
stderrScanner := bufio.NewScanner(stderr)
urlRegex := regexp.MustCompile(`https?://[\w.-]+\.trycloudflare\.com`)
for stderrScanner.Scan() {
line := stderrScanner.Text()
if url := urlRegex.FindString(line); url != "" {
fmt.Println("Found URL:", url)
return url, nil
}
}
if err := cmd.Wait(); err != nil {
return "", fmt.Errorf("Error waiting for command: %v", err)
}
if err := stderrScanner.Err(); err != nil {
return "", fmt.Errorf("Error reading stderr: %v", err)
}
return "", fmt.Errorf("no url found")
}
func sendUrl(endpoint, cookie string) error {
url := "http://proxy.illegalesachen.download/settings"
payload := struct {
Sharing *bool `json:"sharing"`
Endpoint string `json:"endpoint"`
}{
Endpoint: endpoint,
}
body, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("Error marshalling payload: %v", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
if err != nil {
return fmt.Errorf("Error creating request: %v", err)
}
req.AddCookie(&http.Cookie{
Name: "session_cookie",
Value: cookie,
})
req.Header.Set("Content-Type", "application/json")
fmt.Println(req)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("Error sending request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Error in request: %s", resp.Status)
}
fmt.Println("Response Status:", resp.Status)
return nil
}