From 17720442612cdb058c25df7c0822ce530e88f956 Mon Sep 17 00:00:00 2001 From: JuLi0n21 Date: Mon, 17 Mar 2025 23:35:52 +0100 Subject: [PATCH] updating go-backend --- go-backend/.gitignore | 3 +- go-backend/database.go | 19 +++--- go-backend/handlers.go | 143 ++++++++++++++++++++++------------------- go-backend/main.go | 141 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 223 insertions(+), 83 deletions(-) diff --git a/go-backend/.gitignore b/go-backend/.gitignore index ba21c38..4bdc63d 100644 --- a/go-backend/.gitignore +++ b/go-backend/.gitignore @@ -1,2 +1,3 @@ data/* -.vscode/ \ No newline at end of file +.vscode/ +.env \ No newline at end of file diff --git a/go-backend/database.go b/go-backend/database.go index 7f9dda1..49a075a 100644 --- a/go-backend/database.go +++ b/go-backend/database.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "os" + "path" "path/filepath" "strconv" "strings" @@ -17,12 +18,12 @@ import ( var ErrBeatmapCountNotMatch = errors.New("beatmap count not matching") 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 - fileName = osuRoot + osuRoot = osuroot dir := filepath.Dir(connectionString) @@ -57,7 +58,7 @@ func initDB(connectionString string, osuDb *parser.OsuDB, osuRoot string) (*sql. return nil, err } - collectionDB, err := parser.ParseCollectionsDB(osuRoot + "collection.db") + collectionDB, err := parser.ParseCollectionsDB(path.Join(osuRoot, "collection.db")) if err != nil { return nil, err } @@ -411,7 +412,7 @@ func getCollection(db *sql.DB, limit, offset, index int) (Collection, error) { 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) } @@ -449,7 +450,7 @@ func getCollectionByName(db *sql.DB, limit, offset int, name string) (Collection 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) } @@ -493,7 +494,7 @@ func getCollections(db *sql.DB, q string, limit, offset int) ([]CollectionPrevie if i, err := strconv.Atoi(count); err == nil { c.Items = i } - c.Image = extractImageFromFile(fileName, folder, file) + c.Image = extractImageFromFile(osuRoot, folder, file) collections = append(collections, c) } @@ -517,7 +518,7 @@ func scanSongs(rows *sql.Rows) ([]Song, error) { 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 { fmt.Println(err) s.Image = fmt.Sprintf("404.png") @@ -539,7 +540,7 @@ func scanSong(row *sql.Row) (Song, error) { return Song{}, err } - s.Image = extractImageFromFile(fileName, s.Folder, s.File) + s.Image = extractImageFromFile(osuRoot, s.Folder, s.File) return s, nil } diff --git a/go-backend/handlers.go b/go-backend/handlers.go index 5eb53da..7974160 100644 --- a/go-backend/handlers.go +++ b/go-backend/handlers.go @@ -13,6 +13,7 @@ import ( _ "backend/docs" + "github.com/joho/godotenv" httpSwagger "github.com/swaggo/http-swagger" "github.com/juli0n21/go-osu-parser/parser" @@ -27,6 +28,7 @@ type Server struct { OsuDir string Db *sql.DB OsuDb *parser.OsuDB + Env map[string]string } func (s *Server) registerRoutes() { @@ -46,6 +48,8 @@ func (s *Server) registerRoutes() { http.HandleFunc("/api/v1/audio/{filepath}", s.songFile) http.HandleFunc("/api/v1/image/{filepath}", s.imageFile) + + http.HandleFunc("/api/v1/callback", s.callback) 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 -// @Description Searches collections 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 {array} Collection "List of collections" -// @Failure 400 {object} string "Bad Request" -// @Failure 500 {object} string "Internal Server Error" -// @Router /search/collections [get] +// @Summary Searches collections based on a query +// @Description Searches collections 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 {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") @@ -231,15 +235,15 @@ func (s *Server) collectionSearch(w http.ResponseWriter, r *http.Request) { 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] +// @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 == "" { @@ -250,18 +254,18 @@ func (s *Server) aristsSongs(w http.ResponseWriter, r *http.Request) { writeJSON(w, []Song{}, http.StatusOK) } -// @Summary Searches active records based on a query -// @Description Searches active records 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} ActiveSearch "Active search result" -// @Failure 400 {object} string "Bad Request" -// @Failure 500 {object} string "Internal Server Error" -// @Router /search/active [get] +// @Summary Searches active records based on a query +// @Description Searches active records 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} 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 == "" { @@ -281,18 +285,18 @@ func (s *Server) activeSearch(w http.ResponseWriter, r *http.Request) { 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] +// @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 == "" { @@ -312,16 +316,16 @@ func (s *Server) artistSearch(w http.ResponseWriter, r *http.Request) { writeJSON(w, a, http.StatusOK) } -// @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] +// @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) { f := r.PathValue("filepath") 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) } -// @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] +// @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) { f := r.PathValue("filepath") 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)) } +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) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) diff --git a/go-backend/main.go b/go-backend/main.go index 4d9638f..2a97279 100644 --- a/go-backend/main.go +++ b/go-backend/main.go @@ -1,8 +1,17 @@ package main import ( + "bufio" + "bytes" + "encoding/json" "fmt" "log" + "net/http" + "os" + "os/exec" + "path" + "regexp" + "strings" "github.com/joho/godotenv" "github.com/juli0n21/go-osu-parser/parser" @@ -12,32 +21,148 @@ import ( // @version 1.0 // @description Server Hosting ur own osu files over a simple Api -// @host localhost:8080 -// @BasePath /api/v1/ +// @host localhost:8080 +// @BasePath /api/v1/ func main() { - filename := "/mnt/g/Anwendungen/osu!/osu!.db" - osuRoot := "/mnt/g/Anwendungen/osu!/" - - if err := godotenv.Load(); err != nil { - fmt.Println("Error loading .env file") + envMap, err := godotenv.Read(".env") + if err != nil { + fmt.Println("Error reading .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) if err != nil { 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) if err != nil { log.Fatal(err) } s := &Server{ - Port: ":8080", + Port: port, Db: db, OsuDir: osuRoot, + Env: envMap, } 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 +}