Update REST to allow config submission, form allowing editing of all values including the download profile commands and arguments. Neat.
This commit is contained in:
parent
2aba19770f
commit
8b291f4629
@ -1,6 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
@ -30,7 +32,7 @@ type Config struct {
|
|||||||
ConfigVersion int `yaml:"config_version" json:"config_version"`
|
ConfigVersion int `yaml:"config_version" json:"config_version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultConfig() Config {
|
func DefaultConfig() *Config {
|
||||||
defaultConfig := Config{}
|
defaultConfig := Config{}
|
||||||
stdProfile := DownloadProfile{Name: "standard youtube-dl video", Command: "youtube-dl", Args: []string{
|
stdProfile := DownloadProfile{Name: "standard youtube-dl video", Command: "youtube-dl", Args: []string{
|
||||||
"--newline",
|
"--newline",
|
||||||
@ -40,6 +42,8 @@ func DefaultConfig() Config {
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
defaultConfig.DownloadProfiles = append(defaultConfig.DownloadProfiles, stdProfile)
|
defaultConfig.DownloadProfiles = append(defaultConfig.DownloadProfiles, stdProfile)
|
||||||
|
defaultConfig.DownloadProfiles = append(defaultConfig.DownloadProfiles, stdProfile)
|
||||||
|
|
||||||
defaultConfig.Server.Port = 6123
|
defaultConfig.Server.Port = 6123
|
||||||
defaultConfig.Server.Address = "http://localhost:6123"
|
defaultConfig.Server.Address = "http://localhost:6123"
|
||||||
defaultConfig.Server.DownloadPath = "./"
|
defaultConfig.Server.DownloadPath = "./"
|
||||||
@ -49,7 +53,25 @@ func DefaultConfig() Config {
|
|||||||
|
|
||||||
defaultConfig.ConfigVersion = 1
|
defaultConfig.ConfigVersion = 1
|
||||||
|
|
||||||
return defaultConfig
|
return &defaultConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) UpdateFromJSON(j []byte) error {
|
||||||
|
newConfig := Config{}
|
||||||
|
err := json.Unmarshal(j, &newConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unmarshal error in config: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("Config is unmarshalled ok")
|
||||||
|
|
||||||
|
// other checks
|
||||||
|
if newConfig.UI.PopupHeight < 100 || newConfig.UI.PopupHeight > 2000 {
|
||||||
|
return errors.New("bad popup height")
|
||||||
|
}
|
||||||
|
|
||||||
|
*c = newConfig
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteDefaultConfig(path string) {
|
func WriteDefaultConfig(path string) {
|
||||||
|
25
main.go
25
main.go
@ -42,7 +42,7 @@ var versionInfo = version.Info{CurrentVersion: "v0.5.0"}
|
|||||||
//go:embed web
|
//go:embed web
|
||||||
var webFS embed.FS
|
var webFS embed.FS
|
||||||
|
|
||||||
var conf config.Config
|
var conf *config.Config
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
conf = config.DefaultConfig()
|
conf = config.DefaultConfig()
|
||||||
@ -131,7 +131,28 @@ func ConfigHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ConfigRESTHandler(w http.ResponseWriter, r *http.Request) {
|
func ConfigRESTHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
|
type errorResponse struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method == "POST" {
|
||||||
|
log.Printf("Updating config")
|
||||||
|
b, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Printf("Got this request:", string(b))
|
||||||
|
err = conf.UpdateFromJSON(b)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errorRes := errorResponse{Error: err.Error()}
|
||||||
|
errorResB, _ := json.Marshal(errorRes)
|
||||||
|
w.WriteHeader(400)
|
||||||
|
w.Write(errorResB)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b, _ := json.Marshal(conf)
|
b, _ := json.Marshal(conf)
|
||||||
w.Write(b)
|
w.Write(b)
|
||||||
|
@ -24,7 +24,8 @@ func (i *Info) UpdateGitHubVersion() error {
|
|||||||
versionUrl := "https://api.github.com/repos/tardisx/gropple/releases"
|
versionUrl := "https://api.github.com/repos/tardisx/gropple/releases"
|
||||||
resp, err := http.Get(versionUrl)
|
resp, err := http.Get(versionUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error getting response. ", err)
|
log.Printf("Error getting response. ", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
@ -65,11 +66,11 @@ func (i *Info) canUpgrade() bool {
|
|||||||
log.Printf("We are %s, github is %s", i.CurrentVersion, i.GithubVersion)
|
log.Printf("We are %s, github is %s", i.CurrentVersion, i.GithubVersion)
|
||||||
|
|
||||||
if !semver.IsValid(i.CurrentVersion) {
|
if !semver.IsValid(i.CurrentVersion) {
|
||||||
log.Fatalf("current version %s is invalid", i.CurrentVersion)
|
log.Printf("current version %s is invalid", i.CurrentVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !semver.IsValid(i.GithubVersion) {
|
if !semver.IsValid(i.GithubVersion) {
|
||||||
log.Fatalf("github version %s is invalid", i.GithubVersion)
|
log.Printf("github version %s is invalid", i.GithubVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
if semver.Compare(i.CurrentVersion, i.GithubVersion) == -1 {
|
if semver.Compare(i.CurrentVersion, i.GithubVersion) == -1 {
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
<h2>gropple config</h2>
|
<h2>gropple config</h2>
|
||||||
|
|
||||||
|
<p x-text="error_message"></p>
|
||||||
|
|
||||||
<p x-show="version && version.upgrade_available">
|
<p x-show="version && version.upgrade_available">
|
||||||
<a href="https://github.com/tardisx/gropple/releases">Upgrade is available</a> -
|
<a href="https://github.com/tardisx/gropple/releases">Upgrade is available</a> -
|
||||||
you have
|
you have
|
||||||
@ -21,7 +23,7 @@
|
|||||||
<legend>Server</legend>
|
<legend>Server</legend>
|
||||||
|
|
||||||
<label for="config-server-port">Listen Port</label>
|
<label for="config-server-port">Listen Port</label>
|
||||||
<input type="text" id="config-server-port" placeholder="port number" x-model="config.server.port" />
|
<input type="text" id="config-server-port" placeholder="port number" x-model.number="config.server.port" />
|
||||||
<span class="pure-form-message">The port the web server will listen on.</span>
|
<span class="pure-form-message">The port the web server will listen on.</span>
|
||||||
|
|
||||||
<label for="config-server-address">Server address (URL)</label>
|
<label for="config-server-address">Server address (URL)</label>
|
||||||
@ -38,11 +40,11 @@
|
|||||||
<legend>UI</legend>
|
<legend>UI</legend>
|
||||||
|
|
||||||
<label for="config-ui-popupwidth">Popup Width</label>
|
<label for="config-ui-popupwidth">Popup Width</label>
|
||||||
<input type="text" id="config-ui-popupwidth" placeholder="width in pixels" x-model="config.ui.popup_width" />
|
<input type="text" id="config-ui-popupwidth" placeholder="width in pixels" x-model.number="config.ui.popup_width" />
|
||||||
<span class="pure-form-message">The width of popup windows in pixels.</span>
|
<span class="pure-form-message">The width of popup windows in pixels.</span>
|
||||||
|
|
||||||
<label for="config-ui-popupheight">Popup Height</label>
|
<label for="config-ui-popupheight">Popup Height</label>
|
||||||
<input type="text" id="config-ui-popupheight" placeholder="height in pixels" x-model="config.ui.popup_height" />
|
<input type="text" id="config-ui-popupheight" placeholder="height in pixels" x-model.number="config.ui.popup_height" />
|
||||||
<span class="pure-form-message">The height of popup windows in pixels.</span>
|
<span class="pure-form-message">The height of popup windows in pixels.</span>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@ -50,21 +52,49 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-md-1-2">
|
<div class="pure-u-md-1-2">
|
||||||
<form class="pure-form pure-form-stacked">
|
<form class="pure-form ">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
||||||
<legend>Download Profiles</legend>
|
<legend>Download Profiles</legend>
|
||||||
|
|
||||||
<label for="config-profiles-0-name">Name of this profile</label>
|
<template x-for="(profile, i) in config.profiles">
|
||||||
<input type="text" id="config-profiles-0-name" placeholder="name" x-model="config.profiles[0].name" />
|
<div>
|
||||||
<span class="pure-form-message">The name of this profile. For your information only.</span>
|
<label x-bind:for="'config-profiles-'+i+'-name'">Name of profile <span x-text="i+1"></span></label>
|
||||||
|
<input type="text" x-bind:id="'config-profiles-'+i+'-name'" placeholder="name" x-model="profile.name" />
|
||||||
|
<span class="pure-form-message">The name of this profile. For your information only.</span>
|
||||||
|
|
||||||
|
<label x-bind:for="'config-profiles-'+i+'-command'">Command to run</label>
|
||||||
|
<input type="text" x-bind:id="'config-profiles-'+i+'-command'" placeholder="name" x-model="profile.command" />
|
||||||
|
<span class="pure-form-message">Which command to run.</span>
|
||||||
|
|
||||||
|
|
||||||
|
<label>Args</label>
|
||||||
|
|
||||||
|
<template x-for="(arg, j) in profile.args">
|
||||||
|
<div>
|
||||||
|
<input type="text" x-bind:id="'config-profiles-'+i+'-arg-'+j" placeholder="arg" x-model="profile.args[j]" />
|
||||||
|
<button class="pure-button" href="#" @click.prevent="profile.args.splice(j, 1);;">del</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<button class="pure-button" href="#" @click.prevent="profile.args.push('');">add arg</button>
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pure-g">
|
||||||
|
<div class="pure-u-1">
|
||||||
|
<button class="pure-button" @click="save_config();" href="#">Save Config</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -74,7 +104,10 @@
|
|||||||
<script>
|
<script>
|
||||||
function config() {
|
function config() {
|
||||||
return {
|
return {
|
||||||
config: { server : {}, ui : {}, profiles: [{}] }, version: {},
|
config: { server : {}, ui : {}, profiles: [] },
|
||||||
|
version: {},
|
||||||
|
error_message: '',
|
||||||
|
|
||||||
fetch_config() {
|
fetch_config() {
|
||||||
fetch('/rest/config')
|
fetch('/rest/config')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
@ -82,10 +115,32 @@
|
|||||||
this.config = config;
|
this.config = config;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.log('failed to fetch version info - will retry');
|
console.log('failed to fetch config', error);
|
||||||
setTimeout(() => { this.fetch_version() }, 1000 );
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
save_config() {
|
||||||
|
console.log(this.config);
|
||||||
|
let op = {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(this.config),
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}
|
||||||
|
fetch('/rest/config', op)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status >= 200 && response.status <= 299) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw Error(response);
|
||||||
|
}})
|
||||||
|
.then(config => {
|
||||||
|
console.log('fixing object');
|
||||||
|
this.config = config;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.error_message = error.error;
|
||||||
|
console.log('failed to update config', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user