Changed the structure of the whole application, should be no changes to functionality.
This commit is contained in:
19
.idea/MusicServer.iml
generated
19
.idea/MusicServer.iml
generated
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="Go" enabled="true">
|
|
||||||
<buildTags>
|
|
||||||
<option name="customFlags">
|
|
||||||
<array>
|
|
||||||
<option value="appengine" />
|
|
||||||
</array>
|
|
||||||
</option>
|
|
||||||
</buildTags>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.idea/dataSources" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
11
.idea/dataSources.xml
generated
11
.idea/dataSources.xml
generated
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="music_dev_local@localhost" uuid="e63caf71-2b1a-400d-9cc4-4b87b1f9b807">
|
|
||||||
<driver-ref>postgresql</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:postgresql://localhost:5432/music_dev_local</jdbc-url>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/MusicServer.iml" filepath="$PROJECT_DIR$/.idea/MusicServer.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
192
.idea/workspace.xml
generated
192
.idea/workspace.xml
generated
@@ -1,192 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="BranchesTreeState">
|
|
||||||
<expand>
|
|
||||||
<path>
|
|
||||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
<item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
</path>
|
|
||||||
<path>
|
|
||||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
<item name="REMOTE_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
</path>
|
|
||||||
<path>
|
|
||||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
<item name="REMOTE_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
<item name="GROUP_NODE:origin" type="e8cecc67:BranchNodeDescriptor" />
|
|
||||||
</path>
|
|
||||||
</expand>
|
|
||||||
<select />
|
|
||||||
</component>
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="d639f8a9-4b6d-4957-9ba4-8361acac15ca" name="Default Changelist" comment="">
|
|
||||||
<change afterPath="$PROJECT_DIR$/indexFacade.go" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/app.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/app.yaml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/musicFacade.go" beforeDir="false" afterPath="$PROJECT_DIR$/musicFacade.go" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/musicserver.go" beforeDir="false" afterPath="$PROJECT_DIR$/musicserver.go" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="FileTemplateManagerImpl">
|
|
||||||
<option name="RECENT_TEMPLATES">
|
|
||||||
<list>
|
|
||||||
<option value="Go File" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="GOROOT" path="/usr/local/Cellar/go/1.15.5/libexec" />
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectId" id="1ipVJv6kTmBdByNysh6NxmS21gD" />
|
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">
|
|
||||||
<property name="ASKED_SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
|
|
||||||
<property name="DatabaseDriversLRU" value="postgresql" />
|
|
||||||
<property name="DefaultGoTemplateProperty" value="Go File" />
|
|
||||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
|
||||||
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
|
|
||||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
|
||||||
<property name="go.import.settings.migrated" value="true" />
|
|
||||||
<property name="go.tried.to.enable.integration.vgo.integrator" value="true" />
|
|
||||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/songs" />
|
|
||||||
<property name="node.js.detected.package.eslint" value="true" />
|
|
||||||
<property name="node.js.detected.package.tslint" value="true" />
|
|
||||||
<property name="node.js.path.for.package.eslint" value="project" />
|
|
||||||
<property name="node.js.path.for.package.tslint" value="project" />
|
|
||||||
<property name="node.js.selected.package.eslint" value="(autodetect)" />
|
|
||||||
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
|
||||||
<property name="restartRequiresConfirmation" value="false" />
|
|
||||||
</component>
|
|
||||||
<component name="RecentsManager">
|
|
||||||
<key name="CopyFile.RECENT_KEYS">
|
|
||||||
<recent name="$PROJECT_DIR$/songs" />
|
|
||||||
</key>
|
|
||||||
</component>
|
|
||||||
<component name="RunManager" selected="Go Build.App Engine">
|
|
||||||
<configuration name="App Engine" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
|
||||||
<module name="MusicServer" />
|
|
||||||
<working_directory value="$PROJECT_DIR$" />
|
|
||||||
<go_parameters value="-i" />
|
|
||||||
<kind value="PACKAGE" />
|
|
||||||
<filePath value="$PROJECT_DIR$" />
|
|
||||||
<package value="MusicServer" />
|
|
||||||
<directory value="$PROJECT_DIR$" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<configuration name="Dockerfile" type="docker-deploy" factoryName="dockerfile" temporary="true" server-name="Docker">
|
|
||||||
<deployment type="dockerfile">
|
|
||||||
<settings>
|
|
||||||
<option name="sourceFilePath" value="Dockerfile" />
|
|
||||||
</settings>
|
|
||||||
</deployment>
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<configuration name="Dockerfile" type="docker-deploy" factoryName="dockerfile" temporary="true" server-name="Docker">
|
|
||||||
<deployment type="dockerfile">
|
|
||||||
<settings>
|
|
||||||
<option name="imageTag" value="sansan91/music-server:2.0.0" />
|
|
||||||
<option name="buildCliOptions" value="" />
|
|
||||||
<option name="command" value="" />
|
|
||||||
<option name="containerName" value="music-server-go" />
|
|
||||||
<option name="entrypoint" value="" />
|
|
||||||
<option name="envVars">
|
|
||||||
<list>
|
|
||||||
<DockerEnvVarImpl>
|
|
||||||
<option name="name" value="DB_HOST" />
|
|
||||||
<option name="value" value="ssh.sanplex.xyz" />
|
|
||||||
</DockerEnvVarImpl>
|
|
||||||
<DockerEnvVarImpl>
|
|
||||||
<option name="name" value="DB_USERNAME" />
|
|
||||||
<option name="value" value="postgres" />
|
|
||||||
</DockerEnvVarImpl>
|
|
||||||
<DockerEnvVarImpl>
|
|
||||||
<option name="name" value="DB_PASSWORD" />
|
|
||||||
<option name="value" value="DkrSle9501" />
|
|
||||||
</DockerEnvVarImpl>
|
|
||||||
<DockerEnvVarImpl>
|
|
||||||
<option name="name" value="DB_NAME" />
|
|
||||||
<option name="value" value="music_test" />
|
|
||||||
</DockerEnvVarImpl>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
<option name="portBindings">
|
|
||||||
<list>
|
|
||||||
<DockerPortBindingImpl>
|
|
||||||
<option name="containerPort" value="8080" />
|
|
||||||
<option name="hostPort" value="8080" />
|
|
||||||
</DockerPortBindingImpl>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
<option name="commandLineOptions" value="" />
|
|
||||||
<option name="sourceFilePath" value="Dockerfile" />
|
|
||||||
<option name="volumeBindings">
|
|
||||||
<list>
|
|
||||||
<DockerVolumeBindingImpl>
|
|
||||||
<option name="containerPath" value="/sorted" />
|
|
||||||
<option name="hostPath" value="$USER_HOME$/Resilio Sync/Sorterat_test" />
|
|
||||||
</DockerVolumeBindingImpl>
|
|
||||||
<DockerVolumeBindingImpl>
|
|
||||||
<option name="containerPath" value="/doc" />
|
|
||||||
<option name="hostPath" value="$USER_HOME$/doc" />
|
|
||||||
</DockerVolumeBindingImpl>
|
|
||||||
<DockerVolumeBindingImpl>
|
|
||||||
<option name="containerPath" value="/sorterat" />
|
|
||||||
<option name="hostPath" value="$USER_HOME$/Resilio Sync/Sorterat_test" />
|
|
||||||
</DockerVolumeBindingImpl>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</settings>
|
|
||||||
</deployment>
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<recent_temporary>
|
|
||||||
<list>
|
|
||||||
<item itemvalue="Docker.Dockerfile" />
|
|
||||||
</list>
|
|
||||||
</recent_temporary>
|
|
||||||
</component>
|
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="3" />
|
|
||||||
</component>
|
|
||||||
<component name="Vcs.Log.Tabs.Properties">
|
|
||||||
<option name="TAB_STATES">
|
|
||||||
<map>
|
|
||||||
<entry key="MAIN">
|
|
||||||
<value>
|
|
||||||
<State />
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
<option name="oldMeFiltersMigrated" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="VcsManagerConfiguration">
|
|
||||||
<MESSAGE value="1.0 of Go version" />
|
|
||||||
<MESSAGE value="Small fix in Dockerfile" />
|
|
||||||
<MESSAGE value="Fixed CORS" />
|
|
||||||
<MESSAGE value="Hopefully fixed the caching problem with random" />
|
|
||||||
<MESSAGE value="Another small change that should fix the caching problem." />
|
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Another small change that should fix the caching problem." />
|
|
||||||
</component>
|
|
||||||
<component name="VgoProject">
|
|
||||||
<integration-enabled>true</integration-enabled>
|
|
||||||
</component>
|
|
||||||
<component name="XDebuggerManager">
|
|
||||||
<watches-manager>
|
|
||||||
<configuration name="GoApplicationRunConfiguration">
|
|
||||||
<watch expression="games" language="go" />
|
|
||||||
<watch expression="songQue" language="go" />
|
|
||||||
</configuration>
|
|
||||||
</watches-manager>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -19,9 +19,9 @@ ENV DB_PASSWORD ""
|
|||||||
ENV DB_NAME ""
|
ENV DB_NAME ""
|
||||||
|
|
||||||
COPY --from=build_go /music-server/MusicServer .
|
COPY --from=build_go /music-server/MusicServer .
|
||||||
COPY ./doc/swagger.yaml .
|
COPY docss/swagger.yaml .
|
||||||
COPY ./songs/ ./songs/
|
COPY ./songs/ ./songs/
|
||||||
COPY ./init.sh .
|
COPY ./init.sh .
|
||||||
RUN chmod 777 ./init.sh
|
RUN chmod 777 ./conf.sh
|
||||||
|
|
||||||
CMD ./init.sh
|
CMD ./init.sh
|
||||||
2
app.yaml
2
app.yaml
@@ -1,5 +1,5 @@
|
|||||||
application: musicserver
|
application: musicserver
|
||||||
version: 2.1.4
|
version: 2.2.0
|
||||||
runtime: go115
|
runtime: go115
|
||||||
api_version: go1
|
api_version: go1
|
||||||
|
|
||||||
|
|||||||
13
cmd/backend/main.go
Normal file
13
cmd/backend/main.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"music-server/pkg/conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
conf.SetupDb()
|
||||||
|
|
||||||
|
conf.SetupRestServer()
|
||||||
|
|
||||||
|
conf.CloseDb()
|
||||||
|
}
|
||||||
246
database.go
246
database.go
@@ -1,246 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/jackc/pgtype"
|
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var dbPool *pgxpool.Pool
|
|
||||||
|
|
||||||
func initDB(host string, port int, user string, password string, dbname string) {
|
|
||||||
|
|
||||||
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
|
|
||||||
"password=%s dbname=%s sslmode=disable",
|
|
||||||
host, port, user, password, dbname)
|
|
||||||
|
|
||||||
fmt.Println(psqlInfo)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
dbPool, err = pgxpool.Connect(context.Background(), psqlInfo)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var success string
|
|
||||||
err = dbPool.QueryRow(context.Background(), "select 'Successfully connected!'").Scan(&success)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
fmt.Println(success)
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeDb() {
|
|
||||||
dbPool.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGameName(gameId int) string {
|
|
||||||
var gameName = ""
|
|
||||||
err := dbPool.QueryRow(context.Background(),
|
|
||||||
"SELECT game_name FROM game WHERE id = $1", gameId).Scan(&gameName)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return gameName
|
|
||||||
}
|
|
||||||
|
|
||||||
func setGameDeletionDate() {
|
|
||||||
_, err := dbPool.Exec(context.Background(),
|
|
||||||
"UPDATE game SET deleted=$1", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func clearSongs(gameId int) {
|
|
||||||
if gameId == -1 {
|
|
||||||
_, err := dbPool.Exec(context.Background(), "DELETE FROM song")
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, err := dbPool.Exec(context.Background(), "DELETE FROM song where game_id=$1", gameId)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func clearGames() {
|
|
||||||
_, err := dbPool.Exec(context.Background(), "DELETE FROM game")
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateGameName(id int, name string, path string) {
|
|
||||||
_, err := dbPool.Exec(context.Background(),
|
|
||||||
"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 := dbPool.Exec(context.Background(),
|
|
||||||
"UPDATE game SET deleted=null WHERE id=$1", id)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addSong(song SongData) {
|
|
||||||
_, err := dbPool.Exec(context.Background(),
|
|
||||||
"INSERT INTO song(game_id, song_name, path) VALUES ($1, $2, $3)",
|
|
||||||
song.gameId, song.songName, song.path)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func findSongsFromGame(id int) []SongData {
|
|
||||||
rows, err := dbPool.Query(context.Background(),
|
|
||||||
"SELECT song_name, path, times_played FROM song WHERE game_id = $1", id)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var songDataList []SongData
|
|
||||||
for rows.Next() {
|
|
||||||
var songName string
|
|
||||||
var path string
|
|
||||||
var timesPlayed int
|
|
||||||
|
|
||||||
err := rows.Scan(&songName, &path, ×Played)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
songDataList = append(songDataList, SongData{
|
|
||||||
gameId: id,
|
|
||||||
songName: songName,
|
|
||||||
path: path,
|
|
||||||
timesPlayed: timesPlayed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return songDataList
|
|
||||||
}
|
|
||||||
|
|
||||||
func getIdByGameName(name string) int {
|
|
||||||
var gameId = -1
|
|
||||||
err := dbPool.QueryRow(context.Background(),
|
|
||||||
"SELECT id FROM game WHERE game_name = $1", name).Scan(&gameId)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return gameId
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertGame(name string, path string) int {
|
|
||||||
gameId := -1
|
|
||||||
err := dbPool.QueryRow(context.Background(),
|
|
||||||
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
|
||||||
name, path, time.Now()).Scan(&gameId)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
resetGameIdSeq()
|
|
||||||
err2 := dbPool.QueryRow(context.Background(),
|
|
||||||
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
|
||||||
name, path, time.Now()).Scan(&gameId)
|
|
||||||
if err2 != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gameId
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertGameWithExistingId(id int, name string, path string) {
|
|
||||||
_, err := dbPool.Exec(context.Background(),
|
|
||||||
"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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resetGameIdSeq() {
|
|
||||||
_, err := dbPool.Query(context.Background(), "SELECT setval('game_id_seq', (SELECT MAX(id) FROM game)+1);")
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func findAllGames() []GameData {
|
|
||||||
rows, err := dbPool.Query(context.Background(),
|
|
||||||
"SELECT id, game_name, added, deleted, last_changed, path, times_played, last_played, number_of_songs "+
|
|
||||||
"FROM game "+
|
|
||||||
"ORDER BY game_name")
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
var gameList []GameData
|
|
||||||
for rows.Next() {
|
|
||||||
var id, timesPlayed int
|
|
||||||
var numberOfSongs pgtype.Int4
|
|
||||||
var gameName, path string
|
|
||||||
var added, deleted, lastChanged, lastPlayed pgtype.Timestamp
|
|
||||||
err := rows.Scan(&id, &gameName, &added, &deleted, &lastChanged, &path, ×Played, &lastPlayed, &numberOfSongs)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
gameList = append(gameList, GameData{
|
|
||||||
id: id,
|
|
||||||
gameName: gameName,
|
|
||||||
added: added.Time,
|
|
||||||
deleted: deleted.Time,
|
|
||||||
lastChanged: lastChanged.Time,
|
|
||||||
path: path,
|
|
||||||
timesPlayed: timesPlayed,
|
|
||||||
lastPlayed: lastPlayed.Time,
|
|
||||||
numberOfSongs: numberOfSongs.Int,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return gameList
|
|
||||||
}
|
|
||||||
|
|
||||||
func addGamePlayed(id int) {
|
|
||||||
_, err := dbPool.Exec(context.Background(),
|
|
||||||
"UPDATE game SET times_played=times_played+1, last_played=now() WHERE id=$1", id)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addSongPlayed(id int, name string) {
|
|
||||||
_, err := dbPool.Exec(context.Background(),
|
|
||||||
"UPDATE song SET times_played=times_played+1 WHERE game_id=$1 AND song_name=$2", id, name)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testf() {
|
|
||||||
rows, dbErr := dbPool.Query(context.Background(), "select game_name from game")
|
|
||||||
if dbErr != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
for rows.Next() {
|
|
||||||
var gameName string
|
|
||||||
dbErr = rows.Scan(&gameName)
|
|
||||||
if dbErr != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%v\n", gameName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
version: "2.1.4"
|
version: "2.2.0"
|
||||||
title: "Music Server"
|
title: "Music Server"
|
||||||
description: "Added a check to see if song exists before returning it, if not a new song will be picked up."
|
description: "Changed the structure of the whole application, should be no changes to functionality."
|
||||||
contact:
|
contact:
|
||||||
email: "zarnor91@gmail.com"
|
email: "zarnor91@gmail.com"
|
||||||
servers:
|
servers:
|
||||||
107
indexFacade.go
107
indexFacade.go
@@ -1,107 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
setCorsAndNoCacheHeaders(&w, r)
|
|
||||||
|
|
||||||
if r.URL.Path == "/version" {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
|
|
||||||
testf()
|
|
||||||
|
|
||||||
data := VersionData{Version: "2.1.4",
|
|
||||||
Changelog: "Game list should now be sorted, a new endpoint with the game list in random order have been added.",
|
|
||||||
History: []VersionData{
|
|
||||||
{
|
|
||||||
Version: "2.1.3",
|
|
||||||
Changelog: "Added a check to see if song exists before returning it, if not a new song will be picked up.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.1.2",
|
|
||||||
Changelog: "Added test server to swagger file.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.1.1",
|
|
||||||
Changelog: "Fixed bug where wrong song was showed as currently played.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.1.0",
|
|
||||||
Changelog: "Added /addQue to add the last received song to the songQue. " +
|
|
||||||
"Changed /rand and /rand/low to not add song to the que. " +
|
|
||||||
"Changed /next to not call /rand when the end of the que is reached, instead the last song in the que will be resent.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.0.3",
|
|
||||||
Changelog: "Another small change that should fix the caching problem.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.0.2",
|
|
||||||
Changelog: "Hopefully fixed the caching problem with random.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.0.1",
|
|
||||||
Changelog: "Fixed CORS",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "2.0.0",
|
|
||||||
Changelog: "Rebuilt the application in Go.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "1.2.0",
|
|
||||||
Changelog: "Made the /sync endpoint async. " +
|
|
||||||
"Fixed bug where the game list wasn't reloaded when using /reset. " +
|
|
||||||
"Fixed bug where the songNo showed in the list didn't match what should be sent.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "1.1.0",
|
|
||||||
Changelog: "Added sync endpoint, don't really trust it to 100%, would say beta. " +
|
|
||||||
"Fixed bug with /next after /previous. Added /reset endpoint. " +
|
|
||||||
"Added some info more to /info and /list.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "1.0.0",
|
|
||||||
Changelog: "Added swagger documentation. Created version 1.0.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: "0.5.5",
|
|
||||||
Changelog: "Added increase played endpoint.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_ = json.NewEncoder(w).Encode(data)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/doc" {
|
|
||||||
http.ServeFile(w, r, "./doc/swagger.yaml")
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/" {
|
|
||||||
rows, dbErr := dbPool.Query(context.Background(), "select game_name from game")
|
|
||||||
if dbErr != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
for rows.Next() {
|
|
||||||
var gameName string
|
|
||||||
dbErr = rows.Scan(&gameName)
|
|
||||||
if dbErr != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintf(w, "%v\n", gameName)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := fmt.Fprint(w, "Hello, World!!")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
348
musicFacade.go
348
musicFacade.go
@@ -1,348 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var currentSong = -1
|
|
||||||
var games []GameData
|
|
||||||
var songQue []SongData
|
|
||||||
var lastFetched SongData
|
|
||||||
|
|
||||||
func getSoundCheckSong() string {
|
|
||||||
reset()
|
|
||||||
|
|
||||||
files, err := ioutil.ReadDir("songs")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
fileInfo := files[rand.Intn(len(files))]
|
|
||||||
return "songs/" + fileInfo.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
func reset() {
|
|
||||||
songQue = nil
|
|
||||||
currentSong = -1
|
|
||||||
games = findAllGames()
|
|
||||||
}
|
|
||||||
|
|
||||||
func addLatestToQue() {
|
|
||||||
if lastFetched.path != "" {
|
|
||||||
currentSong = len(songQue)
|
|
||||||
songQue = append(songQue, lastFetched)
|
|
||||||
lastFetched = SongData{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRandomSong() string {
|
|
||||||
if games == nil || len(games) == 0 {
|
|
||||||
games = findAllGames()
|
|
||||||
}
|
|
||||||
|
|
||||||
song := getSongFromList(games)
|
|
||||||
|
|
||||||
lastFetched = song
|
|
||||||
return song.path
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSongFromList(games []GameData) SongData {
|
|
||||||
songFound := false
|
|
||||||
var song SongData
|
|
||||||
for !songFound {
|
|
||||||
game := getRandomGame(games)
|
|
||||||
songs := findSongsFromGame(game.id)
|
|
||||||
song = songs[rand.Intn(len(songs))]
|
|
||||||
|
|
||||||
//Check if file exists and open
|
|
||||||
openFile, err := os.Open(song.path)
|
|
||||||
if err != nil {
|
|
||||||
//File not found
|
|
||||||
log.Fatal("Song not found, maybe delete song and/or game" + song.songName + " songPath: " + song.path)
|
|
||||||
} else {
|
|
||||||
songFound = true
|
|
||||||
}
|
|
||||||
|
|
||||||
err = openFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return song
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRandomSongLowChance() string {
|
|
||||||
gameList := findAllGames()
|
|
||||||
|
|
||||||
var listOfGames []GameData
|
|
||||||
|
|
||||||
var averagePlayed = getAveragePlayed(gameList)
|
|
||||||
|
|
||||||
for _, data := range gameList {
|
|
||||||
var timesToAdd = averagePlayed - data.timesPlayed
|
|
||||||
if timesToAdd <= 0 {
|
|
||||||
listOfGames = append(listOfGames, data)
|
|
||||||
} else {
|
|
||||||
for i := 0; i < timesToAdd; i++ {
|
|
||||||
listOfGames = append(listOfGames, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
song := getSongFromList(listOfGames)
|
|
||||||
|
|
||||||
lastFetched = song
|
|
||||||
return song.path
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSongInfo() SongInfo {
|
|
||||||
if songQue == nil {
|
|
||||||
return SongInfo{}
|
|
||||||
}
|
|
||||||
var currentSongData = songQue[currentSong]
|
|
||||||
|
|
||||||
currentGameData := getCurrentGame(currentSongData)
|
|
||||||
|
|
||||||
return SongInfo{
|
|
||||||
Game: currentGameData.gameName,
|
|
||||||
GamePlayed: currentGameData.timesPlayed,
|
|
||||||
Song: currentSongData.songName,
|
|
||||||
SongPlayed: currentSongData.timesPlayed,
|
|
||||||
CurrentlyPlaying: true,
|
|
||||||
SongNo: currentSong,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPlayedSongs() []SongInfo {
|
|
||||||
var songList []SongInfo
|
|
||||||
|
|
||||||
for i, song := range songQue {
|
|
||||||
gameData := getCurrentGame(song)
|
|
||||||
songList = append(songList, SongInfo{
|
|
||||||
Game: gameData.gameName,
|
|
||||||
GamePlayed: gameData.timesPlayed,
|
|
||||||
Song: song.songName,
|
|
||||||
SongPlayed: song.timesPlayed,
|
|
||||||
CurrentlyPlaying: i == currentSong,
|
|
||||||
SongNo: i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return songList
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSong(song string) string {
|
|
||||||
currentSong, _ = strconv.Atoi(song)
|
|
||||||
if currentSong >= len(songQue) {
|
|
||||||
currentSong = len(songQue) - 1
|
|
||||||
} else if currentSong < 0 {
|
|
||||||
currentSong = 0
|
|
||||||
}
|
|
||||||
var songData = songQue[currentSong]
|
|
||||||
return songData.path
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllGames() []string {
|
|
||||||
if games == nil || len(games) == 0 {
|
|
||||||
games = findAllGames()
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsonArray []string
|
|
||||||
for _, game := range games {
|
|
||||||
jsonArray = append(jsonArray, game.gameName)
|
|
||||||
}
|
|
||||||
return jsonArray
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllGamesRandom() []string {
|
|
||||||
if games == nil || len(games) == 0 {
|
|
||||||
games = findAllGames()
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsonArray []string
|
|
||||||
for _, game := range games {
|
|
||||||
jsonArray = append(jsonArray, game.gameName)
|
|
||||||
}
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] })
|
|
||||||
return jsonArray
|
|
||||||
}
|
|
||||||
|
|
||||||
func setPlayed(songNumber int) {
|
|
||||||
if songQue == nil || len(songQue) == 0 || songNumber >= len(songQue) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var songData = songQue[songNumber]
|
|
||||||
addGamePlayed(songData.gameId)
|
|
||||||
addSongPlayed(songData.gameId, songData.songName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNextSong() string {
|
|
||||||
if songQue == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if currentSong == len(songQue)-1 || currentSong == -1 {
|
|
||||||
var songData = songQue[currentSong]
|
|
||||||
return songData.path
|
|
||||||
} else {
|
|
||||||
currentSong = currentSong + 1
|
|
||||||
var songData = songQue[currentSong]
|
|
||||||
return songData.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPreviousSong() string {
|
|
||||||
if songQue == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if currentSong == -1 || currentSong == 0 {
|
|
||||||
var songData = songQue[0]
|
|
||||||
return songData.path
|
|
||||||
} else {
|
|
||||||
currentSong = currentSong - 1
|
|
||||||
var songData = songQue[currentSong]
|
|
||||||
return songData.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func musicHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
setCorsAndNoCacheHeaders(&w, r)
|
|
||||||
if r.URL.Path == "/music" && r.Method == http.MethodGet {
|
|
||||||
song := r.URL.Query().Get("song")
|
|
||||||
if song == "" {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, err := fmt.Fprint(w, "song can't be empty")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s := getSong(song)
|
|
||||||
sendSong(w, s)
|
|
||||||
}
|
|
||||||
} else if r.URL.Path == "/music/first" && r.Method == http.MethodGet {
|
|
||||||
song := getSoundCheckSong()
|
|
||||||
sendSong(w, song)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/reset" && r.Method == http.MethodGet {
|
|
||||||
reset()
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/rand" && r.Method == http.MethodGet {
|
|
||||||
song := getRandomSong()
|
|
||||||
sendSong(w, song)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/rand/low" && r.Method == http.MethodGet {
|
|
||||||
chance := getRandomSongLowChance()
|
|
||||||
sendSong(w, chance)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/info" && r.Method == http.MethodGet {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
_ = json.NewEncoder(w).Encode(getSongInfo())
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/list" && r.Method == http.MethodGet {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
_ = json.NewEncoder(w).Encode(getPlayedSongs())
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/next" {
|
|
||||||
song := getNextSong()
|
|
||||||
sendSong(w, song)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/previous" {
|
|
||||||
song := getPreviousSong()
|
|
||||||
sendSong(w, song)
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/all" && r.Method == http.MethodGet {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
_ = json.NewEncoder(w).Encode(getAllGames())
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/all/random" && r.Method == http.MethodGet {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
_ = json.NewEncoder(w).Encode(getAllGamesRandom())
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/music/played" && r.Method == http.MethodPut {
|
|
||||||
var p Played
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&p)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setPlayed(p.song)
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
} else if r.URL.Path == "/music/addQue" && r.Method == http.MethodGet {
|
|
||||||
addLatestToQue()
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendSong(writer http.ResponseWriter, Filename string) {
|
|
||||||
fmt.Println("Client requests: " + Filename)
|
|
||||||
|
|
||||||
//Check if file exists and open
|
|
||||||
openFile, err := os.Open(Filename)
|
|
||||||
if err != nil {
|
|
||||||
//File not found, send 404
|
|
||||||
http.Error(writer, "Song not found.", 404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func(openFile *os.File) {
|
|
||||||
_ = openFile.Close()
|
|
||||||
}(openFile) //Close after function return
|
|
||||||
|
|
||||||
//File is found, create and send the correct headers
|
|
||||||
|
|
||||||
//Get the Content-Type of the file
|
|
||||||
//Create a buffer to store the header of the file in
|
|
||||||
FileHeader := make([]byte, 512)
|
|
||||||
//Copy the headers into the FileHeader buffer
|
|
||||||
_, _ = openFile.Read(FileHeader)
|
|
||||||
//Get content type of file
|
|
||||||
//FileContentType := http.DetectContentType(FileHeader)
|
|
||||||
|
|
||||||
//Get the file size
|
|
||||||
FileStat, _ := openFile.Stat() //Get info from file
|
|
||||||
FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string
|
|
||||||
|
|
||||||
//Send the headers
|
|
||||||
//writer.Header().Set("Content-Disposition", "attachment; filename="+Filename)
|
|
||||||
writer.Header().Set("Content-Type", "audio/mpeg")
|
|
||||||
writer.Header().Set("Content-Length", FileSize)
|
|
||||||
|
|
||||||
//Send the file
|
|
||||||
//We read 512 bytes from the file already, so we reset the offset back to 0
|
|
||||||
_, _ = openFile.Seek(0, 0)
|
|
||||||
_, _ = io.Copy(writer, openFile) //'Copy' the file to the client
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type Played struct {
|
|
||||||
song int
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCurrentGame(currentSongData SongData) GameData {
|
|
||||||
for _, game := range games {
|
|
||||||
if game.id == currentSongData.gameId {
|
|
||||||
return game
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return GameData{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAveragePlayed(gameList []GameData) int {
|
|
||||||
var sum int
|
|
||||||
for _, data := range gameList {
|
|
||||||
sum += data.timesPlayed
|
|
||||||
}
|
|
||||||
return sum / len(gameList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRandomGame(listOfGames []GameData) GameData {
|
|
||||||
return listOfGames[rand.Intn(len(listOfGames))]
|
|
||||||
}
|
|
||||||
122
musicserver.go
122
musicserver.go
@@ -1,122 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Get the value of an Environment Variable
|
|
||||||
host := os.Getenv("DB_HOST")
|
|
||||||
dbPort, dbPortErr := strconv.Atoi(os.Getenv("DB_PORT"))
|
|
||||||
if dbPortErr != nil {
|
|
||||||
dbPort = 0
|
|
||||||
}
|
|
||||||
username := os.Getenv("DB_USERNAME")
|
|
||||||
password := os.Getenv("DB_PASSWORD")
|
|
||||||
dbName := os.Getenv("DB_NAME")
|
|
||||||
|
|
||||||
fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n",
|
|
||||||
host, dbPort, username, password, dbName)
|
|
||||||
|
|
||||||
if host == "" {
|
|
||||||
host = "localhost"
|
|
||||||
}
|
|
||||||
if dbPort == 0 {
|
|
||||||
dbPort = 5432
|
|
||||||
}
|
|
||||||
if username == "" {
|
|
||||||
username = "sebastian"
|
|
||||||
}
|
|
||||||
if password == "" {
|
|
||||||
password = "950100"
|
|
||||||
}
|
|
||||||
if dbName == "" {
|
|
||||||
dbName = "music_dev_local"
|
|
||||||
}
|
|
||||||
|
|
||||||
initDB(host, dbPort, username, password, dbName)
|
|
||||||
defer closeDb()
|
|
||||||
|
|
||||||
r := mux.NewRouter()
|
|
||||||
r.HandleFunc("/sync", syncHandler)
|
|
||||||
r.HandleFunc("/sync/{func}", syncHandler)
|
|
||||||
r.HandleFunc("/music", musicHandler)
|
|
||||||
r.HandleFunc("/music/{func}", musicHandler)
|
|
||||||
r.HandleFunc("/music/{func}/{func2}", musicHandler)
|
|
||||||
r.HandleFunc("/{func}", indexHandler)
|
|
||||||
http.Handle("/", r)
|
|
||||||
|
|
||||||
port := os.Getenv("PORT")
|
|
||||||
if port == "" {
|
|
||||||
port = "8080"
|
|
||||||
log.Printf("Defaulting to port %s", port)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Listening on port %s", port)
|
|
||||||
log.Printf("Open http://localhost:%s in the browser", port)
|
|
||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersionData struct {
|
|
||||||
Version string `json:"version"`
|
|
||||||
Changelog string `json:"changelog"`
|
|
||||||
History []VersionData `json:"history"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SongInfo struct {
|
|
||||||
Game string `json:"Game"`
|
|
||||||
GamePlayed int `json:"GamePlayed"`
|
|
||||||
Song string `json:"Song"`
|
|
||||||
SongPlayed int `json:"SongPlayed"`
|
|
||||||
CurrentlyPlaying bool `json:"CurrentlyPlaying"`
|
|
||||||
SongNo int `json:"SongNo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type SongData struct {
|
|
||||||
gameId int
|
|
||||||
songName string
|
|
||||||
path string
|
|
||||||
timesPlayed int
|
|
||||||
}
|
|
||||||
|
|
||||||
func setCorsAndNoCacheHeaders(w *http.ResponseWriter, r *http.Request) {
|
|
||||||
var etagHeaders = []string{
|
|
||||||
"ETag",
|
|
||||||
"If-Modified-Since",
|
|
||||||
"If-Match",
|
|
||||||
"If-None-Match",
|
|
||||||
"If-Range",
|
|
||||||
"If-Unmodified-Since",
|
|
||||||
}
|
|
||||||
|
|
||||||
(*w).Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT")
|
|
||||||
(*w).Header().Set("Last-Modified", time.Now().String()+" GMT")
|
|
||||||
(*w).Header().Set("Cache-Control", "no-cache, no-store, private, max-age=0")
|
|
||||||
(*w).Header().Set("Pragma", "no-cache")
|
|
||||||
(*w).Header().Set("X-Accel-Expires", "0")
|
|
||||||
(*w).Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
|
|
||||||
for _, v := range etagHeaders {
|
|
||||||
if r.Header.Get(v) != "" {
|
|
||||||
r.Header.Del(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
32
pkg/api/index.go
Normal file
32
pkg/api/index.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"music-server/pkg/helpers"
|
||||||
|
"music-server/pkg/server"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
helpers.SetCorsAndNoCacheHeaders(&w, r)
|
||||||
|
|
||||||
|
if r.URL.Path == "/version" {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
history := server.GetVersionHistory()
|
||||||
|
_ = json.NewEncoder(w).Encode(history)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/docs" {
|
||||||
|
http.ServeFile(w, r, "./docs/swagger.yaml")
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/" {
|
||||||
|
_, err := fmt.Fprint(w, "Hello, World!!")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
79
pkg/api/music.go
Normal file
79
pkg/api/music.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"music-server/pkg/helpers"
|
||||||
|
"music-server/pkg/models"
|
||||||
|
"music-server/pkg/server"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MusicHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
helpers.SetCorsAndNoCacheHeaders(&w, r)
|
||||||
|
if r.URL.Path == "/music" && r.Method == http.MethodGet {
|
||||||
|
song := r.URL.Query().Get("song")
|
||||||
|
if song == "" {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
_, err := fmt.Fprint(w, "song can't be empty")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s := server.GetSong(song)
|
||||||
|
helpers.SendSong(w, s)
|
||||||
|
}
|
||||||
|
} else if r.URL.Path == "/music/first" && r.Method == http.MethodGet {
|
||||||
|
song := server.GetSoundCheckSong()
|
||||||
|
helpers.SendSong(w, song)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/reset" && r.Method == http.MethodGet {
|
||||||
|
server.Reset()
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/rand" && r.Method == http.MethodGet {
|
||||||
|
song := server.GetRandomSong()
|
||||||
|
helpers.SendSong(w, song)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/rand/low" && r.Method == http.MethodGet {
|
||||||
|
chance := server.GetRandomSongLowChance()
|
||||||
|
helpers.SendSong(w, chance)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/info" && r.Method == http.MethodGet {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(server.GetSongInfo())
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/list" && r.Method == http.MethodGet {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(server.GetPlayedSongs())
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/next" {
|
||||||
|
song := server.GetNextSong()
|
||||||
|
helpers.SendSong(w, song)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/previous" {
|
||||||
|
song := server.GetPreviousSong()
|
||||||
|
helpers.SendSong(w, song)
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/all" && r.Method == http.MethodGet {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(server.GetAllGames())
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/all/random" && r.Method == http.MethodGet {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
_ = json.NewEncoder(w).Encode(server.GetAllGamesRandom())
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/played" && r.Method == http.MethodPut {
|
||||||
|
var p models.Played
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&p)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
server.SetPlayed(p.Song)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
} else if r.URL.Path == "/music/addQue" && r.Method == http.MethodGet {
|
||||||
|
server.AddLatestToQue()
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
pkg/api/sync.go
Normal file
28
pkg/api/sync.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"music-server/pkg/helpers"
|
||||||
|
"music-server/pkg/server"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SyncHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
helpers.SetCorsAndNoCacheHeaders(&w, r)
|
||||||
|
if r.URL.Path == "/sync" {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
server.SyncGames()
|
||||||
|
_, err := fmt.Fprint(w, "Games are synced")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/sync/reset" {
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
server.ResetDB()
|
||||||
|
_, err := fmt.Fprint(w, "Games and songs are deleted from the database")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
pkg/conf/conf.go
Normal file
70
pkg/conf/conf.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"log"
|
||||||
|
"music-server/pkg/api"
|
||||||
|
"music-server/pkg/db"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetupDb() {
|
||||||
|
// Get the value of an Environment Variable
|
||||||
|
host := os.Getenv("DB_HOST")
|
||||||
|
dbPort, dbPortErr := strconv.Atoi(os.Getenv("DB_PORT"))
|
||||||
|
if dbPortErr != nil {
|
||||||
|
dbPort = 0
|
||||||
|
}
|
||||||
|
username := os.Getenv("DB_USERNAME")
|
||||||
|
password := os.Getenv("DB_PASSWORD")
|
||||||
|
dbName := os.Getenv("DB_NAME")
|
||||||
|
|
||||||
|
fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n",
|
||||||
|
host, dbPort, username, password, dbName)
|
||||||
|
|
||||||
|
if host == "" {
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
|
if dbPort == 0 {
|
||||||
|
dbPort = 5432
|
||||||
|
}
|
||||||
|
if username == "" {
|
||||||
|
username = "sebastian"
|
||||||
|
}
|
||||||
|
if password == "" {
|
||||||
|
password = "950100"
|
||||||
|
}
|
||||||
|
if dbName == "" {
|
||||||
|
dbName = "music_dev_local"
|
||||||
|
}
|
||||||
|
|
||||||
|
db.InitDB(host, dbPort, username, password, dbName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseDb() {
|
||||||
|
defer db.CloseDb()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupRestServer() {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/sync", api.SyncHandler)
|
||||||
|
r.HandleFunc("/sync/{func}", api.SyncHandler)
|
||||||
|
r.HandleFunc("/music", api.MusicHandler)
|
||||||
|
r.HandleFunc("/music/{func}", api.MusicHandler)
|
||||||
|
r.HandleFunc("/music/{func}/{func2}", api.MusicHandler)
|
||||||
|
r.HandleFunc("/{func}", api.IndexHandler)
|
||||||
|
http.Handle("/", r)
|
||||||
|
|
||||||
|
port := os.Getenv("PORT")
|
||||||
|
if port == "" {
|
||||||
|
port = "8080"
|
||||||
|
log.Printf("Defaulting to port %s", port)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Listening on port %s", port)
|
||||||
|
log.Printf("Open http://localhost:%s in the browser", port)
|
||||||
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
|
||||||
|
}
|
||||||
61
pkg/db/dbHelper.go
Normal file
61
pkg/db/dbHelper.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pool *pgxpool.Pool
|
||||||
|
|
||||||
|
func InitDB(host string, port int, user string, password string, dbname string) {
|
||||||
|
|
||||||
|
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
|
||||||
|
"password=%s dbname=%s sslmode=disable",
|
||||||
|
host, port, user, password, dbname)
|
||||||
|
|
||||||
|
fmt.Println(psqlInfo)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
pool, err = pgxpool.Connect(context.Background(), psqlInfo)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var success string
|
||||||
|
err = pool.QueryRow(context.Background(), "select 'Successfully connected!'").Scan(&success)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseDb() {
|
||||||
|
pool.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Testf() {
|
||||||
|
rows, dbErr := pool.Query(context.Background(), "select game_name from game")
|
||||||
|
if dbErr != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
var gameName string
|
||||||
|
dbErr = rows.Scan(&gameName)
|
||||||
|
if dbErr != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "%v\n", gameName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetGameIdSeq() {
|
||||||
|
_, err := pool.Query(context.Background(), "SELECT setval('game_id_seq', (SELECT MAX(id) FROM game)+1);")
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
133
pkg/db/game.go
Normal file
133
pkg/db/game.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/jackc/pgtype"
|
||||||
|
"music-server/pkg/models"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetGameName(gameId int) string {
|
||||||
|
var gameName = ""
|
||||||
|
err := pool.QueryRow(context.Background(),
|
||||||
|
"SELECT game_name FROM game WHERE id = $1", gameId).Scan(&gameName)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return gameName
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetGameDeletionDate() {
|
||||||
|
_, err := pool.Exec(context.Background(),
|
||||||
|
"UPDATE game SET deleted=$1", time.Now())
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearGames() {
|
||||||
|
_, err := pool.Exec(context.Background(), "DELETE FROM game")
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateGameName(id int, name string, path string) {
|
||||||
|
_, err := pool.Exec(context.Background(),
|
||||||
|
"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 := pool.Exec(context.Background(),
|
||||||
|
"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 := pool.QueryRow(context.Background(),
|
||||||
|
"SELECT id FROM game WHERE game_name = $1", name).Scan(&gameId)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return gameId
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertGame(name string, path string) int {
|
||||||
|
gameId := -1
|
||||||
|
err := pool.QueryRow(context.Background(),
|
||||||
|
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
||||||
|
name, path, time.Now()).Scan(&gameId)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
resetGameIdSeq()
|
||||||
|
err2 := pool.QueryRow(context.Background(),
|
||||||
|
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
||||||
|
name, path, time.Now()).Scan(&gameId)
|
||||||
|
if err2 != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gameId
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertGameWithExistingId(id int, name string, path string) {
|
||||||
|
_, err := pool.Exec(context.Background(),
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindAllGames() []models.GameData {
|
||||||
|
rows, err := pool.Query(context.Background(),
|
||||||
|
"SELECT id, game_name, added, deleted, last_changed, path, times_played, last_played, number_of_songs "+
|
||||||
|
"FROM game "+
|
||||||
|
"ORDER BY game_name")
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
var gameList []models.GameData
|
||||||
|
for rows.Next() {
|
||||||
|
var id, timesPlayed int
|
||||||
|
var numberOfSongs pgtype.Int4
|
||||||
|
var gameName, path string
|
||||||
|
var added, deleted, lastChanged, lastPlayed pgtype.Timestamp
|
||||||
|
err := rows.Scan(&id, &gameName, &added, &deleted, &lastChanged, &path, ×Played, &lastPlayed, &numberOfSongs)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
gameList = append(gameList, models.GameData{
|
||||||
|
Id: id,
|
||||||
|
GameName: gameName,
|
||||||
|
Added: added.Time,
|
||||||
|
Deleted: deleted.Time,
|
||||||
|
LastChanged: lastChanged.Time,
|
||||||
|
Path: path,
|
||||||
|
TimesPlayed: timesPlayed,
|
||||||
|
LastPlayed: lastPlayed.Time,
|
||||||
|
NumberOfSongs: numberOfSongs.Int,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return gameList
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddGamePlayed(id int) {
|
||||||
|
_, err := pool.Exec(context.Background(),
|
||||||
|
"UPDATE game SET times_played=times_played+1, last_played=now() WHERE id=$1", id)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
68
pkg/db/song.go
Normal file
68
pkg/db/song.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"music-server/pkg/models"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ClearSongs(gameId int) {
|
||||||
|
if gameId == -1 {
|
||||||
|
_, err := pool.Exec(context.Background(), "DELETE FROM song")
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := pool.Exec(context.Background(), "DELETE FROM song where game_id=$1", gameId)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSong(song models.SongData) {
|
||||||
|
_, err := pool.Exec(context.Background(),
|
||||||
|
"INSERT INTO song(game_id, song_name, path) VALUES ($1, $2, $3)",
|
||||||
|
song.GameId, song.SongName, song.Path)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindSongsFromGame(id int) []models.SongData {
|
||||||
|
rows, err := pool.Query(context.Background(),
|
||||||
|
"SELECT song_name, path, times_played FROM song WHERE game_id = $1", id)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var songDataList []models.SongData
|
||||||
|
for rows.Next() {
|
||||||
|
var songName string
|
||||||
|
var path string
|
||||||
|
var timesPlayed int
|
||||||
|
|
||||||
|
err := rows.Scan(&songName, &path, ×Played)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
songDataList = append(songDataList, models.SongData{
|
||||||
|
GameId: id,
|
||||||
|
SongName: songName,
|
||||||
|
Path: path,
|
||||||
|
TimesPlayed: timesPlayed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return songDataList
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSongPlayed(id int, name string) {
|
||||||
|
_, err := pool.Exec(context.Background(),
|
||||||
|
"UPDATE song SET times_played=times_played+1 WHERE game_id=$1 AND song_name=$2", id, name)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
74
pkg/helpers/helpers.go
Normal file
74
pkg/helpers/helpers.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetCorsAndNoCacheHeaders(w *http.ResponseWriter, r *http.Request) {
|
||||||
|
var etagHeaders = []string{
|
||||||
|
"ETag",
|
||||||
|
"If-Modified-Since",
|
||||||
|
"If-Match",
|
||||||
|
"If-None-Match",
|
||||||
|
"If-Range",
|
||||||
|
"If-Unmodified-Since",
|
||||||
|
}
|
||||||
|
|
||||||
|
(*w).Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT")
|
||||||
|
(*w).Header().Set("Last-Modified", time.Now().String()+" GMT")
|
||||||
|
(*w).Header().Set("Cache-Control", "no-cache, no-store, private, max-age=0")
|
||||||
|
(*w).Header().Set("Pragma", "no-cache")
|
||||||
|
(*w).Header().Set("X-Accel-Expires", "0")
|
||||||
|
(*w).Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
|
||||||
|
for _, v := range etagHeaders {
|
||||||
|
if r.Header.Get(v) != "" {
|
||||||
|
r.Header.Del(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendSong(writer http.ResponseWriter, Filename string) {
|
||||||
|
fmt.Println("Client requests: " + Filename)
|
||||||
|
|
||||||
|
//Check if file exists and open
|
||||||
|
openFile, err := os.Open(Filename)
|
||||||
|
if err != nil {
|
||||||
|
//File not found, send 404
|
||||||
|
http.Error(writer, "Song not found.", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(openFile *os.File) {
|
||||||
|
_ = openFile.Close()
|
||||||
|
}(openFile) //Close after function return
|
||||||
|
|
||||||
|
//File is found, create and send the correct headers
|
||||||
|
|
||||||
|
//Get the Content-Type of the file
|
||||||
|
//Create a buffer to store the header of the file in
|
||||||
|
FileHeader := make([]byte, 512)
|
||||||
|
//Copy the headers into the FileHeader buffer
|
||||||
|
_, _ = openFile.Read(FileHeader)
|
||||||
|
//Get content type of file
|
||||||
|
//FileContentType := http.DetectContentType(FileHeader)
|
||||||
|
|
||||||
|
//Get the file size
|
||||||
|
FileStat, _ := openFile.Stat() //Get info from file
|
||||||
|
FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string
|
||||||
|
|
||||||
|
//Send the headers
|
||||||
|
//writer.Header().Set("Content-Disposition", "attachment; filename="+Filename)
|
||||||
|
writer.Header().Set("Content-Type", "audio/mpeg")
|
||||||
|
writer.Header().Set("Content-Length", FileSize)
|
||||||
|
|
||||||
|
//Send the file
|
||||||
|
//We read 512 bytes from the file already, so we reset the offset back to 0
|
||||||
|
_, _ = openFile.Seek(0, 0)
|
||||||
|
_, _ = io.Copy(writer, openFile) //'Copy' the file to the client
|
||||||
|
return
|
||||||
|
}
|
||||||
41
pkg/models/models.go
Normal file
41
pkg/models/models.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Played struct {
|
||||||
|
Song int
|
||||||
|
}
|
||||||
|
|
||||||
|
type VersionData struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Changelog string `json:"changelog"`
|
||||||
|
History []VersionData `json:"history"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SongInfo struct {
|
||||||
|
Game string `json:"Game"`
|
||||||
|
GamePlayed int `json:"GamePlayed"`
|
||||||
|
Song string `json:"Song"`
|
||||||
|
SongPlayed int `json:"SongPlayed"`
|
||||||
|
CurrentlyPlaying bool `json:"CurrentlyPlaying"`
|
||||||
|
SongNo int `json:"SongNo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type SongData struct {
|
||||||
|
GameId int
|
||||||
|
SongName string
|
||||||
|
Path string
|
||||||
|
TimesPlayed int
|
||||||
|
}
|
||||||
76
pkg/server/index.go
Normal file
76
pkg/server/index.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"music-server/pkg/db"
|
||||||
|
"music-server/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetVersionHistory() models.VersionData {
|
||||||
|
db.Testf()
|
||||||
|
|
||||||
|
data := models.VersionData{Version: "2.2.0",
|
||||||
|
Changelog: "Changed the structure of the whole application, should be no changes to functionality.",
|
||||||
|
History: []models.VersionData{
|
||||||
|
{
|
||||||
|
Version: "2.1.4",
|
||||||
|
Changelog: "Game list should now be sorted, a new endpoint with the game list in random order have been added.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.1.3",
|
||||||
|
Changelog: "Added a check to see if song exists before returning it, if not a new song will be picked up.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.1.2",
|
||||||
|
Changelog: "Added test server to swagger file.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.1.1",
|
||||||
|
Changelog: "Fixed bug where wrong song was showed as currently played.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.1.0",
|
||||||
|
Changelog: "Added /addQue to add the last received song to the songQue. " +
|
||||||
|
"Changed /rand and /rand/low to not add song to the que. " +
|
||||||
|
"Changed /next to not call /rand when the end of the que is reached, instead the last song in the que will be resent.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.0.3",
|
||||||
|
Changelog: "Another small change that should fix the caching problem.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.0.2",
|
||||||
|
Changelog: "Hopefully fixed the caching problem with random.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.0.1",
|
||||||
|
Changelog: "Fixed CORS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "2.0.0",
|
||||||
|
Changelog: "Rebuilt the application in Go.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "1.2.0",
|
||||||
|
Changelog: "Made the /sync endpoint async. " +
|
||||||
|
"Fixed bug where the game list wasn't reloaded when using /reset. " +
|
||||||
|
"Fixed bug where the songNo showed in the list didn't match what should be sent.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "1.1.0",
|
||||||
|
Changelog: "Added sync endpoint, don't really trust it to 100%, would say beta. " +
|
||||||
|
"Fixed bug with /next after /previous. Added /reset endpoint. " +
|
||||||
|
"Added some info more to /info and /list.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "1.0.0",
|
||||||
|
Changelog: "Added swagger documentation. Created version 1.0.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "0.5.5",
|
||||||
|
Changelog: "Added increase played endpoint.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
233
pkg/server/music.go
Normal file
233
pkg/server/music.go
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"music-server/pkg/db"
|
||||||
|
"music-server/pkg/models"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var currentSong = -1
|
||||||
|
var games []models.GameData
|
||||||
|
var songQue []models.SongData
|
||||||
|
var lastFetched models.SongData
|
||||||
|
|
||||||
|
func GetSoundCheckSong() string {
|
||||||
|
Reset()
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir("songs")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fileInfo := files[rand.Intn(len(files))]
|
||||||
|
return "songs/" + fileInfo.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Reset() {
|
||||||
|
songQue = nil
|
||||||
|
currentSong = -1
|
||||||
|
games = db.FindAllGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddLatestToQue() {
|
||||||
|
if lastFetched.Path != "" {
|
||||||
|
currentSong = len(songQue)
|
||||||
|
songQue = append(songQue, lastFetched)
|
||||||
|
lastFetched = models.SongData{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRandomSong() string {
|
||||||
|
if games == nil || len(games) == 0 {
|
||||||
|
games = db.FindAllGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
song := getSongFromList(games)
|
||||||
|
|
||||||
|
lastFetched = song
|
||||||
|
return song.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRandomSongLowChance() string {
|
||||||
|
gameList := db.FindAllGames()
|
||||||
|
|
||||||
|
var listOfGames []models.GameData
|
||||||
|
|
||||||
|
var averagePlayed = getAveragePlayed(gameList)
|
||||||
|
|
||||||
|
for _, data := range gameList {
|
||||||
|
var timesToAdd = averagePlayed - data.TimesPlayed
|
||||||
|
if timesToAdd <= 0 {
|
||||||
|
listOfGames = append(listOfGames, data)
|
||||||
|
} else {
|
||||||
|
for i := 0; i < timesToAdd; i++ {
|
||||||
|
listOfGames = append(listOfGames, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
song := getSongFromList(listOfGames)
|
||||||
|
|
||||||
|
lastFetched = song
|
||||||
|
return song.Path
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSongInfo() models.SongInfo {
|
||||||
|
if songQue == nil {
|
||||||
|
return models.SongInfo{}
|
||||||
|
}
|
||||||
|
var currentSongData = songQue[currentSong]
|
||||||
|
|
||||||
|
currentGameData := getCurrentGame(currentSongData)
|
||||||
|
|
||||||
|
return models.SongInfo{
|
||||||
|
Game: currentGameData.GameName,
|
||||||
|
GamePlayed: currentGameData.TimesPlayed,
|
||||||
|
Song: currentSongData.SongName,
|
||||||
|
SongPlayed: currentSongData.TimesPlayed,
|
||||||
|
CurrentlyPlaying: true,
|
||||||
|
SongNo: currentSong,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlayedSongs() []models.SongInfo {
|
||||||
|
var songList []models.SongInfo
|
||||||
|
|
||||||
|
for i, song := range songQue {
|
||||||
|
gameData := getCurrentGame(song)
|
||||||
|
songList = append(songList, models.SongInfo{
|
||||||
|
Game: gameData.GameName,
|
||||||
|
GamePlayed: gameData.TimesPlayed,
|
||||||
|
Song: song.SongName,
|
||||||
|
SongPlayed: song.TimesPlayed,
|
||||||
|
CurrentlyPlaying: i == currentSong,
|
||||||
|
SongNo: i,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return songList
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSong(song string) string {
|
||||||
|
currentSong, _ = strconv.Atoi(song)
|
||||||
|
if currentSong >= len(songQue) {
|
||||||
|
currentSong = len(songQue) - 1
|
||||||
|
} else if currentSong < 0 {
|
||||||
|
currentSong = 0
|
||||||
|
}
|
||||||
|
var songData = songQue[currentSong]
|
||||||
|
return songData.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllGames() []string {
|
||||||
|
if games == nil || len(games) == 0 {
|
||||||
|
games = db.FindAllGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonArray []string
|
||||||
|
for _, game := range games {
|
||||||
|
jsonArray = append(jsonArray, game.GameName)
|
||||||
|
}
|
||||||
|
return jsonArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllGamesRandom() []string {
|
||||||
|
if games == nil || len(games) == 0 {
|
||||||
|
games = db.FindAllGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonArray []string
|
||||||
|
for _, game := range games {
|
||||||
|
jsonArray = append(jsonArray, game.GameName)
|
||||||
|
}
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] })
|
||||||
|
return jsonArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetPlayed(songNumber int) {
|
||||||
|
if songQue == nil || len(songQue) == 0 || songNumber >= len(songQue) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var songData = songQue[songNumber]
|
||||||
|
db.AddGamePlayed(songData.GameId)
|
||||||
|
db.AddSongPlayed(songData.GameId, songData.SongName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNextSong() string {
|
||||||
|
if songQue == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if currentSong == len(songQue)-1 || currentSong == -1 {
|
||||||
|
var songData = songQue[currentSong]
|
||||||
|
return songData.Path
|
||||||
|
} else {
|
||||||
|
currentSong = currentSong + 1
|
||||||
|
var songData = songQue[currentSong]
|
||||||
|
return songData.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPreviousSong() string {
|
||||||
|
if songQue == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if currentSong == -1 || currentSong == 0 {
|
||||||
|
var songData = songQue[0]
|
||||||
|
return songData.Path
|
||||||
|
} else {
|
||||||
|
currentSong = currentSong - 1
|
||||||
|
var songData = songQue[currentSong]
|
||||||
|
return songData.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSongFromList(games []models.GameData) models.SongData {
|
||||||
|
songFound := false
|
||||||
|
var song models.SongData
|
||||||
|
for !songFound {
|
||||||
|
game := getRandomGame(games)
|
||||||
|
songs := db.FindSongsFromGame(game.Id)
|
||||||
|
song = songs[rand.Intn(len(songs))]
|
||||||
|
|
||||||
|
//Check if file exists and open
|
||||||
|
openFile, err := os.Open(song.Path)
|
||||||
|
if err != nil {
|
||||||
|
//File not found
|
||||||
|
log.Fatal("Song not found, maybe delete song and/or game" + song.SongName + " songPath: " + song.Path)
|
||||||
|
} else {
|
||||||
|
songFound = true
|
||||||
|
}
|
||||||
|
|
||||||
|
err = openFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return song
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCurrentGame(currentSongData models.SongData) models.GameData {
|
||||||
|
for _, game := range games {
|
||||||
|
if game.Id == currentSongData.GameId {
|
||||||
|
return game
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return models.GameData{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAveragePlayed(gameList []models.GameData) int {
|
||||||
|
var sum int
|
||||||
|
for _, data := range gameList {
|
||||||
|
sum += data.TimesPlayed
|
||||||
|
}
|
||||||
|
return sum / len(gameList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRandomGame(listOfGames []models.GameData) models.GameData {
|
||||||
|
return listOfGames[rand.Intn(len(listOfGames))]
|
||||||
|
}
|
||||||
@@ -1,37 +1,18 @@
|
|||||||
package main
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"music-server/pkg/db"
|
||||||
|
"music-server/pkg/models"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func syncHandler(w http.ResponseWriter, r *http.Request) {
|
func SyncGames() {
|
||||||
setCorsAndNoCacheHeaders(&w, r)
|
|
||||||
if r.URL.Path == "/sync" {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
syncGames()
|
|
||||||
_, err := fmt.Fprint(w, "Games are synced")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if r.URL.Path == "/sync/reset" {
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
resetDB()
|
|
||||||
_, err := fmt.Fprint(w, "Games and songs are deleted from the database")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func syncGames() {
|
|
||||||
host := os.Getenv("DB_HOST")
|
host := os.Getenv("DB_HOST")
|
||||||
var dir string
|
var dir string
|
||||||
if host != "" {
|
if host != "" {
|
||||||
@@ -42,7 +23,7 @@ func syncGames() {
|
|||||||
fmt.Printf("dir: %s\n", dir)
|
fmt.Printf("dir: %s\n", dir)
|
||||||
foldersToSkip := []string{".sync"}
|
foldersToSkip := []string{".sync"}
|
||||||
fmt.Println(foldersToSkip)
|
fmt.Println(foldersToSkip)
|
||||||
setGameDeletionDate()
|
db.SetGameDeletionDate()
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(dir)
|
files, err := ioutil.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -76,6 +57,11 @@ func syncGames() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ResetDB() {
|
||||||
|
db.ClearSongs(-1)
|
||||||
|
db.ClearGames()
|
||||||
|
}
|
||||||
|
|
||||||
func getIdFromFile(file os.FileInfo) int {
|
func getIdFromFile(file os.FileInfo) int {
|
||||||
name := file.Name()
|
name := file.Name()
|
||||||
if !file.IsDir() && strings.HasSuffix(name, ".id") {
|
if !file.IsDir() && strings.HasSuffix(name, ".id") {
|
||||||
@@ -89,24 +75,24 @@ func getIdFromFile(file os.FileInfo) int {
|
|||||||
|
|
||||||
func checkIfChanged(id int, name string, path string) {
|
func checkIfChanged(id int, name string, path string) {
|
||||||
fmt.Printf("Id from file: %v\n", id)
|
fmt.Printf("Id from file: %v\n", id)
|
||||||
nameFromDb := getGameName(id)
|
nameFromDb := db.GetGameName(id)
|
||||||
fmt.Printf("Name from file: %v\n", name)
|
fmt.Printf("Name from file: %v\n", name)
|
||||||
fmt.Printf("Name from DB: %v\n", nameFromDb)
|
fmt.Printf("Name from DB: %v\n", nameFromDb)
|
||||||
if nameFromDb == "" {
|
if nameFromDb == "" {
|
||||||
fmt.Println("Not in db")
|
fmt.Println("Not in db")
|
||||||
insertGameWithExistingId(id, name, path)
|
db.InsertGameWithExistingId(id, name, path)
|
||||||
fmt.Println("Added to db")
|
fmt.Println("Added to db")
|
||||||
} else if name != nameFromDb {
|
} else if name != nameFromDb {
|
||||||
fmt.Println("Diff name")
|
fmt.Println("Diff name")
|
||||||
updateGameName(id, name, path)
|
db.UpdateGameName(id, name, path)
|
||||||
}
|
}
|
||||||
removeDeletionDate(id)
|
db.RemoveDeletionDate(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addNewGame(name string, path string) {
|
func addNewGame(name string, path string) {
|
||||||
newId := getIdByGameName(name)
|
newId := db.GetIdByGameName(name)
|
||||||
if newId == -1 {
|
if newId == -1 {
|
||||||
newId = insertGame(name, path)
|
newId = db.InsertGame(name, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("newId = %v", newId)
|
fmt.Printf("newId = %v", newId)
|
||||||
@@ -121,8 +107,8 @@ func addNewGame(name string, path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkSongs(gameDir string, gameId int) {
|
func checkSongs(gameDir string, gameId int) {
|
||||||
songs := make([]SongData, 0)
|
songs := make([]models.SongData, 0)
|
||||||
findSongsFromGame := findSongsFromGame(gameId)
|
findSongsFromGame := db.FindSongsFromGame(gameId)
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(gameDir)
|
files, err := ioutil.ReadDir(gameDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -132,22 +118,17 @@ func checkSongs(gameDir string, gameId int) {
|
|||||||
path := gameDir + entry.Name()
|
path := gameDir + entry.Name()
|
||||||
songName := entry.Name()
|
songName := entry.Name()
|
||||||
if !entry.IsDir() && !strings.HasSuffix(songName, ".id") {
|
if !entry.IsDir() && !strings.HasSuffix(songName, ".id") {
|
||||||
songs = append(songs, SongData{gameId: gameId, songName: songName, path: path})
|
songs = append(songs, models.SongData{GameId: gameId, SongName: songName, Path: path})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(songs) != len(findSongsFromGame) {
|
if len(songs) != len(findSongsFromGame) {
|
||||||
clearSongs(gameId)
|
db.ClearSongs(gameId)
|
||||||
for _, song := range songs {
|
for _, song := range songs {
|
||||||
addSong(song)
|
db.AddSong(song)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetDB() {
|
|
||||||
clearSongs(-1)
|
|
||||||
clearGames()
|
|
||||||
}
|
|
||||||
|
|
||||||
func contains(s []string, searchTerm string) bool {
|
func contains(s []string, searchTerm string) bool {
|
||||||
i := sort.SearchStrings(s, searchTerm)
|
i := sort.SearchStrings(s, searchTerm)
|
||||||
return i < len(s) && s[i] == searchTerm
|
return i < len(s) && s[i] == searchTerm
|
||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user