9 Commits
4.0.0 ... main

Author SHA1 Message Date
290d79ef5e Changed how time are sent to frontend during sync
All checks were successful
Build / build (push) Successful in 40s
2025-11-15 14:55:03 +01:00
aa0b8275e7 Fix so that ending slash doesn't matter for characters path
All checks were successful
Build / build (push) Successful in 40s
2025-11-08 12:04:44 +01:00
c369b13fae Added characters to Dockerfile
All checks were successful
Build / build (push) Successful in 39s
Publish / publish (push) Successful in 47s
2025-11-08 11:54:51 +01:00
bef915ac6d Fixed gitea script
All checks were successful
Build / build (push) Successful in 39s
2025-11-07 21:10:40 +01:00
cff777f278 Small fixes to getting character images
All checks were successful
Build / build (push) Successful in 44s
Publish / publish (push) Successful in 51s
2025-11-07 20:24:46 +01:00
61cab73ffc Small fix to update song played
All checks were successful
Build / build (push) Successful in 50s
2025-10-26 20:40:48 +01:00
a6294e46f2 Small changes to sync progress
All checks were successful
Build / build (push) Successful in 52s
2025-09-19 22:10:27 +02:00
5f91643b4d Added time to sync and progress respond
All checks were successful
Build / build (push) Successful in 1m58s
2025-08-30 13:36:45 +02:00
806e88adeb #1 - Created request to check newest version of the app
All checks were successful
Build / build (push) Successful in 2m35s
#2 - Added request to download the newest version of the app
#3 - Added request to check progress during sync
#4 - Now blocking all request while sync is in progress
#5 - Implemented ants for thread pooling
#6 - Changed the sync request to now only start the sync
2025-08-23 11:36:03 +02:00
32 changed files with 727 additions and 695 deletions

View File

@@ -1,6 +1,6 @@
name: Build
run-name: ${{ gitea.actor }} is runs ci pipeline
#on:
# release:
# types: [published]

View File

@@ -1,6 +1,6 @@
name: Publish
run-name: ${{ gitea.actor }} is runs ci pipeline
#on:
# release:
# types: [published]

7
.idea/dataSources.xml generated
View File

@@ -25,5 +25,12 @@
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://ssh.sanplex.xyz:9432/music_prod</jdbc-url>
</data-source>
<data-source source="LOCAL" name="music_test2@localhost" uuid="a423ab0a-55b0-42e1-8070-25d8ef34bfac">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://localhost:5432/music_test2</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

View File

@@ -21,6 +21,7 @@ FROM golang:1.23-alpine
EXPOSE 8080
VOLUME /sorted
VOLUME /frontend
VOLUME /characters
ENV PORT 8080
ENV DB_HOST ""
@@ -29,6 +30,7 @@ ENV DB_USERNAME ""
ENV DB_PASSWORD ""
ENV DB_NAME ""
ENV MUSIC_PATH ""
ENV CHARACTERS_PATH ""
COPY --from=build_go /app/main .
COPY ./songs/ ./songs/

View File

@@ -1,44 +1,131 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT
// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag
package docs
import "github.com/swaggo/swag"
import (
"bytes"
"encoding/json"
"strings"
"text/template"
const docTemplate = `{
"github.com/swaggo/swag"
)
var doc = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{escape .Description}}",
"title": "{{.Title}}",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Sebastian Olsson",
"email": "zarnor91@gmail.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"contact": {},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {}
"paths": {
"/version": {
"get": {
"description": "get string by ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"accounts"
],
"summary": "Getting the version of the backend",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/backend.VersionData"
}
},
"404": {
"description": "Not Found",
"schema": {
"type": "string"
}
}
}
}
}
},
"definitions": {
"backend.VersionData": {
"type": "object",
"properties": {
"changelog": {
"type": "string",
"example": "account name"
},
"history": {
"type": "array",
"items": {
"$ref": "#/definitions/backend.VersionData"
}
},
"version": {
"type": "string",
"example": "1.0.0"
}
}
}
}
}`
type swaggerInfo struct {
Version string
Host string
BasePath string
Schemes []string
Title string
Description string
}
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "0.5",
Host: "localhost:8080",
BasePath: "",
Schemes: []string{},
Title: "Swagger Example API",
Description: "This is a sample server Petstore server.",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
var SwaggerInfo = swaggerInfo{
Version: "",
Host: "",
BasePath: "",
Schemes: []string{},
Title: "",
Description: "",
}
type s struct{}
func (s *s) ReadDoc() string {
sInfo := SwaggerInfo
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
"escape": func(v interface{}) string {
// escape tabs
str := strings.Replace(v.(string), "\t", "\\t", -1)
// replace " with \", and if that results in \\", replace that with \\\"
str = strings.Replace(str, "\"", "\\\"", -1)
return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1)
},
}).Parse(doc)
if err != nil {
return doc
}
var tpl bytes.Buffer
if err := t.Execute(&tpl, sInfo); err != nil {
return doc
}
return tpl.String()
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
swag.Register("swagger", &s{})
}

View File

@@ -1,19 +1,58 @@
{
"swagger": "2.0",
"info": {
"description": "This is a sample server Petstore server.",
"title": "Swagger Example API",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Sebastian Olsson",
"email": "zarnor91@gmail.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "0.5"
"contact": {}
},
"host": "localhost:8080",
"paths": {}
"paths": {
"/version": {
"get": {
"description": "get string by ID",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"accounts"
],
"summary": "Getting the version of the backend",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/backend.VersionData"
}
},
"404": {
"description": "Not Found",
"schema": {
"type": "string"
}
}
}
}
}
},
"definitions": {
"backend.VersionData": {
"type": "object",
"properties": {
"changelog": {
"type": "string",
"example": "account name"
},
"history": {
"type": "array",
"items": {
"$ref": "#/definitions/backend.VersionData"
}
},
"version": {
"type": "string",
"example": "1.0.0"
}
}
}
}
}

View File

@@ -1,14 +1,37 @@
host: localhost:8080
definitions:
backend.VersionData:
properties:
changelog:
example: account name
type: string
history:
items:
$ref: '#/definitions/backend.VersionData'
type: array
version:
example: 1.0.0
type: string
type: object
info:
contact:
email: zarnor91@gmail.com
name: Sebastian Olsson
description: This is a sample server Petstore server.
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
termsOfService: http://swagger.io/terms/
title: Swagger Example API
version: "0.5"
paths: {}
contact: {}
paths:
/version:
get:
consumes:
- application/json
description: get string by ID
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/backend.VersionData'
"404":
description: Not Found
schema:
type: string
summary: Getting the version of the backend
tags:
- accounts
swagger: "2.0"

View File

@@ -7,14 +7,13 @@ import (
"music-server/internal/db"
"music-server/internal/server"
"net/http"
"os"
"os/signal"
"runtime/pprof"
"syscall"
"time"
)
// @title Swagger Example API
//
// @Title Swagger Example API
// @version 0.5
// @description This is a sample server Petstore server.
// @termsOfService http://swagger.io/terms/
@@ -25,15 +24,14 @@ import (
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @host localhost:8080
func main() {
f, perr := os.Create("cpu.pprof")
/*f, perr := os.Create("cpu.pprof")
if perr != nil {
log.Fatal(perr)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
defer pprof.StopCPUProfile()*/
server := server.NewServer()

36
go.mod
View File

@@ -5,15 +5,16 @@ go 1.23.0
toolchain go1.24.2
require (
github.com/MShekow/directory-checksum v1.4.6
github.com/a-h/templ v0.3.865
github.com/golang-migrate/migrate/v4 v4.18.1
github.com/jackc/pgx/v5 v5.5.5
github.com/labstack/echo/v4 v4.13.3
github.com/MShekow/directory-checksum v1.4.9
github.com/a-h/templ v0.3.937
github.com/golang-migrate/migrate/v4 v4.18.3
github.com/jackc/pgx/v5 v5.7.5
github.com/labstack/echo/v4 v4.13.4
github.com/lib/pq v1.10.9
github.com/spf13/afero v1.11.0
github.com/panjf2000/ants/v2 v2.11.3
github.com/spf13/afero v1.14.0
github.com/swaggo/echo-swagger v1.4.1
github.com/swaggo/swag v1.16.4
github.com/swaggo/swag v1.16.6
)
require (
@@ -30,12 +31,12 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/swaggo/files/v2 v2.0.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
@@ -43,12 +44,13 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
go.opentelemetry.io/otel/trace v1.32.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.8.0 // indirect
golang.org/x/tools v0.32.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/mod v0.26.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.27.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.35.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

80
go.sum
View File

@@ -2,22 +2,22 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/MShekow/directory-checksum v1.4.6 h1:2fhlCYbpjEN1iH9S0tdmEM0p1wvNT9x5x0rIchGI7nE=
github.com/MShekow/directory-checksum v1.4.6/go.mod h1:bMfFBkaIlNk7O9VgEi8D2X7Q2Jfk3c7d67z3t6cpIi4=
github.com/MShekow/directory-checksum v1.4.9 h1:olzWbrq9ylwfi7afuoivzHM8AV2z2KOaT7FJ6Ri2ppU=
github.com/MShekow/directory-checksum v1.4.9/go.mod h1:LhNeWmPftlKTlc3TNurdihPK/whw9j76VnLaTRu2SkU=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/a-h/templ v0.3.865 h1:nYn5EWm9EiXaDgWcMQaKiKvrydqgxDUtT1+4zU2C43A=
github.com/a-h/templ v0.3.865/go.mod h1:oLBbZVQ6//Q6zpvSMPTuBK0F3qOtBdFBcGRspcT+VNQ=
github.com/a-h/templ v0.3.937 h1:Ta+0Tf9YuZplUyKTUxReV36FCRKtK6FRMWpmXERHDnM=
github.com/a-h/templ v0.3.937/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
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/dhui/dktest v0.4.3 h1:wquqUxAFdcUgabAVLvSCOKOlag5cIZuaOjYIBOWdsR0=
github.com/dhui/dktest v0.4.3/go.mod h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs=
github.com/dhui/dktest v0.4.5 h1:uUfYBIVREmj/Rw6MvgmqNAYzTiKOHJak+enB5Di73MM=
github.com/dhui/dktest v0.4.5/go.mod h1:tmcyeHDKagvlDrz7gDKq4UAJOLIfVZYkfD5OnHDwcCo=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
@@ -48,8 +48,8 @@ github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyr
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y=
github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks=
github.com/golang-migrate/migrate/v4 v4.18.3 h1:EYGkoOsvgHHfm5U/naS1RP/6PL/Xv3S4B/swMiAmDLs=
github.com/golang-migrate/migrate/v4 v4.18.3/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -59,12 +59,12 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -74,8 +74,8 @@ 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/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
@@ -85,9 +85,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
@@ -101,14 +100,16 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
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=
@@ -119,8 +120,8 @@ github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO
github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc=
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
@@ -135,31 +136,30 @@ go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQD
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
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/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.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-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
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=

View File

@@ -1,14 +1,18 @@
package backend
import (
"fmt"
"log"
"os"
"strings"
)
func GetCharacters() []string {
musicPath := os.Getenv("MUSIC_PATH")
charactersPath := musicPath + "characters/"
func GetCharacterList() []string {
charactersPath := os.Getenv("CHARACTERS_PATH")
fmt.Printf("dir: %s\n", charactersPath)
if !strings.HasSuffix(charactersPath, "/") {
charactersPath += "/"
}
files, err := os.ReadDir(charactersPath)
if err != nil {
log.Fatal(err)
@@ -24,12 +28,15 @@ func GetCharacters() []string {
}
func GetCharacter(character string) string {
musicPath := os.Getenv("MUSIC_PATH")
charactersPath := musicPath + "characters/"
charactersPath := os.Getenv("CHARACTERS_PATH")
fmt.Printf("dir: %s\n", charactersPath)
if !strings.HasSuffix(charactersPath, "/") {
charactersPath += "/"
}
return charactersPath + character
}
func isImage(entry os.DirEntry) bool {
return !entry.IsDir() && (strings.HasSuffix(entry.Name(), ".jpg") || strings.HasSuffix(entry.Name(), ".png"))
return !entry.IsDir() && (strings.HasSuffix(entry.Name(), ".jpg") || strings.HasSuffix(entry.Name(), ".jpeg") ||
strings.HasSuffix(entry.Name(), ".png"))
}

View File

@@ -0,0 +1,106 @@
package backend
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
)
type giteaResponse struct {
Id int `json:"id"`
Name string `json:"name"`
Assets []assetResponse `json:"assets"`
}
type assetResponse struct {
Id int `json:"id"`
Name string `json:"name"`
DownloadUrl string `json:"browser_download_url"`
}
func CheckLatest() string {
resp, err := http.Get("https://gitea.sanplex.tech/api/v1/repos/sansan/MusicPlayer/releases/latest")
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
//Create a variable of the same type as our model
var cResp giteaResponse
//Decode the data
if err := json.NewDecoder(resp.Body).Decode(&cResp); err != nil {
fmt.Println(err)
log.Fatal("ooopsss! an error occurred, please try again")
}
log.Printf("Id: %v, Name: %v", cResp.Id, cResp.Name)
return cResp.Name
}
func ListAssetsOfLatest() []string {
resp, err := http.Get("https://gitea.sanplex.tech/api/v1/repos/sansan/MusicPlayer/releases/latest")
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
//Create a variable of the same type as our model
var cResp giteaResponse
//Decode the data
if err := json.NewDecoder(resp.Body).Decode(&cResp); err != nil {
fmt.Println(err)
log.Fatal("ooopsss! an error occurred, please try again")
}
log.Printf("Id: %v, Name: %v", cResp.Id, cResp.Name)
var assets []string
for _, asset := range cResp.Assets {
log.Printf("Id: %v, Name: %v, Asset: %v", cResp.Id, cResp.Name, asset.Name)
assets = append(assets, asset.Name)
}
return assets
}
func DownloadLatestWindows() string {
resp, err := http.Get("https://gitea.sanplex.tech/api/v1/repos/sansan/MusicPlayer/releases/latest")
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
//Create a variable of the same type as our model
var cResp giteaResponse
//Decode the data
if err := json.NewDecoder(resp.Body).Decode(&cResp); err != nil {
fmt.Println(err)
log.Fatal("ooopsss! an error occurred, please try again")
}
log.Printf("Id: %v, Name: %v", cResp.Id, cResp.Name)
for _, asset := range cResp.Assets {
log.Printf("Id: %v, Name: %v, Asset: %v", cResp.Id, cResp.Name, asset.Name)
if strings.HasSuffix(asset.Name, ".exe") {
return asset.DownloadUrl
}
}
return ""
}
func DownloadLatestLinux() string {
resp, err := http.Get("https://gitea.sanplex.tech/api/v1/repos/sansan/MusicPlayer/releases/latest")
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
//Create a variable of the same type as our model
var cResp giteaResponse
//Decode the data
if err := json.NewDecoder(resp.Body).Decode(&cResp); err != nil {
fmt.Println(err)
log.Fatal("ooopsss! an error occurred, please try again")
}
log.Printf("Id: %v, Name: %v", cResp.Id, cResp.Name)
for _, asset := range cResp.Assets {
log.Printf("Id: %v, Name: %v, Asset: %v", cResp.Id, cResp.Name, asset.Name)
if strings.HasSuffix(asset.Name, ".x86_64") {
return asset.DownloadUrl
}
}
return ""
}

View File

@@ -15,9 +15,26 @@ type VersionData struct {
}
func GetVersionHistory() VersionData {
data := VersionData{Version: "3.2",
Changelog: "Upgraded Go version and the version of all dependencies. Fixed som more bugs.",
data := VersionData{Version: "4.5.0",
Changelog: "#1 - Created request to check newest version of the app\n" +
"#2 - Added request to download the newest version of the app\n" +
"#3 - Added request to check progress during sync\n" +
"#4 - Now blocking all request while sync is in progress\n" +
"#5 - Implemented ants for thread pooling\n" +
"#6 - Changed the sync request to now only start the sync",
History: []VersionData{
{
Version: "4.0.0",
Changelog: "Changed framework from gin to Echo\n" +
"Reorganized the code\n" +
"Implemented sqlc\n" +
"Added support to send character images from the server\n" +
"Added function to create a new database of no one exists",
},
{
Version: "3.2",
Changelog: "Upgraded Go version and the version of all dependencies. Fixed som more bugs.",
},
{
Version: "3.1",
Changelog: "Fixed some bugs with songs not found made the application crash. Now checking if song exists and if not, remove song from DB and find another one. Frontend is now decoupled from the backend.",

View File

@@ -21,13 +21,10 @@ type SongInfo struct {
var currentSong = -1
// var games []models.GameData
var gamesNew []repository.Game
// var songQue []models.SongData
var songQueNew []repository.Song
// var lastFetched models.SongData
var lastFetchedNew repository.Song
var repo *repository.Queries
@@ -60,7 +57,6 @@ func Reset() {
currentSong = -1
initRepo()
gamesNew, _ = repo.FindAllGames(db.Ctx)
//games = db.FindAllGames()
}
func AddLatestToQue() {
@@ -80,8 +76,6 @@ func AddLatestPlayed() {
initRepo()
repo.AddGamePlayed(db.Ctx, currentSongData.GameID)
repo.AddSongPlayed(db.Ctx, repository.AddSongPlayedParams{GameID: currentSongData.GameID, SongName: currentSongData.SongName})
//db.AddGamePlayed(currentSongData.GameId)
//db.AddSongPlayed(currentSongData.GameId, currentSongData.SongName)
}
func SetPlayed(songNumber int) {
@@ -92,14 +86,9 @@ func SetPlayed(songNumber int) {
initRepo()
repo.AddGamePlayed(db.Ctx, songData.GameID)
repo.AddSongPlayed(db.Ctx, repository.AddSongPlayedParams{GameID: songData.GameID, SongName: songData.SongName})
//db.AddGamePlayed(songData.GameId)
//db.AddSongPlayed(songData.GameId, songData.SongName)
}
func GetRandomSong() string {
/*if len(games) == 0 {
games = db.FindAllGames()
}*/
getAllGames()
if len(gamesNew) == 0 {
return ""
@@ -111,12 +100,8 @@ func GetRandomSong() string {
}
func GetRandomSongLowChance() string {
/*if len(games) == 0 {
games = db.FindAllGames()
}*/
getAllGames()
//var listOfGames []models.GameData
var listOfGames []repository.Game
var averagePlayed = getAveragePlayed()
@@ -139,15 +124,10 @@ func GetRandomSongLowChance() string {
}
func GetRandomSongClassic() string {
/*if games == nil || len(games) == 0 {
games = db.FindAllGames()
}*/
getAllGames()
var listOfAllSongs []repository.Song
for _, game := range gamesNew {
//listOfAllSongs = append(listOfAllSongs, db.FindSongsFromGame(game.Id)...)
songList, _ := repo.FindSongsFromGame(db.Ctx, game.ID)
listOfAllSongs = append(listOfAllSongs, songList...)
}
@@ -156,14 +136,11 @@ func GetRandomSongClassic() string {
var song repository.Song
for !songFound {
song = listOfAllSongs[rand.Intn(len(listOfAllSongs))]
//gameData, err := db.GetGameById(song.GameId)
gameData, err := repo.GetGameById(db.Ctx, song.GameID)
if err != nil {
//db.RemoveBrokenSong(song)
repo.RemoveBrokenSong(db.Ctx, song.Path)
//log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %v\n", song.SongName, gameData.GameName, song.FileName)
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %s\n", song.SongName, gameData.GameName, *song.FileName)
continue
}
@@ -171,10 +148,8 @@ func GetRandomSongClassic() string {
openFile, err := os.Open(song.Path)
if err != nil || (song.FileName != nil && gameData.Path+*song.FileName != song.Path) {
//File not found
//db.RemoveBrokenSong(song)
repo.RemoveBrokenSong(db.Ctx, song.Path)
//log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %v\n", song.SongName, gameData.GameName, song.FileName)
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %s\n", song.SongName, gameData.GameName, *song.FileName)
} else {
songFound = true
}
@@ -234,9 +209,6 @@ func GetSong(song string) string {
}
func GetAllGames() []string {
/*if games == nil || len(games) == 0 {
games = db.FindAllGames()
}*/
getAllGames()
var jsonArray []string
@@ -247,9 +219,6 @@ func GetAllGames() []string {
}
func GetAllGamesRandom() []string {
/*if games == nil || len(games) == 0 {
games = db.FindAllGames()
}*/
getAllGames()
var jsonArray []string
@@ -293,10 +262,7 @@ func getSongFromList(games []repository.Game) repository.Song {
var song repository.Song
for !songFound {
game := getRandomGame(games)
//log.Println("game = ", game)
//songs := db.FindSongsFromGame(game.Id)
songs, _ := repo.FindSongsFromGame(db.Ctx, game.ID)
//log.Println("songs = ", songs)
if len(songs) == 0 {
continue
}
@@ -305,14 +271,9 @@ func getSongFromList(games []repository.Game) repository.Song {
//Check if file exists and open
openFile, err := os.Open(song.Path)
//log.Println("game.Path+song.FileName: ", game.Path+song.FileName)
//log.Println("song.Path: ", song.Path)
//log.Println("game.Path+song.FileName != song.Path: ", game.Path+song.FileName != song.Path)
if err != nil || (song.FileName != nil && game.Path+*song.FileName != song.Path) || (song.FileName != nil && strings.HasSuffix(*song.FileName, ".wav")) {
//File not found
//db.RemoveBrokenSong(song)
repo.RemoveBrokenSong(db.Ctx, song.Path)
//log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + game.GameName + "' FileName: " + song.FileName)
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %v\n", song.SongName, game.GameName, song.FileName)
} else {
songFound = true

View File

@@ -17,10 +17,19 @@ import (
"sync"
"time"
"github.com/panjf2000/ants/v2"
"github.com/MShekow/directory-checksum/directory_checksum"
"github.com/spf13/afero"
)
var Syncing = false
var foldersSynced float32
var numberOfFoldersToSync float32
var start time.Time
var totalTime time.Duration
var timeSpent time.Duration
var allGames []repository.Game
var gamesBeforeSync []repository.Game
var gamesAfterSync []repository.Game
@@ -32,13 +41,19 @@ var gamesRemoved []string
var catchedErrors []string
var brokenSongs []string
type Response struct {
type SyncResponse struct {
GamesAdded []string `json:"games_added"`
GamesReAdded []string `json:"games_re_added"`
GamesChangedTitle map[string]string `json:"games_changed_title"`
GamesChangedContent []string `json:"games_changed_content"`
GamesRemoved []string `json:"games_removed"`
CatchedErrors []string `json:"catched_errors"`
TotalTime string `json:"total_time"`
}
type ProgressResponse struct {
Progress string `json:"progress"`
TimeSpent string `json:"time_spent"`
}
type GameStatus int
@@ -61,67 +76,26 @@ func (gs GameStatus) String() string {
return statusName[gs]
}
var syncWg sync.WaitGroup
func ResetDB() {
//db.ClearSongs(-1)
repo.ClearSongs(db.Ctx)
//db.ClearGames()
repo.ClearGames(db.Ctx)
}
func SyncGamesNewFull() Response {
return syncGamesNew(true)
func SyncProgress() ProgressResponse {
progress := int((foldersSynced / numberOfFoldersToSync) * 100)
currentTime := time.Now()
timeSpent = currentTime.Sub(start)
out := time.Time{}.Add(timeSpent)
fmt.Printf("\nTime spent: %v\n", timeSpent)
fmt.Printf("Time spent: %v\n", out.Format("15:04:05.00000"))
log.Printf("Progress: %v/%v %v%%\n", int(foldersSynced), int(numberOfFoldersToSync), progress)
return ProgressResponse{
Progress: fmt.Sprintf("%v", progress),
TimeSpent: out.Format("15:04:05"),
}
}
func SyncGamesNewOnlyChanges() Response {
return syncGamesNew(false)
}
func syncGamesNew(full bool) Response {
musicPath := os.Getenv("MUSIC_PATH")
fmt.Printf("dir: %s\n", musicPath)
initRepo()
start := time.Now()
foldersToSkip := []string{".sync", "dist", "old", "characters"}
fmt.Println(foldersToSkip)
var err error
gamesAdded = nil
gamesReAdded = nil
gamesChangedTitle = nil
gamesChangedContent = nil
gamesRemoved = nil
catchedErrors = nil
brokenSongs = nil
gamesBeforeSync, err = repo.FindAllGames(db.Ctx)
handleError("FindAllGames Before", err, "")
fmt.Printf("Games Before: %d\n", len(gamesBeforeSync))
allGames, err = repo.GetAllGamesIncludingDeleted(db.Ctx)
handleError("GetAllGamesIncludingDeleted", err, "")
err = repo.SetGameDeletionDate(db.Ctx)
handleError("SetGameDeletionDate", err, "")
directories, err := os.ReadDir(musicPath)
if err != nil {
log.Fatal(err)
}
syncWg.Add(len(directories))
for _, dir := range directories {
go func() {
defer syncWg.Done()
syncGameNew(dir, foldersToSkip, musicPath, full)
}()
}
syncWg.Wait()
checkBrokenSongsNew()
gamesAfterSync, err = repo.FindAllGames(db.Ctx)
handleError("FindAllGames After", err, "")
func SyncResult() SyncResponse {
fmt.Printf("\nGames Before: %d\n", len(gamesBeforeSync))
fmt.Printf("Games After: %d\n", len(gamesAfterSync))
@@ -148,7 +122,7 @@ func syncGamesNew(full bool) Response {
fmt.Printf("\n\n")
var gamesRemovedTemp []string
for _, beforeGame := range gamesBeforeSync {
var found bool = false
var found = false
for _, afterGame := range gamesAfterSync {
if beforeGame.GameName == afterGame.GameName {
found = true
@@ -186,32 +160,110 @@ func syncGamesNew(full bool) Response {
fmt.Printf("%s\n", error)
}
finished := time.Now()
totalTime := finished.Sub(start)
out := time.Time{}.Add(totalTime)
fmt.Printf("\nTotal time: %v\n", totalTime)
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
return Response{
return SyncResponse{
GamesAdded: gamesAdded,
GamesReAdded: gamesReAdded,
GamesChangedTitle: gamesChangedTitle,
GamesChangedContent: gamesChangedContent,
GamesRemoved: gamesRemoved,
CatchedErrors: catchedErrors,
TotalTime: out.Format("15:04:05"),
}
}
func SyncGamesNewFull() {
syncGamesNew(true)
Reset()
}
func SyncGamesNewOnlyChanges() {
syncGamesNew(false)
Reset()
}
func syncGamesNew(full bool) {
Syncing = true
musicPath := os.Getenv("MUSIC_PATH")
fmt.Printf("dir: %s\n", musicPath)
if !strings.HasSuffix(musicPath, "/") {
musicPath += "/"
}
var syncWg sync.WaitGroup
initRepo()
start = time.Now()
foldersToSkip := []string{".sync", "dist", "old", "characters"}
fmt.Println(foldersToSkip)
var err error
gamesAdded = nil
gamesReAdded = nil
gamesChangedTitle = nil
gamesChangedContent = nil
gamesRemoved = nil
catchedErrors = nil
brokenSongs = nil
gamesBeforeSync, err = repo.FindAllGames(db.Ctx)
handleError("FindAllGames Before", err, "")
fmt.Printf("Games Before: %d\n", len(gamesBeforeSync))
allGames, err = repo.GetAllGamesIncludingDeleted(db.Ctx)
handleError("GetAllGamesIncludingDeleted", err, "")
err = repo.SetGameDeletionDate(db.Ctx)
handleError("SetGameDeletionDate", err, "")
directories, err := os.ReadDir(musicPath)
if err != nil {
log.Fatal(err)
}
pool, _ := ants.NewPool(50, ants.WithPreAlloc(true))
defer pool.Release()
foldersSynced = 0
numberOfFoldersToSync = float32(len(directories))
syncWg.Add(int(numberOfFoldersToSync))
for _, dir := range directories {
pool.Submit(func() {
defer syncWg.Done()
syncGameNew(dir, foldersToSkip, musicPath, full)
})
}
syncWg.Wait()
checkBrokenSongsNew()
gamesAfterSync, err = repo.FindAllGames(db.Ctx)
handleError("FindAllGames After", err, "")
finished := time.Now()
totalTime = finished.Sub(start)
out := time.Time{}.Add(totalTime)
fmt.Printf("\nTotal time: %v\n", totalTime)
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
Syncing = false
}
func checkBrokenSongsNew() {
allSongs, err := repo.FetchAllSongs(db.Ctx)
handleError("FetchAllSongs", err, "")
var brokenWg sync.WaitGroup
poolBroken, _ := ants.NewPool(50, ants.WithPreAlloc(true))
defer poolBroken.Release()
brokenWg.Add(len(allSongs))
for _, song := range allSongs {
go func() {
poolBroken.Submit(func() {
defer brokenWg.Done()
checkBrokenSongNew(song)
}()
})
}
brokenWg.Wait()
err = repo.RemoveBrokenSongs(db.Ctx, brokenSongs)
@@ -343,6 +395,8 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full
err = repo.RemoveDeletionDate(db.Ctx, id)
handleError("RemoveDeletionDate", err, "")
}
foldersSynced++
log.Printf("Progress: %v/%v %v%%\n", int(foldersSynced), int(numberOfFoldersToSync), int((foldersSynced/numberOfFoldersToSync)*100))
}
func insertGameNew(name string, path string, hash string) int32 {
@@ -365,19 +419,26 @@ func insertGameNew(name string, path string, hash string) int32 {
func newCheckSongs(entries []os.DirEntry, gameDir string, id int32) int32 {
//hasher := md5.New()
var numberOfSongs int32
numberOfFiles := len(entries)
var songWg sync.WaitGroup
songWg.Add(len(entries))
poolSong, _ := ants.NewPool(numberOfFiles, ants.WithPreAlloc(true))
defer poolSong.Release()
songWg.Add(numberOfFiles)
for _, entry := range entries {
go func() {
poolSong.Submit(func() {
defer songWg.Done()
newCheckSong(entry, gameDir, id)
}()
if newCheckSong(entry, gameDir, id) {
numberOfSongs++
}
})
}
songWg.Wait()
return numberOfSongs
}
func newCheckSong(entry os.DirEntry, gameDir string, id int32) {
func newCheckSong(entry os.DirEntry, gameDir string, id int32) bool {
fileInfo, err := entry.Info()
if err != nil {
log.Println(err)
@@ -396,7 +457,7 @@ func newCheckSong(entry os.DirEntry, gameDir string, id int32) {
handleError("GetSongWithHash", err, fmt.Sprintf("GameID: %d | Path: %s | SongName: %s | SongHash: %s\n", id, path, entry.Name(), songHash))
if err == nil {
if song.SongName == songName && song.Path == path {
return
return false
}
}
fmt.Printf("Song Changed\n")
@@ -432,9 +493,11 @@ func newCheckSong(entry os.DirEntry, gameDir string, id int32) {
}
}
return true
} else if isCoverImage(fileInfo) {
//TODO: Later add cover art image here in db
}
return false
}
func handleError(funcName string, err error, msg string) {

View File

@@ -1,103 +0,0 @@
package database
import (
"fmt"
"music-server/internal/db"
"os"
"time"
)
type gameData struct {
Id int
GameName string
Added time.Time
Deleted time.Time
LastChanged time.Time
Path string
TimesPlayed int
LastPlayed time.Time
NumberOfSongs int32
}
func GetGameName(gameId int) string {
var gameName = ""
err := db.Dbpool.QueryRow(db.Ctx,
"SELECT game_name FROM game WHERE id = $1", gameId).Scan(&gameName)
if err != nil {
if compareError.Error() != err.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
return ""
}
return gameName
}
func SetGameDeletionDate() {
_, err := db.Dbpool.Exec(db.Ctx,
"UPDATE game SET deleted=$1 WHERE deleted IS NULL", time.Now())
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}
func UpdateGameName(id int, name string, path string) {
_, err := db.Dbpool.Exec(db.Ctx,
"UPDATE game SET game_name=$1, path=$2, last_changed=$3 WHERE id=$4",
name, path, time.Now(), id)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}
func RemoveDeletionDate(id int) {
_, err := db.Dbpool.Exec(db.Ctx,
"UPDATE game SET deleted=null WHERE id=$1", id)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}
func GetIdByGameName(name string) int {
var gameId = -1
err := db.Dbpool.QueryRow(db.Ctx,
"SELECT id FROM game WHERE game_name = $1", name).Scan(&gameId)
if err != nil {
if compareError.Error() != err.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
return -1
}
return gameId
}
func InsertGame(name string, path string) int {
gameId := -1
err := db.Dbpool.QueryRow(db.Ctx,
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
name, path, time.Now()).Scan(&gameId)
if err != nil {
if compareError.Error() != err.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
db.ResetGameIdSeq()
err2 := db.Dbpool.QueryRow(db.Ctx,
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
name, path, time.Now()).Scan(&gameId)
if err2 != nil {
if compareError.Error() != err2.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
return -1
}
}
return gameId
}
func InsertGameWithExistingId(id int, name string, path string) {
_, err := db.Dbpool.Exec(db.Ctx,
"INSERT INTO game(id, game_name, path, added) VALUES ($1, $2, $3, $4)",
id, name, path, time.Now())
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}

View File

@@ -1,206 +0,0 @@
package database
import (
"fmt"
"io/fs"
"log"
"os"
"sort"
"strconv"
"strings"
"sync"
"time"
)
var wg sync.WaitGroup
func SyncGames() {
start := time.Now()
dir := os.Getenv("MUSIC_PATH")
fmt.Printf("dir: %s\n", dir)
foldersToSkip := []string{".sync", "dist", "old", "characters"}
fmt.Println(foldersToSkip)
SetGameDeletionDate()
checkBrokenSongs()
files, err := os.ReadDir(dir)
if err != nil {
log.Fatal(err)
}
for _, file := range files {
syncGame(file, foldersToSkip, dir)
}
finished := time.Now()
totalTime := finished.Sub(start)
out := time.Time{}.Add(totalTime)
fmt.Printf("\nTotal time: %v\n", totalTime)
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
}
func SyncGamesQuick() {
start := time.Now()
dir := os.Getenv("MUSIC_PATH")
fmt.Printf("dir: %s\n", dir)
foldersToSkip := []string{".sync", "dist", "old", "characters"}
fmt.Println(foldersToSkip)
SetGameDeletionDate()
checkBrokenSongs()
files, err := os.ReadDir(dir)
if err != nil {
log.Fatal(err)
}
for _, file := range files {
wg.Add(1)
go func() {
defer wg.Done()
syncGame(file, foldersToSkip, dir)
}()
}
wg.Wait()
finished := time.Now()
totalTime := finished.Sub(start)
out := time.Time{}.Add(totalTime)
fmt.Printf("\nTotal time: %v\n", totalTime)
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
}
func syncGame(file os.DirEntry, foldersToSkip []string, dir string) {
if file.IsDir() && !contains(foldersToSkip, file.Name()) {
fmt.Println(file.Name())
path := dir + file.Name() + "/"
fmt.Println(path)
entries, err := os.ReadDir(path)
if err != nil {
log.Println(err)
}
id := -1
for _, entry := range entries {
fileInfo, err := entry.Info()
if err != nil {
log.Println(err)
}
id = getIdFromFile(fileInfo)
if id != -1 {
break
}
}
if id == -1 {
addNewGame(file.Name(), path)
} else {
checkIfChanged(id, file.Name(), path)
checkSongs(path, id)
}
}
}
func getIdFromFile(file os.FileInfo) int {
name := file.Name()
if !file.IsDir() && strings.HasSuffix(name, ".id") {
name = strings.Replace(name, ".id", "", 1)
name = strings.Replace(name, ".", "", 1)
i, _ := strconv.Atoi(name)
return i
}
return -1
}
func checkIfChanged(id int, name string, path string) {
fmt.Printf("Id from file: %v\n", id)
nameFromDb := GetGameName(id)
fmt.Printf("Name from file: %v\n", name)
fmt.Printf("Name from DB: %v\n", nameFromDb)
if nameFromDb == "" {
fmt.Println("Not in db")
InsertGameWithExistingId(id, name, path)
fmt.Println("Added to db")
} else if name != nameFromDb {
fmt.Println("Diff name")
UpdateGameName(id, name, path)
checkBrokenSongs()
}
RemoveDeletionDate(id)
}
func addNewGame(name string, path string) {
newId := GetIdByGameName(name)
if newId != -1 {
checkBrokenSongs()
RemoveDeletionDate(newId)
} else {
newId = InsertGame(name, path)
}
fmt.Printf("newId = %v", newId)
fileName := path + "/." + strconv.Itoa(newId) + ".id"
fmt.Printf("fileName = %v", fileName)
err := os.WriteFile(fileName, nil, 0644)
if err != nil {
panic(err)
}
checkSongs(path, newId)
}
func checkSongs(gameDir string, gameId int) {
files, err := os.ReadDir(gameDir)
if err != nil {
log.Println(err)
}
for _, file := range files {
entry, err := file.Info()
if err != nil {
log.Println(err)
}
if isSong(entry) {
path := gameDir + entry.Name()
fileName := entry.Name()
songName, _ := strings.CutSuffix(fileName, ".mp3")
if CheckSong(path) {
UpdateSong(songName, fileName, path)
} else {
AddSong(SongData{GameId: gameId, SongName: songName, Path: path, FileName: fileName})
}
} else if isCoverImage(entry) {
//TODO: Later add cover art image here in db
}
}
//TODO: Add number of songs here
}
func checkBrokenSongs() {
allSongs := FetchAllSongs()
var brokenSongs []SongData
for _, song := range allSongs {
//Check if file exists and open
openFile, err := os.Open(song.Path)
if err != nil {
//File not found
brokenSongs = append(brokenSongs, song)
fmt.Printf("song broken: %v", song.Path)
} else {
err = openFile.Close()
if err != nil {
log.Println(err)
}
}
}
RemoveBrokenSongs(brokenSongs)
}
func isSong(entry fs.FileInfo) bool {
return !entry.IsDir() && strings.HasSuffix(entry.Name(), ".mp3")
}
func isCoverImage(entry fs.FileInfo) bool {
return !entry.IsDir() && strings.Contains(entry.Name(), "cover") &&
(strings.HasSuffix(entry.Name(), ".jpg") || strings.HasSuffix(entry.Name(), ".png"))
}
func contains(s []string, searchTerm string) bool {
i := sort.SearchStrings(s, searchTerm)
return i < len(s) && s[i] == searchTerm
}

View File

@@ -1,92 +0,0 @@
package database
import (
"errors"
"fmt"
"music-server/internal/db"
"os"
"strings"
)
type SongData struct {
GameId int
SongName string
Path string
TimesPlayed int
FileName string
}
var compareError = errors.New("no rows in result set")
func AddSong(song SongData) {
_, err := db.Dbpool.Exec(db.Ctx,
"INSERT INTO song(game_id, song_name, path, file_name) VALUES ($1, $2, $3, $4)",
song.GameId, song.SongName, song.Path, song.FileName)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}
func CheckSong(songPath string) bool {
var path string
err := db.Dbpool.QueryRow(db.Ctx,
"SELECT path FROM song WHERE path = $1", songPath).Scan(&path)
if err != nil {
if compareError.Error() != err.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
}
return path != ""
}
func UpdateSong(songName string, fileName string, path string) {
_, err := db.Dbpool.Exec(db.Ctx,
"UPDATE song SET song_name=$1, file_name=$2 WHERE path = $3",
songName, fileName, path)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}
func FetchAllSongs() []SongData {
rows, err := db.Dbpool.Query(db.Ctx,
"SELECT song_name, path FROM song")
if err != nil {
if compareError.Error() != err.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
return nil
}
var songDataList []SongData
for rows.Next() {
var songName string
var path string
err := rows.Scan(&songName, &path)
if err != nil {
if compareError.Error() != err.Error() {
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
}
}
songDataList = append(songDataList, SongData{
SongName: songName,
Path: path,
})
}
return songDataList
}
func RemoveBrokenSongs(songs []SongData) {
joined := ""
for _, song := range songs {
joined += "'" + song.Path + "',"
}
joined = strings.TrimSuffix(joined, ",")
_, err := db.Dbpool.Exec(db.Ctx, "DELETE FROM song where path in ($1)", joined)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
}
}

View File

@@ -46,7 +46,6 @@ func InitDB(host string, port string, user string, password string, dbname strin
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
os.Exit(1)
}
Testf()
fmt.Println(success)
}

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.29.0
package repository

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.29.0
// source: game.sql
package repository

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.29.0
package repository

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.29.0
// source: song.sql
package repository

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.29.0
// source: song_list.sql
package repository

View File

@@ -0,0 +1,41 @@
package server
import (
"github.com/labstack/echo/v4"
"log"
"music-server/internal/backend"
"net/http"
)
type DownloadHandler struct {
}
func NewDownloadHandler() *DownloadHandler {
return &DownloadHandler{}
}
func (d *DownloadHandler) checkLatest(ctx echo.Context) error {
log.Println("Checking latest version")
latest := backend.CheckLatest()
return ctx.JSON(http.StatusOK, latest)
}
func (d *DownloadHandler) listAssetsOfLatest(ctx echo.Context) error {
log.Println("Listing assets")
assets := backend.ListAssetsOfLatest()
return ctx.JSON(http.StatusOK, assets)
}
func (d *DownloadHandler) downloadLatestWindows(ctx echo.Context) error {
log.Println("Downloading latest windows")
asset := backend.DownloadLatestWindows()
ctx.Response().Header().Set("Content-Type", "application/octet-stream")
return ctx.Redirect(http.StatusFound, asset)
}
func (d *DownloadHandler) downloadLatestLinux(ctx echo.Context) error {
log.Println("Downloading latest linux")
asset := backend.DownloadLatestLinux()
ctx.Response().Header().Set("Content-Type", "application/octet-stream")
return ctx.Redirect(http.StatusFound, asset)
}

View File

@@ -42,12 +42,12 @@ func (i *IndexHandler) HealthCheck(ctx echo.Context) error {
return ctx.JSON(http.StatusOK, db.Health())
}
func (i *IndexHandler) GetCharacters(ctx echo.Context) error {
characters := backend.GetCharacters()
func (i *IndexHandler) GetCharacterList(ctx echo.Context) error {
characters := backend.GetCharacterList()
return ctx.JSON(http.StatusOK, characters)
}
func (i *IndexHandler) GetCharacter(ctx echo.Context) error {
character := ctx.QueryParam("character")
character := ctx.QueryParam("name")
return ctx.File(backend.GetCharacter(character))
}

View File

@@ -1,9 +1,11 @@
package server
import (
"log"
"music-server/internal/backend"
"net/http"
"os"
"strconv"
"github.com/labstack/echo/v4"
)
@@ -16,6 +18,10 @@ func NewMusicHandler() *MusicHandler {
}
func (m *MusicHandler) GetSong(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
song := ctx.QueryParam("song")
if song == "" {
return ctx.String(http.StatusBadRequest, "song can't be empty")
@@ -30,6 +36,10 @@ func (m *MusicHandler) GetSong(ctx echo.Context) error {
}
func (m *MusicHandler) GetSoundCheckSong(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
songPath := backend.GetSoundCheckSong()
file, err := os.Open(songPath)
if err != nil {
@@ -40,11 +50,19 @@ func (m *MusicHandler) GetSoundCheckSong(ctx echo.Context) error {
}
func (m *MusicHandler) ResetMusic(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
backend.Reset()
return ctx.NoContent(http.StatusOK)
}
func (m *MusicHandler) GetRandomSong(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
songPath := backend.GetRandomSong()
file, err := os.Open(songPath)
if err != nil {
@@ -55,6 +73,10 @@ func (m *MusicHandler) GetRandomSong(ctx echo.Context) error {
}
func (m *MusicHandler) GetRandomSongLowChance(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
songPath := backend.GetRandomSongLowChance()
file, err := os.Open(songPath)
if err != nil {
@@ -65,6 +87,10 @@ func (m *MusicHandler) GetRandomSongLowChance(ctx echo.Context) error {
}
func (m *MusicHandler) GetRandomSongClassic(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
songPath := backend.GetRandomSongClassic()
file, err := os.Open(songPath)
if err != nil {
@@ -85,6 +111,10 @@ func (m *MusicHandler) GetPlayedSongs(ctx echo.Context) error {
}
func (m *MusicHandler) GetNextSong(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
songPath := backend.GetNextSong()
file, err := os.Open(songPath)
if err != nil {
@@ -95,6 +125,10 @@ func (m *MusicHandler) GetNextSong(ctx echo.Context) error {
}
func (m *MusicHandler) GetPreviousSong(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
songPath := backend.GetPreviousSong()
file, err := os.Open(songPath)
if err != nil {
@@ -105,35 +139,51 @@ func (m *MusicHandler) GetPreviousSong(ctx echo.Context) error {
}
func (m *MusicHandler) GetAllGames(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
gameList := backend.GetAllGames()
return ctx.JSON(http.StatusOK, gameList)
}
func (m *MusicHandler) GetAllGamesRandom(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
gameList := backend.GetAllGamesRandom()
return ctx.JSON(http.StatusOK, gameList)
}
type played struct {
Song int
}
func (m *MusicHandler) PutPlayed(ctx echo.Context) error {
var played played
err := ctx.Bind(&played)
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
song, err := strconv.Atoi(ctx.QueryParam("song"))
if err != nil {
return ctx.JSON(http.StatusBadRequest, err)
}
backend.SetPlayed(played.Song)
log.Println("song", song)
backend.SetPlayed(song)
return ctx.NoContent(http.StatusOK)
}
func (m *MusicHandler) AddLatestToQue(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
backend.AddLatestToQue()
return ctx.NoContent(http.StatusOK)
}
func (m *MusicHandler) AddLatestPlayed(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
backend.AddLatestPlayed()
return ctx.NoContent(http.StatusOK)
}

View File

@@ -12,10 +12,22 @@ import (
"github.com/a-h/templ"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
echoSwagger "github.com/swaggo/echo-swagger" // echo-swagger middleware
"github.com/swaggo/echo-swagger" // echo-swagger middleware
//_ "github.com/swaggo/echo-swagger/example/docs" // docs is generated by Swag CLI, you have to import it.
)
// @Title Swagger Example API
// @version 0.5
// @description This is a sample server Petstore server.
// @termsOfService http://swagger.io/terms/
// @contact.name Sebastian Olsson
// @contact.email zarnor91@gmail.com
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
func (s *Server) RegisterRoutes() http.Handler {
e := echo.New()
e.Use(middleware.Logger())
@@ -37,29 +49,37 @@ func (s *Server) RegisterRoutes() http.Handler {
e.Static("/", "/frontend")
swagger := http.FileServer(http.FS(web.Swagger))
e.GET("/swagger/*", echo.WrapHandler(swagger))
/*swagger := http.FileServer(http.FS(web.Swagger))
e.GET("/swagger/*", echo.WrapHandler(swagger))*/
swaggerRedirect := func(c echo.Context) error {
return c.Redirect(http.StatusMovedPermanently, "/doc/index.html")
return c.Redirect(http.StatusMovedPermanently, "/swagger/index.html")
}
e.GET("/doc", swaggerRedirect)
e.GET("/doc/", swaggerRedirect)
e.GET("/doc/*", echoSwagger.WrapHandler)
e.GET("/swagger", swaggerRedirect)
e.GET("/swagger/", swaggerRedirect)
e.GET("/swagger/*", echoSwagger.WrapHandler)
index := NewIndexHandler()
e.GET("/version", index.GetVersion)
e.GET("/dbtest", index.GetDBTest)
e.GET("/health", index.HealthCheck)
e.GET("/character", index.GetCharacter)
e.GET("/characters", index.GetCharacters)
e.GET("/characters", index.GetCharacterList)
download := NewDownloadHandler()
e.GET("/download", download.checkLatest)
e.GET("/download/list", download.listAssetsOfLatest)
e.GET("/download/windows", download.downloadLatestWindows)
e.GET("/download/linux", download.downloadLatestLinux)
sync := NewSyncHandler()
syncGroup := e.Group("/sync")
syncGroup.GET("", sync.SyncGames)
syncGroup.GET("", sync.SyncGamesNewOnlyChanges)
syncGroup.GET("/progress", sync.SyncProgress)
syncGroup.GET("/new", sync.SyncGamesNewOnlyChanges)
syncGroup.GET("/full", sync.SyncGamesNewFull)
syncGroup.GET("/new/full", sync.SyncGamesNewFull)
syncGroup.GET("/quick", sync.SyncGamesQuick)
syncGroup.GET("/quick", sync.SyncGamesNewOnlyChanges)
syncGroup.GET("/reset", sync.ResetGames)
music := NewMusicHandler()

View File

@@ -15,12 +15,13 @@ type Server struct {
}
var (
host = os.Getenv("DB_HOST")
dbPort = os.Getenv("DB_PORT")
dbName = os.Getenv("DB_NAME")
username = os.Getenv("DB_USERNAME")
password = os.Getenv("DB_PASSWORD")
musicPath = os.Getenv("MUSIC_PATH")
host = os.Getenv("DB_HOST")
dbPort = os.Getenv("DB_PORT")
dbName = os.Getenv("DB_NAME")
username = os.Getenv("DB_USERNAME")
password = os.Getenv("DB_PASSWORD")
musicPath = os.Getenv("MUSIC_PATH")
charactersPath = os.Getenv("CHARACTERS_PATH")
)
func NewServer() *http.Server {
@@ -30,15 +31,16 @@ func NewServer() *http.Server {
port: port,
}
//conf.SetupDb()
if host == "" || dbPort == "" || username == "" || password == "" || dbName == "" || musicPath == "" {
log.Fatal("Invalid settings")
}
fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n",
host, dbPort, username, password, dbName)
log.Printf("Path: %s\n", musicPath)
log.Printf("musicPath: %s\n", musicPath)
log.Printf("charactersPath: %s\n", charactersPath)
//conf.SetupDb()
if host == "" || dbPort == "" || username == "" || password == "" || dbName == "" || musicPath == "" || charactersPath == "" {
log.Fatal("Invalid settings")
}
db.Migrate_db(host, dbPort, username, password, dbName)

View File

@@ -3,7 +3,6 @@ package server
import (
"log"
"music-server/internal/backend"
"music-server/internal/database"
"net/http"
"github.com/labstack/echo/v4"
@@ -16,33 +15,42 @@ func NewSyncHandler() *SyncHandler {
return &SyncHandler{}
}
func (s *SyncHandler) SyncGames(ctx echo.Context) error {
database.SyncGames()
backend.Reset()
return ctx.JSON(http.StatusOK, "Games are synced")
}
func (s *SyncHandler) SyncGamesQuick(ctx echo.Context) error {
database.SyncGamesQuick()
backend.Reset()
return ctx.JSON(http.StatusOK, "Games are synced")
func (s *SyncHandler) SyncProgress(ctx echo.Context) error {
if backend.Syncing {
log.Println("Getting progress")
response := backend.SyncProgress()
return ctx.JSON(http.StatusOK, response)
}
log.Println("Getting result")
response := backend.SyncResult()
return ctx.JSON(http.StatusOK, response)
}
func (s *SyncHandler) SyncGamesNewOnlyChanges(ctx echo.Context) error {
log.Println("Syncing games new")
response := backend.SyncGamesNewOnlyChanges()
backend.Reset()
return ctx.JSON(http.StatusOK, response)
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
log.Println("Start syncing games")
go backend.SyncGamesNewOnlyChanges()
return ctx.JSON(http.StatusOK, "Start syncing games")
}
func (s *SyncHandler) SyncGamesNewFull(ctx echo.Context) error {
log.Println("Syncing games new full")
response := backend.SyncGamesNewFull()
backend.Reset()
return ctx.JSON(http.StatusOK, response)
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
log.Println("Start syncing games full")
go backend.SyncGamesNewFull()
return ctx.JSON(http.StatusOK, "Start syncing games full")
}
func (s *SyncHandler) ResetGames(ctx echo.Context) error {
if backend.Syncing {
log.Println("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress")
}
backend.ResetDB()
return ctx.JSON(http.StatusOK, "Games and songs are deleted from the database")
}

View File

@@ -41,10 +41,11 @@ sqlc-generate:
migrate-create name:
@migrate create -ext sql -dir internal/db/migrations -seq {{name}}
[no-cd]
build: sqlc-generate templ-build tailwind-build
@echo "Building..."
@swag init -d ./cmd/,./internal/backend/ -o ./cmd/docs
@go build -o main cmd/main.go
@echo "Building..."
@swag init -g routes.go -d ./internal/server/,./internal/backend/ -o ./cmd/docs
@go build -o main cmd/main.go
run:
@templ generate

BIN
main

Binary file not shown.