1.0 of Go version
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.idea
|
||||||
4
.idea/MusicServer.iml
generated
4
.idea/MusicServer.iml
generated
@@ -10,7 +10,9 @@
|
|||||||
</buildTags>
|
</buildTags>
|
||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.idea/dataSources" />
|
||||||
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
11
.idea/dataSources.xml
generated
Normal file
11
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?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>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
245
.idea/workspace.xml
generated
245
.idea/workspace.xml
generated
@@ -1,25 +1,86 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<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">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="d639f8a9-4b6d-4957-9ba4-8361acac15ca" name="Default Changelist" comment="" />
|
<list default="true" id="d639f8a9-4b6d-4957-9ba4-8361acac15ca" name="Default Changelist" comment="">
|
||||||
|
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/.idea/dataSources.xml" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/Dockerfile" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/database.go" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/doc/swagger.yaml" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/init.sh" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/musicFacade.go" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/songs/01. Opening.mp3" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/songs/01. Title.mp3" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/syncFacade.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$/musicserver.go" beforeDir="false" afterPath="$PROJECT_DIR$/musicserver.go" afterDir="false" />
|
||||||
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="GOROOT" path="/usr/local/Cellar/go/1.15.2/libexec" />
|
<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="ProjectId" id="1ipVJv6kTmBdByNysh6NxmS21gD" />
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||||
<component name="ProjectViewState">
|
<component name="ProjectViewState">
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">
|
<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="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||||
|
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
|
||||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
<property name="go.import.settings.migrated" value="true" />
|
<property name="go.import.settings.migrated" value="true" />
|
||||||
<property name="last_opened_file_path" value="$USER_HOME$" />
|
<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" />
|
<property name="restartRequiresConfirmation" value="false" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
|
<recent name="$PROJECT_DIR$/songs" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
<component name="RunManager">
|
<component name="RunManager">
|
||||||
<configuration name="App Engine" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
<configuration name="App Engine" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||||
<module name="MusicServer" />
|
<module name="MusicServer" />
|
||||||
@@ -31,27 +92,189 @@
|
|||||||
<directory value="$PROJECT_DIR$" />
|
<directory value="$PROJECT_DIR$" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</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>
|
||||||
</component>
|
</component>
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
<option name="version" value="3" />
|
<option name="version" value="3" />
|
||||||
</component>
|
</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="VgoProject">
|
||||||
|
<integration-enabled>true</integration-enabled>
|
||||||
|
</component>
|
||||||
<component name="WindowStateProjectService">
|
<component name="WindowStateProjectService">
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.bottom" timestamp="1602604775177">
|
<state x="432" y="337" key="#GOROOT" timestamp="1606056684244">
|
||||||
<screen x="0" y="0" width="1280" height="800" />
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
</state>
|
</state>
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.bottom/0.0.1280.800@0.0.1280.800" timestamp="1602604775177" />
|
<state x="432" y="337" key="#GOROOT/0.0.1280.800@0.0.1280.800" timestamp="1606056684244" />
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.center" timestamp="1602604775176">
|
<state x="440" y="240" key="#Go_Modules" timestamp="1602878032740">
|
||||||
<screen x="0" y="0" width="1280" height="800" />
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
</state>
|
</state>
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.center/0.0.1280.800@0.0.1280.800" timestamp="1602604775176" />
|
<state x="440" y="240" key="#Go_Modules/0.0.1280.800@0.0.1280.800" timestamp="1602878032740" />
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.left" timestamp="1602604775175">
|
<state x="209" y="65" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1606500738678">
|
||||||
<screen x="0" y="0" width="1280" height="800" />
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
</state>
|
</state>
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.left/0.0.1280.800@0.0.1280.800" timestamp="1602604775175" />
|
<state x="209" y="65" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.1280.800@0.0.1280.800" timestamp="1606500738678" />
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.right" timestamp="1602604775177">
|
<state x="354" y="206" key="#com.intellij.fileTypes.FileTypeChooser" timestamp="1606327049349">
|
||||||
<screen x="0" y="0" width="1280" height="800" />
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
</state>
|
</state>
|
||||||
<state width="1238" height="212" key="GridCell.Tab.0.right/0.0.1280.800@0.0.1280.800" timestamp="1602604775177" />
|
<state x="354" y="206" key="#com.intellij.fileTypes.FileTypeChooser/0.0.1280.800@0.0.1280.800" timestamp="1606327049349" />
|
||||||
|
<state x="63" y="22" width="1120" height="704" key="CommitChangelistDialog2" timestamp="1606500771742">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="63" y="22" width="1120" height="704" key="CommitChangelistDialog2/0.0.1280.800@0.0.1280.800" timestamp="1606500771742" />
|
||||||
|
<state x="500" y="304" key="Github.ShareDialog" timestamp="1602604919305">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="500" y="304" key="Github.ShareDialog/0.0.1280.800@0.0.1280.800" timestamp="1602604919305" />
|
||||||
|
<state x="454" y="112" key="Github.UntrackedFilesDialog" timestamp="1602604943862">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="454" y="112" key="Github.UntrackedFilesDialog/0.0.1280.800@0.0.1280.800" timestamp="1602604943862" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.bottom" timestamp="1606334681949">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.bottom/0.0.1280.800@0.0.1280.800" timestamp="1606334681949" />
|
||||||
|
<state width="846" height="212" key="GridCell.Tab.0.bottom/0.25.1280.702@0.25.1280.702" timestamp="1606330812762" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.center" timestamp="1606334681948">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.center/0.0.1280.800@0.0.1280.800" timestamp="1606334681948" />
|
||||||
|
<state width="846" height="212" key="GridCell.Tab.0.center/0.25.1280.702@0.25.1280.702" timestamp="1606330812757" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.left" timestamp="1606334681947">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.left/0.0.1280.800@0.0.1280.800" timestamp="1606334681947" />
|
||||||
|
<state width="846" height="212" key="GridCell.Tab.0.left/0.25.1280.702@0.25.1280.702" timestamp="1606330812754" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.right" timestamp="1606334681949">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.0.right/0.0.1280.800@0.0.1280.800" timestamp="1606334681949" />
|
||||||
|
<state width="846" height="212" key="GridCell.Tab.0.right/0.25.1280.702@0.25.1280.702" timestamp="1606330812760" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.bottom" timestamp="1606334681952">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.bottom/0.0.1280.800@0.0.1280.800" timestamp="1606334681952" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.bottom/0.25.1280.702@0.25.1280.702" timestamp="1606330741478" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.center" timestamp="1606334681950">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.center/0.0.1280.800@0.0.1280.800" timestamp="1606334681950" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.center/0.25.1280.702@0.25.1280.702" timestamp="1606330741474" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.left" timestamp="1606334681950">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.left/0.0.1280.800@0.0.1280.800" timestamp="1606334681950" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.left/0.25.1280.702@0.25.1280.702" timestamp="1606330741473" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.right" timestamp="1606334681951">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.right/0.0.1280.800@0.0.1280.800" timestamp="1606334681951" />
|
||||||
|
<state width="1238" height="264" key="GridCell.Tab.1.right/0.25.1280.702@0.25.1280.702" timestamp="1606330741474" />
|
||||||
|
<state x="491" y="322" key="VCS.ChangelistChooser" timestamp="1604854207192">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="491" y="322" key="VCS.ChangelistChooser/0.0.1280.800@0.0.1280.800" timestamp="1604854207192" />
|
||||||
|
<state x="546" y="264" key="com.intellij.docker.deployment.ui.DockerPortBindingsField.v173.dialogSize" timestamp="1606060189431">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="546" y="264" key="com.intellij.docker.deployment.ui.DockerPortBindingsField.v173.dialogSize/0.0.1280.800@0.0.1280.800" timestamp="1606060189431" />
|
||||||
|
<state x="361" y="264" width="706" height="259" key="com.intellij.docker.deployment.ui.DockerVolumeBindingsField.v173.dialogSize" timestamp="1606334614894">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="361" y="264" width="706" height="259" key="com.intellij.docker.deployment.ui.DockerVolumeBindingsField.v173.dialogSize/0.0.1280.800@0.0.1280.800" timestamp="1606334614894" />
|
||||||
|
<state x="483" y="173" key="refactoring.ChangeSignatureDialog" timestamp="1603014849046">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="483" y="173" key="refactoring.ChangeSignatureDialog/0.0.1280.800@0.0.1280.800" timestamp="1603014849046" />
|
||||||
|
<state x="305" y="124" width="670" height="676" key="search.everywhere.popup" timestamp="1602967169862">
|
||||||
|
<screen x="0" y="0" width="1280" height="800" />
|
||||||
|
</state>
|
||||||
|
<state x="305" y="124" width="670" height="676" key="search.everywhere.popup/0.0.1280.800@0.0.1280.800" timestamp="1602967169862" />
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager>
|
||||||
|
<breakpoints>
|
||||||
|
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||||
|
<url>file://$PROJECT_DIR$/musicFacade.go</url>
|
||||||
|
<line>139</line>
|
||||||
|
<option name="timeStamp" value="4" />
|
||||||
|
</line-breakpoint>
|
||||||
|
</breakpoints>
|
||||||
|
</breakpoint-manager>
|
||||||
|
<watches-manager>
|
||||||
|
<configuration name="GoApplicationRunConfiguration">
|
||||||
|
<watch expression="games" language="go" />
|
||||||
|
<watch expression="songQue" language="go" />
|
||||||
|
</configuration>
|
||||||
|
</watches-manager>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
27
Dockerfile
Normal file
27
Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
FROM golang:1.15.5-alpine as build_go
|
||||||
|
|
||||||
|
COPY *.go go.mod /music-server/
|
||||||
|
WORKDIR /music-server
|
||||||
|
RUN go build
|
||||||
|
|
||||||
|
# Stage 2, distribution container
|
||||||
|
FROM golang:1.15.5-alpine
|
||||||
|
RUN apk add --no-cache bash
|
||||||
|
EXPOSE 8080
|
||||||
|
VOLUME /sorted
|
||||||
|
VOLUME /sorterad
|
||||||
|
VOLUME /doc
|
||||||
|
|
||||||
|
ENV DB_HOST ""
|
||||||
|
ENV DB_PORT ""
|
||||||
|
ENV DB_USERNAME ""
|
||||||
|
ENV DB_PASSWORD ""
|
||||||
|
ENV DB_NAME ""
|
||||||
|
|
||||||
|
COPY --from=build_go /music-server/MusicServer .
|
||||||
|
COPY ./doc/swagger.yaml .
|
||||||
|
COPY ./songs/ ./songs/
|
||||||
|
COPY ./init.sh .
|
||||||
|
RUN chmod 777 ./init.sh
|
||||||
|
|
||||||
|
CMD ./init.sh
|
||||||
2
app.yaml
2
app.yaml
@@ -1,5 +1,5 @@
|
|||||||
application: musicserver
|
application: musicserver
|
||||||
version: 1
|
version: 2.0.0
|
||||||
runtime: go115
|
runtime: go115
|
||||||
api_version: go1
|
api_version: go1
|
||||||
|
|
||||||
|
|||||||
244
database.go
Normal file
244
database.go
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
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")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
290
doc/swagger.yaml
Normal file
290
doc/swagger.yaml
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
version: "2.0.0"
|
||||||
|
title: "Music Server"
|
||||||
|
description: "Rebuilt the application in Go."
|
||||||
|
contact:
|
||||||
|
email: "zarnor91@gmail.com"
|
||||||
|
servers:
|
||||||
|
- url: https://music.sanplex.xyz/
|
||||||
|
description: Main (production) server
|
||||||
|
tags:
|
||||||
|
- name: "Music"
|
||||||
|
description: "Endpoints for the music"
|
||||||
|
- name: "Version"
|
||||||
|
description: "Information about the application"
|
||||||
|
- name: "Sync"
|
||||||
|
description: "Sync the database with the folders"
|
||||||
|
paths:
|
||||||
|
/music:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Get song"
|
||||||
|
description: "Get a specified song from the que, if invalid number it will be the first or the last song in que"
|
||||||
|
operationId: "getSong"
|
||||||
|
parameters:
|
||||||
|
- name: "song"
|
||||||
|
in: "query"
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: "The number the song has in the que"
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "The speciefied file"
|
||||||
|
content:
|
||||||
|
audio/mpeg:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/first:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Start a match"
|
||||||
|
description: "Get a sound check song and starts a new song que"
|
||||||
|
operationId: "getFisrt"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A file"
|
||||||
|
content:
|
||||||
|
audio/mpeg:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/rand:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Get random song"
|
||||||
|
description: "Takes a random song from a random game"
|
||||||
|
operationId: "getRandom"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A file"
|
||||||
|
content:
|
||||||
|
audio/mpeg:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/rand/low:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Get random song"
|
||||||
|
description: "Takes a random song from a random game but increases the chans for games that haven't been played"
|
||||||
|
operationId: "getRandomLow"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A file"
|
||||||
|
content:
|
||||||
|
audio/mpeg:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/info:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Get info of current song"
|
||||||
|
description: "Return the info of the song currently playing"
|
||||||
|
operationId: "getInfo"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "Info of current song"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/info'
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/list:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Gets song que"
|
||||||
|
description: "Gets a list of all songs that have been fetched"
|
||||||
|
operationId: "getList"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A list"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/list'
|
||||||
|
"500":
|
||||||
|
description: "Something went wrong on the server"
|
||||||
|
/music/next:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Get next song"
|
||||||
|
description: "Gets next song in the song que, if there is no more a new random song will be generated."
|
||||||
|
operationId: "getNext"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A file"
|
||||||
|
content:
|
||||||
|
audio/mpeg:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/previous:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Get previous song"
|
||||||
|
description: "Gets previous song in the song que, if there is no more the first song will be returns."
|
||||||
|
operationId: "getPrevious"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A file"
|
||||||
|
content:
|
||||||
|
audio/mpeg:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
format: binary
|
||||||
|
"500":
|
||||||
|
description: "Something wnet wrong on the server"
|
||||||
|
/music/all:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Gets all games"
|
||||||
|
description: "Gets a list of all games that is in the databse"
|
||||||
|
operationId: "getAll"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "A list"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example: ["God of War", "Final Fantasy VII"]
|
||||||
|
"500":
|
||||||
|
description: "Something went wrong on the server"
|
||||||
|
/music/played:
|
||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Increase played"
|
||||||
|
description: "Increase the number of times the current game has been played"
|
||||||
|
operationId: "setPlayed"
|
||||||
|
responses:
|
||||||
|
"202":
|
||||||
|
description: "Accepted"
|
||||||
|
"401":
|
||||||
|
description: "Bad Request"
|
||||||
|
"500":
|
||||||
|
description: "Something went wrong on the server"
|
||||||
|
/music/reset:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Music"
|
||||||
|
summary: "Resets the song que"
|
||||||
|
description: "Resets the song que for a new match"
|
||||||
|
operationId: "reset"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "successful operation"
|
||||||
|
"500":
|
||||||
|
description: "Something went wrong on the server"
|
||||||
|
/version:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Version"
|
||||||
|
summary: "Returns pet inventories by status"
|
||||||
|
description: "Returns a map of status codes to quantities"
|
||||||
|
operationId: "getVersionInfo"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "successful operation"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/versionInfo'
|
||||||
|
/sync:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- "Sync"
|
||||||
|
summary: "Sync games"
|
||||||
|
description: "Sync the database with the folders"
|
||||||
|
operationId: "sync"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "successful operation"
|
||||||
|
"500":
|
||||||
|
description: "Something went wrong on the server"
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
list:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
Game:
|
||||||
|
type: string
|
||||||
|
example: God of War
|
||||||
|
Song:
|
||||||
|
type: string
|
||||||
|
example: Main Theme.mp3
|
||||||
|
CurrentlyPlaying:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
description: Only included on the one that's playing
|
||||||
|
SongNo:
|
||||||
|
type: integer
|
||||||
|
example: 3
|
||||||
|
info:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
Game:
|
||||||
|
type: string
|
||||||
|
example: God of War
|
||||||
|
GamePlayed:
|
||||||
|
type: integer
|
||||||
|
example: 10
|
||||||
|
Song:
|
||||||
|
type: string
|
||||||
|
example: Main Theme.mp3
|
||||||
|
SongPlayed:
|
||||||
|
type: integer
|
||||||
|
example: 10
|
||||||
|
SongNo:
|
||||||
|
type: integer
|
||||||
|
example: 3
|
||||||
|
versionInfo:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
example: 0.5.1
|
||||||
|
changelog:
|
||||||
|
type: string
|
||||||
|
example: "Added shadow to build fat jars. Added support to give property files through arguments."
|
||||||
|
history:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/historyInfo'
|
||||||
|
historyInfo:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
example: 0.5.0
|
||||||
|
changelog:
|
||||||
|
type: string
|
||||||
|
example: "Updated kotlin version, gradle version and al libs. Added connection to database with exposed. Added new endpoints."
|
||||||
9
go.mod
Normal file
9
go.mod
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module MusicServer
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/jackc/pgtype v1.5.0
|
||||||
|
github.com/jackc/pgx/v4 v4.9.0
|
||||||
|
)
|
||||||
4
init.sh
Normal file
4
init.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
mkdir /doc
|
||||||
|
cp swagger.yaml /doc
|
||||||
|
./MusicServer
|
||||||
243
musicFacade.go
Normal file
243
musicFacade.go
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var currentSong = -1
|
||||||
|
var games []GameData
|
||||||
|
var songQue []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 getRandomSong() string {
|
||||||
|
if games == nil || len(games) == 0 {
|
||||||
|
games = findAllGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
game := getRandomGame(games)
|
||||||
|
|
||||||
|
songs := findSongsFromGame(game.id)
|
||||||
|
|
||||||
|
song := songs[rand.Intn(len(songs))]
|
||||||
|
|
||||||
|
currentSong = len(songQue)
|
||||||
|
songQue = append(songQue, song)
|
||||||
|
return song.path
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
game := getRandomGame(listOfGames)
|
||||||
|
|
||||||
|
songs := findSongsFromGame(game.id)
|
||||||
|
|
||||||
|
song := songs[rand.Intn(len(songs))]
|
||||||
|
|
||||||
|
currentSong = len(songQue)
|
||||||
|
songQue = append(songQue, song)
|
||||||
|
return song.path
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSongInfo() 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 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 currentSong == len(songQue)-1 || currentSong == -1 {
|
||||||
|
return getRandomSong()
|
||||||
|
} else {
|
||||||
|
currentSong = currentSong + 1
|
||||||
|
var songData = songQue[currentSong]
|
||||||
|
return songData.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPreviousSong() string {
|
||||||
|
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) {
|
||||||
|
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 {
|
||||||
|
http.ServeFile(w, r, getSong(song))
|
||||||
|
}
|
||||||
|
} else if r.URL.Path == "/music/first" && r.Method == http.MethodGet {
|
||||||
|
http.ServeFile(w, r, getSoundCheckSong())
|
||||||
|
|
||||||
|
} 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 {
|
||||||
|
http.ServeFile(w, r, getRandomSong())
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/rand/low" && r.Method == http.MethodGet {
|
||||||
|
http.ServeFile(w, r, getRandomSongLowChance())
|
||||||
|
|
||||||
|
} 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" {
|
||||||
|
http.ServeFile(w, r, getNextSong())
|
||||||
|
|
||||||
|
} else if r.URL.Path == "/music/previous" {
|
||||||
|
http.ServeFile(w, r, getPreviousSong())
|
||||||
|
|
||||||
|
} 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/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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))]
|
||||||
|
}
|
||||||
135
musicserver.go
135
musicserver.go
@@ -1,14 +1,59 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/", indexHandler)
|
// 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")
|
port := os.Getenv("PORT")
|
||||||
if port == "" {
|
if port == "" {
|
||||||
port = "8080"
|
port = "8080"
|
||||||
@@ -20,13 +65,91 @@ func main() {
|
|||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
|
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 indexHandler(w http.ResponseWriter, r *http.Request) {
|
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/test" {
|
if r.URL.Path == "/version" {
|
||||||
_, err := fmt.Fprint(w, "Testing path")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
testf()
|
||||||
|
|
||||||
|
data := VersionData{Version: "2.0.0",
|
||||||
|
Changelog: "Rebuilt the application in Go.",
|
||||||
|
History: []VersionData{
|
||||||
|
{
|
||||||
|
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 == "/" {
|
} 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!!")
|
_, err := fmt.Fprint(w, "Hello, World!!")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
@@ -36,4 +159,4 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
songs/01. Opening.mp3
Executable file
BIN
songs/01. Opening.mp3
Executable file
Binary file not shown.
BIN
songs/01. Title.mp3
Executable file
BIN
songs/01. Title.mp3
Executable file
Binary file not shown.
153
syncFacade.go
Normal file
153
syncFacade.go
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func syncHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
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")
|
||||||
|
var dir string
|
||||||
|
if host != "" {
|
||||||
|
dir = "/sorted/"
|
||||||
|
} else {
|
||||||
|
dir = "/Users/sebastian/Resilio Sync/Sorterat_test/"
|
||||||
|
}
|
||||||
|
fmt.Printf("dir: %s\n", dir)
|
||||||
|
foldersToSkip := []string{".sync"}
|
||||||
|
fmt.Println(foldersToSkip)
|
||||||
|
setGameDeletionDate()
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if file.IsDir() && !contains(foldersToSkip, file.Name()) {
|
||||||
|
fmt.Println(file.Name())
|
||||||
|
path := dir + file.Name() + "/"
|
||||||
|
fmt.Println(path)
|
||||||
|
|
||||||
|
innerFiles, err := ioutil.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
id := -1
|
||||||
|
for _, song := range innerFiles {
|
||||||
|
id = getIdFromFile(song)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
removeDeletionDate(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNewGame(name string, path string) {
|
||||||
|
newId := getIdByGameName(name)
|
||||||
|
if newId == -1 {
|
||||||
|
newId = insertGame(name, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("newId = %v", newId)
|
||||||
|
fileName := path + "/." + strconv.Itoa(newId) + ".id"
|
||||||
|
fmt.Printf("fileName = %v", fileName)
|
||||||
|
|
||||||
|
err := ioutil.WriteFile(fileName, nil, 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
checkSongs(path, newId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkSongs(gameDir string, gameId int) {
|
||||||
|
songs := make([]SongData, 0)
|
||||||
|
findSongsFromGame := findSongsFromGame(gameId)
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(gameDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, entry := range files {
|
||||||
|
path := gameDir + entry.Name()
|
||||||
|
songName := entry.Name()
|
||||||
|
if !entry.IsDir() && !strings.HasSuffix(songName, ".id") {
|
||||||
|
songs = append(songs, SongData{gameId: gameId, songName: songName, path: path})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(songs) != len(findSongsFromGame) {
|
||||||
|
clearSongs(gameId)
|
||||||
|
for _, song := range songs {
|
||||||
|
addSong(song)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetDB() {
|
||||||
|
clearSongs(-1)
|
||||||
|
clearGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(s []string, searchTerm string) bool {
|
||||||
|
i := sort.SearchStrings(s, searchTerm)
|
||||||
|
return i < len(s) && s[i] == searchTerm
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user