Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c47660addf | |||
| 2d0e294af6 | |||
| 283e0f3584 | |||
| 9ef6ab71c7 | |||
| 701583d3fd | |||
| 0c156a19f0 | |||
| cc54bb6469 | |||
| 71c097e578 | |||
| d23e31c0e0 | |||
| 9cb79a846e | |||
| a5ce0c7f63 | |||
| bcc4e145a2 | |||
| d8c0b7d0ea | |||
| fdf70daba7 | |||
| b69cdebf3b | |||
| 9e22490fe2 | |||
|
|
ae24f16631 | ||
|
|
b69acac0d0 | ||
|
|
c833f185cc | ||
|
|
b3ee0d9d1d |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ discord-auto-upload.exe
|
|||||||
assets
|
assets
|
||||||
*.png
|
*.png
|
||||||
*.jpg
|
*.jpg
|
||||||
|
.DS_Store
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 Justin Hawkins
|
Copyright (c) 2021 Justin Hawkins
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Binaries are available for Mac, Linux and Windows [here](https://github.com/tard
|
|||||||
|
|
||||||
#### From source
|
#### From source
|
||||||
|
|
||||||
You'll need to [download Go](https://golang.org/dl/) check the code out somewhere, run 'go generate' and then 'go build'.
|
You'll need to [download Go](https://golang.org/dl/), check the code out somewhere, run 'go generate' and then 'go build'.
|
||||||
|
|
||||||
## Using it
|
## Using it
|
||||||
|
|
||||||
@@ -80,6 +80,11 @@ thumbnail files.
|
|||||||
* Files to upload are determined by the file modification time. If you drag and drop existing files they will
|
* Files to upload are determined by the file modification time. If you drag and drop existing files they will
|
||||||
not be detected and uploaded. Only newly created files will be detected.
|
not be detected and uploaded. Only newly created files will be detected.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
Please check the "log" page on the web interface for information when things are
|
||||||
|
not working as you expect.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
This is just a relatively quick hack. Open to suggestions on new features and improvements.
|
This is just a relatively quick hack. Open to suggestions on new features and improvements.
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mitchellh/go-homedir"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
daulog "github.com/tardisx/discord-auto-upload/log"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config for the application
|
// Config for the application
|
||||||
@@ -18,16 +22,16 @@ var Config struct {
|
|||||||
Exclude string
|
Exclude string
|
||||||
}
|
}
|
||||||
|
|
||||||
const CurrentVersion string = "0.7"
|
const CurrentVersion string = "0.10"
|
||||||
|
|
||||||
// Load the current config or initialise with defaults
|
// Load the current config or initialise with defaults
|
||||||
func LoadOrInit() {
|
func LoadOrInit() {
|
||||||
configPath := configPath()
|
configPath := configPath()
|
||||||
log.Printf("Trying to load from %s\n", configPath)
|
daulog.SendLog(fmt.Sprintf("Trying to load config from %s", configPath), daulog.LogTypeDebug)
|
||||||
_, err := os.Stat(configPath)
|
_, err := os.Stat(configPath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Printf("NOTE: No config file, writing out sample configuration")
|
daulog.SendLog("NOTE: No config file, writing out sample configuration", daulog.LogTypeInfo)
|
||||||
log.Printf("You need to set the configuration via the web interface")
|
daulog.SendLog("You need to set the configuration via the web interface", daulog.LogTypeInfo)
|
||||||
|
|
||||||
Config.WebHookURL = ""
|
Config.WebHookURL = ""
|
||||||
Config.Path = homeDir() + string(os.PathSeparator) + "screenshots"
|
Config.Path = homeDir() + string(os.PathSeparator) + "screenshots"
|
||||||
@@ -51,19 +55,21 @@ func LoadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SaveConfig() {
|
func SaveConfig() {
|
||||||
log.Print("saving configuration")
|
daulog.SendLog("saving configuration", daulog.LogTypeInfo)
|
||||||
path := configPath()
|
path := configPath()
|
||||||
jsonString, _ := json.Marshal(Config)
|
jsonString, _ := json.Marshal(Config)
|
||||||
err := ioutil.WriteFile(path, jsonString, os.ModePerm)
|
err := ioutil.WriteFile(path, jsonString, os.ModePerm)
|
||||||
if (err != nil) {
|
if err != nil {
|
||||||
log.Fatalf("Cannot save config %s: %s", path, err.Error())
|
log.Fatalf("Cannot save config %s: %s", path, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func homeDir() string {
|
func homeDir() string {
|
||||||
dir, err := homedir.Dir()
|
dir, err := homedir.Dir()
|
||||||
if (err != nil) { panic (err) }
|
if err != nil {
|
||||||
return dir;
|
panic(err)
|
||||||
|
}
|
||||||
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
func configPath() string {
|
func configPath() string {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<main role="main" class="inner DAU">
|
<main role="main" class="inner DAU">
|
||||||
<h1 class="DAU-heading">Config</h1>
|
<h1 class="DAU-heading">Config</h1>
|
||||||
<p class="lead">Discord-auto-upload configuration</p>
|
<p class="lead">Discord-auto-upload configuration</p>
|
||||||
|
<a href="https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks"><p class="lead">How to find your discord webhook</p></a>
|
||||||
|
|
||||||
|
|
||||||
<form class="">
|
<form class="">
|
||||||
<div class="form-row align-items-center config-item" data-key="webhook">
|
<div class="form-row align-items-center config-item" data-key="webhook">
|
||||||
@@ -121,10 +123,11 @@ $(document).ready(function() {
|
|||||||
.done(function(data) {
|
.done(function(data) {
|
||||||
var this_el = $(".config-item[data-key='"+key+"']").find('.rest-field');
|
var this_el = $(".config-item[data-key='"+key+"']").find('.rest-field');
|
||||||
if (this_el.hasClass('rest-field-boolean')) {
|
if (this_el.hasClass('rest-field-boolean')) {
|
||||||
this_el.prop('checked', data.Value);
|
this_el.prop('checked', data.value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this_el.val(data.Value);
|
|
||||||
|
this_el.val(data.value);
|
||||||
}
|
}
|
||||||
update_sadness();
|
update_sadness();
|
||||||
|
|
||||||
@@ -140,10 +143,10 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
$.post('/rest/config/'+key, { value: val })
|
$.post('/rest/config/'+key, { value: val })
|
||||||
.done(function(d) {
|
.done(function(d) {
|
||||||
if (d.Success) {
|
if (d.success) {
|
||||||
alert('Updated config');
|
alert('Updated config');
|
||||||
} else {
|
} else {
|
||||||
alert("Error: " + d.Error);
|
alert("Error: " + d.error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ body {
|
|||||||
max-width: 42em;
|
max-width: 42em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: black;
|
||||||
|
color: aliceblue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Header
|
* Header
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
<h1 class="DAU-heading">Discord Auto Upload</h1>
|
<h1 class="DAU-heading">Discord Auto Upload</h1>
|
||||||
<p class="lead">Hey look, it's DAU :-)</p>
|
<p class="lead">Hey look, it's DAU :-)</p>
|
||||||
<p class="lead">
|
<p class="lead">
|
||||||
<a href="https://github.com/tardisx/discord-auto-upload" class="btn btn-lg btn-secondary">Learn more</a>
|
<a href="https://github.com/tardisx/discord-auto-upload" class="btn btn-lg btn-secondary" target="_blank">Learn more</a>
|
||||||
</p>
|
</p>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
53
data/logs.html
Normal file
53
data/logs.html
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
<main role="main" class="inner DAU">
|
||||||
|
<h1 class="DAU-heading">Logs</h1>
|
||||||
|
<p class="lead">Discord-auto-upload logs</p>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">
|
||||||
|
<button type="button" onClick="debug=1; get_logs();" class="btn btn-primary">all logs</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm">
|
||||||
|
<button type="button" onClick="debug=0; get_logs();" class="btn btn-primary">no debug</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm">
|
||||||
|
<button type="button" id="scroll-button" onClick="toggle_scroll();" class="btn btn-primary">disable auto-scroll</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre id="logs" class="text-left pre-scrollable">
|
||||||
|
</pre>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var debug = 0;
|
||||||
|
var scrl = true;
|
||||||
|
$(document).ready(function() {
|
||||||
|
get_logs();
|
||||||
|
setInterval(function() { get_logs(); }, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
function toggle_scroll() {
|
||||||
|
scrl = !scrl;
|
||||||
|
if (scrl) {
|
||||||
|
$('#scroll-button').text('disable auto-scroll');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#scroll-button').text('auto-scroll');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_logs() {
|
||||||
|
$.ajax({ method: 'get', url: '/rest/logs', data: { debug : debug }})
|
||||||
|
.done(function(data) {
|
||||||
|
$('#logs').text(data);
|
||||||
|
console.log('scrl is ', scrl);
|
||||||
|
if (scrl) {
|
||||||
|
$('#logs').scrollTop(10000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
39
data/uploads.html
Normal file
39
data/uploads.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<main role="main" class="inner DAU">
|
||||||
|
<h1 class="DAU-heading">Uploads</h1>
|
||||||
|
<p class="lead">Discord-auto-upload uploads</p>
|
||||||
|
|
||||||
|
<table class="table table-condensed table-dark">
|
||||||
|
<thead>
|
||||||
|
<tr><th>uploaded</th><th>dt</th><th>thumb</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="uploads">
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
get_uploads();
|
||||||
|
});
|
||||||
|
|
||||||
|
function get_uploads() {
|
||||||
|
$.ajax({ method: 'get', url: '/rest/uploads'})
|
||||||
|
.done(function(data) {
|
||||||
|
console.log(data);
|
||||||
|
$('#uploads').empty();
|
||||||
|
if (! data) { return }
|
||||||
|
data.forEach(i => {
|
||||||
|
// {uploaded: true, uploaded_at: "2021-06-08T21:59:52.855936+09:30", url: "https://cdn.discordapp.com/attachments/849615269706203171/851800197046468628/dau736004285.png", width: 640, height: 640}
|
||||||
|
console.log(i);
|
||||||
|
row = $('<tr>');
|
||||||
|
row.append($('<td>').text(i.uploaded ? 'yes' : 'no'));
|
||||||
|
row.append($('<td>').text(i.uploaded_at));
|
||||||
|
row.append($('<td>').html($('<img>', { width : i.width/10, height : i.height/10, src : i.url })));
|
||||||
|
$('#uploads').prepend(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -40,6 +40,8 @@
|
|||||||
<nav class="nav nav-masthead justify-content-center">
|
<nav class="nav nav-masthead justify-content-center">
|
||||||
<a class="nav-link {{ if eq .Path "index.html"}} active {{ end }}" href="/">Home</a>
|
<a class="nav-link {{ if eq .Path "index.html"}} active {{ end }}" href="/">Home</a>
|
||||||
<a class="nav-link {{ if eq .Path "config.html"}} active {{ end }}" href="/config.html">Config</a>
|
<a class="nav-link {{ if eq .Path "config.html"}} active {{ end }}" href="/config.html">Config</a>
|
||||||
|
<a class="nav-link {{ if eq .Path "uploads.html"}} active {{ end }}" href="/uploads.html">Uploads</a>
|
||||||
|
<a class="nav-link {{ if eq .Path "logs.html"}} active {{ end }}" href="/logs.html">Logs</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
218
dau.go
218
dau.go
@@ -3,31 +3,27 @@ package main
|
|||||||
//go:generate go-bindata -pkg assets -o assets/static.go -prefix data/ data
|
//go:generate go-bindata -pkg assets -o assets/static.go -prefix data/ data
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"mime/multipart"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"image"
|
|
||||||
|
|
||||||
_ "image/gif"
|
_ "image/gif"
|
||||||
_ "image/jpeg"
|
_ "image/jpeg"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
|
|
||||||
"github.com/fogleman/gg"
|
|
||||||
"github.com/pborman/getopt"
|
"github.com/pborman/getopt"
|
||||||
|
|
||||||
// "github.com/skratchdot/open-golang/open"
|
// "github.com/skratchdot/open-golang/open"
|
||||||
"golang.org/x/image/font/inconsolata"
|
|
||||||
|
|
||||||
"github.com/tardisx/discord-auto-upload/config"
|
"github.com/tardisx/discord-auto-upload/config"
|
||||||
|
daulog "github.com/tardisx/discord-auto-upload/log"
|
||||||
|
"github.com/tardisx/discord-auto-upload/uploads"
|
||||||
"github.com/tardisx/discord-auto-upload/web"
|
"github.com/tardisx/discord-auto-upload/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,11 +36,11 @@ func main() {
|
|||||||
|
|
||||||
// log.Print("Opening web browser")
|
// log.Print("Opening web browser")
|
||||||
// open.Start("http://localhost:9090")
|
// open.Start("http://localhost:9090")
|
||||||
go web.StartWebServer()
|
web.StartWebServer()
|
||||||
|
|
||||||
checkUpdates()
|
checkUpdates()
|
||||||
|
|
||||||
log.Print("Waiting for images to appear in ", config.Config.Path)
|
daulog.SendLog(fmt.Sprintf("Waiting for images to appear in %s", config.Config.Path), daulog.LogTypeInfo)
|
||||||
// wander the path, forever
|
// wander the path, forever
|
||||||
for {
|
for {
|
||||||
if checkPath(config.Config.Path) {
|
if checkPath(config.Config.Path) {
|
||||||
@@ -55,7 +51,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
lastCheck = newLastCheck
|
lastCheck = newLastCheck
|
||||||
}
|
}
|
||||||
log.Printf("sleeping for %ds before next check of %s", config.Config.Watch, config.Config.Path)
|
daulog.SendLog(fmt.Sprintf("sleeping for %ds before next check of %s", config.Config.Watch, config.Config.Path), daulog.LogTypeDebug)
|
||||||
time.Sleep(time.Duration(config.Config.Watch) * time.Second)
|
time.Sleep(time.Duration(config.Config.Watch) * time.Second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,16 +72,18 @@ func checkPath(path string) bool {
|
|||||||
func checkUpdates() {
|
func checkUpdates() {
|
||||||
|
|
||||||
type GithubRelease struct {
|
type GithubRelease struct {
|
||||||
HTMLURL string
|
HTMLURL string `json:"html_url"`
|
||||||
TagName string
|
TagName string `json:"tag_name"`
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Body string
|
Body string `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
daulog.SendLog("checking for new version", daulog.LogTypeInfo)
|
||||||
|
|
||||||
client := &http.Client{Timeout: time.Second * 5}
|
client := &http.Client{Timeout: time.Second * 5}
|
||||||
resp, err := client.Get("https://api.github.com/repos/tardisx/discord-auto-upload/releases/latest")
|
resp, err := client.Get("https://api.github.com/repos/tardisx/discord-auto-upload/releases/latest")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("WARNING: Update check failed: ", err)
|
daulog.SendLog(fmt.Sprintf("WARNING: Update check failed: %v", err), daulog.LogTypeError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -107,6 +105,7 @@ func checkUpdates() {
|
|||||||
fmt.Println(latest.Body)
|
fmt.Println(latest.Body)
|
||||||
fmt.Println("------------------------------------")
|
fmt.Println("------------------------------------")
|
||||||
fmt.Println("Upgrade at https://github.com/tardisx/discord-auto-upload/releases/latest")
|
fmt.Println("Upgrade at https://github.com/tardisx/discord-auto-upload/releases/latest")
|
||||||
|
daulog.SendLog(fmt.Sprintf("New version available: %s - download at https://github.com/tardisx/discord-auto-upload/releases/latest", latest.TagName), daulog.LogTypeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -136,7 +135,6 @@ func parseOptions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkFile(path string, f os.FileInfo, err error) error {
|
func checkFile(path string, f os.FileInfo, err error) error {
|
||||||
|
|
||||||
if f.ModTime().After(lastCheck) && f.Mode().IsRegular() {
|
if f.ModTime().After(lastCheck) && f.Mode().IsRegular() {
|
||||||
|
|
||||||
if fileEligible(path) {
|
if fileEligible(path) {
|
||||||
@@ -168,190 +166,6 @@ func fileEligible(file string) bool {
|
|||||||
|
|
||||||
func processFile(file string) {
|
func processFile(file string) {
|
||||||
|
|
||||||
if !config.Config.NoWatermark {
|
daulog.SendLog("Sending to uploader", daulog.LogTypeInfo)
|
||||||
log.Print("Copying to temp location and watermarking ", file)
|
uploads.AddFile(file)
|
||||||
file = mungeFile(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Config.WebHookURL == "" {
|
|
||||||
log.Print("WebHookURL is not configured - cannot upload!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Uploading ", file)
|
|
||||||
|
|
||||||
extraParams := map[string]string{}
|
|
||||||
|
|
||||||
if config.Config.Username != "" {
|
|
||||||
log.Print("Overriding username with " + config.Config.Username)
|
|
||||||
extraParams["username"] = config.Config.Username
|
|
||||||
}
|
|
||||||
|
|
||||||
type DiscordAPIResponseAttachment struct {
|
|
||||||
URL string
|
|
||||||
ProxyURL string
|
|
||||||
Size int
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
Filename string
|
|
||||||
}
|
|
||||||
|
|
||||||
type DiscordAPIResponse struct {
|
|
||||||
Attachments []DiscordAPIResponseAttachment
|
|
||||||
ID int64 `json:",string"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var retriesRemaining = 5
|
|
||||||
for retriesRemaining > 0 {
|
|
||||||
|
|
||||||
request, err := newfileUploadRequest(config.Config.WebHookURL, extraParams, "file", file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
start := time.Now()
|
|
||||||
client := &http.Client{Timeout: time.Second * 30}
|
|
||||||
resp, err := client.Do(request)
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Error performing request:", err)
|
|
||||||
retriesRemaining--
|
|
||||||
sleepForRetries(retriesRemaining)
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
log.Print("Bad response from server:", resp.StatusCode)
|
|
||||||
if b, err := ioutil.ReadAll(resp.Body); err == nil {
|
|
||||||
log.Print("Body:", string(b))
|
|
||||||
}
|
|
||||||
retriesRemaining--
|
|
||||||
sleepForRetries(retriesRemaining)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resBody, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Print("could not deal with body: ", err)
|
|
||||||
retriesRemaining--
|
|
||||||
sleepForRetries(retriesRemaining)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
var res DiscordAPIResponse
|
|
||||||
err = json.Unmarshal(resBody, &res)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Print("could not parse JSON: ", err)
|
|
||||||
fmt.Println("Response was:", string(resBody[:]))
|
|
||||||
retriesRemaining--
|
|
||||||
sleepForRetries(retriesRemaining)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(res.Attachments) < 1 {
|
|
||||||
log.Print("bad response - no attachments?")
|
|
||||||
retriesRemaining--
|
|
||||||
sleepForRetries(retriesRemaining)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var a = res.Attachments[0]
|
|
||||||
elapsed := time.Since(start)
|
|
||||||
rate := float64(a.Size) / elapsed.Seconds() / 1024.0
|
|
||||||
|
|
||||||
log.Printf("Uploaded to %s %dx%d", a.URL, a.Width, a.Height)
|
|
||||||
log.Printf("id: %d, %d bytes transferred in %.2f seconds (%.2f KiB/s)", res.ID, a.Size, elapsed.Seconds(), rate)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !config.Config.NoWatermark {
|
|
||||||
log.Print("Removing temporary file ", file)
|
|
||||||
os.Remove(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
if retriesRemaining == 0 {
|
|
||||||
log.Fatal("Failed to upload, even after retries")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func sleepForRetries(retry int) {
|
|
||||||
if retry == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
retryTime := (6-retry)*(6-retry) + 6
|
|
||||||
log.Printf("Will retry in %d seconds (%d remaining attempts)", retryTime, retry)
|
|
||||||
time.Sleep(time.Duration(retryTime) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
body := &bytes.Buffer{}
|
|
||||||
writer := multipart.NewWriter(body)
|
|
||||||
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = io.Copy(part, file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Could not copy: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, val := range params {
|
|
||||||
_ = writer.WriteField(key, val)
|
|
||||||
}
|
|
||||||
err = writer.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", uri, body)
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
||||||
return req, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func mungeFile(path string) string {
|
|
||||||
|
|
||||||
reader, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer reader.Close()
|
|
||||||
|
|
||||||
im, _, err := image.Decode(reader)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
bounds := im.Bounds()
|
|
||||||
// var S float64 = float64(bounds.Max.X)
|
|
||||||
|
|
||||||
dc := gg.NewContext(bounds.Max.X, bounds.Max.Y)
|
|
||||||
dc.Clear()
|
|
||||||
dc.SetRGB(0, 0, 0)
|
|
||||||
|
|
||||||
dc.SetFontFace(inconsolata.Regular8x16)
|
|
||||||
|
|
||||||
dc.DrawImage(im, 0, 0)
|
|
||||||
|
|
||||||
dc.DrawRoundedRectangle(0, float64(bounds.Max.Y-18.0), 320, float64(bounds.Max.Y), 0)
|
|
||||||
dc.SetRGB(0, 0, 0)
|
|
||||||
dc.Fill()
|
|
||||||
|
|
||||||
dc.SetRGB(1, 1, 1)
|
|
||||||
|
|
||||||
dc.DrawString("github.com/tardisx/discord-auto-upload", 5.0, float64(bounds.Max.Y)-5.0)
|
|
||||||
|
|
||||||
tempfile, err := ioutil.TempFile("", "dau")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
tempfile.Close()
|
|
||||||
os.Remove(tempfile.Name())
|
|
||||||
actualName := tempfile.Name() + ".png"
|
|
||||||
|
|
||||||
dc.SavePNG(actualName)
|
|
||||||
return actualName
|
|
||||||
}
|
}
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -7,6 +7,5 @@ require (
|
|||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/pborman/getopt v1.1.0
|
github.com/pborman/getopt v1.1.0
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e
|
||||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6
|
|
||||||
)
|
)
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -6,8 +6,6 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
|
|||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
|
github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
|
||||||
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e h1:PzJMNfFQx+QO9hrC1GwZ4BoPGeNGhfeQEgcQFArEjPk=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
|
|
||||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|||||||
45
log/log.go
Normal file
45
log/log.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogEntryType string
|
||||||
|
|
||||||
|
type LogEntry struct {
|
||||||
|
Timestamp time.Time `json:"ts"`
|
||||||
|
Type LogEntryType `json:"type"`
|
||||||
|
Entry string `json:"log"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
LogTypeInfo = "info"
|
||||||
|
LogTypeError = "error"
|
||||||
|
LogTypeDebug = "debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
var LogEntries []LogEntry
|
||||||
|
var logInput chan LogEntry
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// wait for log entries
|
||||||
|
logInput = make(chan LogEntry)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
aLog := <-logInput
|
||||||
|
LogEntries = append(LogEntries, aLog)
|
||||||
|
for len(LogEntries) > 100 {
|
||||||
|
LogEntries = LogEntries[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendLog(entry string, entryType LogEntryType) {
|
||||||
|
|
||||||
|
logInput <- LogEntry{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Entry: entry,
|
||||||
|
Type: entryType,
|
||||||
|
}
|
||||||
|
}
|
||||||
249
uploads/uploads.go
Normal file
249
uploads/uploads.go
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
// The uploads pacakge encapsulates dealing with file uploads to
|
||||||
|
// discord
|
||||||
|
package uploads
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fogleman/gg"
|
||||||
|
"github.com/tardisx/discord-auto-upload/config"
|
||||||
|
daulog "github.com/tardisx/discord-auto-upload/log"
|
||||||
|
"golang.org/x/image/font/inconsolata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Upload struct {
|
||||||
|
Uploaded bool `json:"uploaded"` // has this file been uploaded to discord
|
||||||
|
UploadedAt time.Time `json:"uploaded_at"`
|
||||||
|
originalFilename string // path on the local disk
|
||||||
|
mungedFilename string // post-watermark
|
||||||
|
Url string `json:"url"` // url on the discord CDN
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var Uploads []*Upload
|
||||||
|
|
||||||
|
func AddFile(file string) {
|
||||||
|
thisUpload := Upload{
|
||||||
|
Uploaded: false,
|
||||||
|
originalFilename: file,
|
||||||
|
}
|
||||||
|
Uploads = append(Uploads, &thisUpload)
|
||||||
|
|
||||||
|
ProcessUpload(&thisUpload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessUpload(up *Upload) {
|
||||||
|
|
||||||
|
file := up.originalFilename
|
||||||
|
|
||||||
|
if !config.Config.NoWatermark {
|
||||||
|
daulog.SendLog("Copying to temp location and watermarking ", daulog.LogTypeInfo)
|
||||||
|
file = mungeFile(file)
|
||||||
|
up.mungedFilename = file
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Config.WebHookURL == "" {
|
||||||
|
daulog.SendLog("WebHookURL is not configured - cannot upload!", daulog.LogTypeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
extraParams := map[string]string{}
|
||||||
|
|
||||||
|
if config.Config.Username != "" {
|
||||||
|
daulog.SendLog("Overriding username with "+config.Config.Username, daulog.LogTypeInfo)
|
||||||
|
extraParams["username"] = config.Config.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiscordAPIResponseAttachment struct {
|
||||||
|
URL string
|
||||||
|
ProxyURL string
|
||||||
|
Size int
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
Filename string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiscordAPIResponse struct {
|
||||||
|
Attachments []DiscordAPIResponseAttachment
|
||||||
|
ID int64 `json:",string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var retriesRemaining = 5
|
||||||
|
for retriesRemaining > 0 {
|
||||||
|
|
||||||
|
request, err := newfileUploadRequest(config.Config.WebHookURL, extraParams, "file", file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
start := time.Now()
|
||||||
|
client := &http.Client{Timeout: time.Second * 30}
|
||||||
|
resp, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("Error performing request:", err)
|
||||||
|
retriesRemaining--
|
||||||
|
sleepForRetries(retriesRemaining)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
// {"message": "Request entity too large", "code": 40005}
|
||||||
|
log.Print("Bad response from server:", resp.StatusCode)
|
||||||
|
if b, err := ioutil.ReadAll(resp.Body); err == nil {
|
||||||
|
log.Print("Body:", string(b))
|
||||||
|
daulog.SendLog(fmt.Sprintf("Bad response: %s", string(b)), daulog.LogTypeError)
|
||||||
|
}
|
||||||
|
retriesRemaining--
|
||||||
|
sleepForRetries(retriesRemaining)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("could not deal with body: ", err)
|
||||||
|
retriesRemaining--
|
||||||
|
sleepForRetries(retriesRemaining)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
var res DiscordAPIResponse
|
||||||
|
err = json.Unmarshal(resBody, &res)
|
||||||
|
|
||||||
|
// {"id": "851092588608880670", "type": 0, "content": "", "channel_id": "849615269706203171", "author": {"bot": true, "id": "849615314274484224", "username": "abcdedf", "avatar": null, "discriminator": "0000"}, "attachments": [{"id": "851092588332449812", "filename": "dau480457962.png", "size": 859505, "url": "https://cdn.discordapp.com/attachments/849615269706203171/851092588332449812/dau480457962.png", "proxy_url": "https://media.discordapp.net/attachments/849615269706203171/851092588332449812/dau480457962.png", "width": 640, "height": 640, "content_type": "image/png"}], "embeds": [], "mentions": [], "mention_roles": [], "pinned": false, "mention_everyone": false, "tts": false, "timestamp": "2021-06-06T13:38:05.660000+00:00", "edited_timestamp": null, "flags": 0, "components": [], "webhook_id": "849615314274484224"}
|
||||||
|
|
||||||
|
daulog.SendLog(fmt.Sprintf("Response: %s", string(resBody[:])), daulog.LogTypeDebug)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Print("could not parse JSON: ", err)
|
||||||
|
fmt.Println("Response was:", string(resBody[:]))
|
||||||
|
retriesRemaining--
|
||||||
|
sleepForRetries(retriesRemaining)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(res.Attachments) < 1 {
|
||||||
|
log.Print("bad response - no attachments?")
|
||||||
|
retriesRemaining--
|
||||||
|
sleepForRetries(retriesRemaining)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var a = res.Attachments[0]
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
rate := float64(a.Size) / elapsed.Seconds() / 1024.0
|
||||||
|
|
||||||
|
daulog.SendLog(fmt.Sprintf("Uploaded to %s %dx%d", a.URL, a.Width, a.Height), daulog.LogTypeInfo)
|
||||||
|
daulog.SendLog(fmt.Sprintf("id: %d, %d bytes transferred in %.2f seconds (%.2f KiB/s)", res.ID, a.Size, elapsed.Seconds(), rate), daulog.LogTypeInfo)
|
||||||
|
|
||||||
|
up.Url = a.URL
|
||||||
|
up.Uploaded = true
|
||||||
|
up.Width = a.Width
|
||||||
|
up.Height = a.Height
|
||||||
|
up.UploadedAt = time.Now()
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.Config.NoWatermark {
|
||||||
|
daulog.SendLog(fmt.Sprintf("Removing temporary file: %s", file), daulog.LogTypeDebug)
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
if retriesRemaining == 0 {
|
||||||
|
log.Fatal("Failed to upload, even after retries")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(part, file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Could not copy: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, val := range params {
|
||||||
|
_ = writer.WriteField(key, val)
|
||||||
|
}
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", uri, body)
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func mungeFile(path string) string {
|
||||||
|
|
||||||
|
reader, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
im, _, err := image.Decode(reader)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
bounds := im.Bounds()
|
||||||
|
// var S float64 = float64(bounds.Max.X)
|
||||||
|
|
||||||
|
dc := gg.NewContext(bounds.Max.X, bounds.Max.Y)
|
||||||
|
dc.Clear()
|
||||||
|
dc.SetRGB(0, 0, 0)
|
||||||
|
|
||||||
|
dc.SetFontFace(inconsolata.Regular8x16)
|
||||||
|
|
||||||
|
dc.DrawImage(im, 0, 0)
|
||||||
|
|
||||||
|
dc.DrawRoundedRectangle(0, float64(bounds.Max.Y-18.0), 320, float64(bounds.Max.Y), 0)
|
||||||
|
dc.SetRGB(0, 0, 0)
|
||||||
|
dc.Fill()
|
||||||
|
|
||||||
|
dc.SetRGB(1, 1, 1)
|
||||||
|
|
||||||
|
dc.DrawString("github.com/tardisx/discord-auto-upload", 5.0, float64(bounds.Max.Y)-5.0)
|
||||||
|
|
||||||
|
tempfile, err := ioutil.TempFile("", "dau")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
tempfile.Close()
|
||||||
|
os.Remove(tempfile.Name())
|
||||||
|
actualName := tempfile.Name() + ".png"
|
||||||
|
|
||||||
|
dc.SavePNG(actualName)
|
||||||
|
return actualName
|
||||||
|
}
|
||||||
|
|
||||||
|
func sleepForRetries(retry int) {
|
||||||
|
if retry == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
retryTime := (6-retry)*(6-retry) + 6
|
||||||
|
daulog.SendLog(fmt.Sprintf("Will retry in %d seconds (%d remaining attempts)", retryTime, retry), daulog.LogTypeError)
|
||||||
|
time.Sleep(time.Duration(retryTime) * time.Second)
|
||||||
|
}
|
||||||
@@ -3,8 +3,6 @@ package web
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/tardisx/discord-auto-upload/assets"
|
|
||||||
"github.com/tardisx/discord-auto-upload/config"
|
|
||||||
"log"
|
"log"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -13,6 +11,11 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/tardisx/discord-auto-upload/assets"
|
||||||
|
"github.com/tardisx/discord-auto-upload/config"
|
||||||
|
daulog "github.com/tardisx/discord-auto-upload/log"
|
||||||
|
"github.com/tardisx/discord-auto-upload/uploads"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DAUWebServer - stuff for the web server
|
// DAUWebServer - stuff for the web server
|
||||||
@@ -21,23 +24,22 @@ type DAUWebServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type valueStringResponse struct {
|
type valueStringResponse struct {
|
||||||
Success bool `json: 'success'`
|
Success bool `json:"success"`
|
||||||
Value string `json: 'value'`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type valueBooleanResponse struct {
|
type valueBooleanResponse struct {
|
||||||
Success bool `json: 'success'`
|
Success bool `json:"success"`
|
||||||
Value bool `json: 'value'`
|
Value bool `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type errorResponse struct {
|
type errorResponse struct {
|
||||||
Success bool `json: 'success'`
|
Success bool `json:"success"`
|
||||||
Error string `json: 'error'`
|
Error string `json:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStatic(w http.ResponseWriter, r *http.Request) {
|
func getStatic(w http.ResponseWriter, r *http.Request) {
|
||||||
// haha this is dumb and I should change it
|
// haha this is dumb and I should change it
|
||||||
// fmt.Println(r.URL)
|
|
||||||
re := regexp.MustCompile(`[^a-zA-Z0-9\.]`)
|
re := regexp.MustCompile(`[^a-zA-Z0-9\.]`)
|
||||||
path := r.URL.Path[1:]
|
path := r.URL.Path[1:]
|
||||||
sanitized_path := re.ReplaceAll([]byte(path), []byte("_"))
|
sanitized_path := re.ReplaceAll([]byte(path), []byte("_"))
|
||||||
@@ -270,8 +272,38 @@ func getSetExclude(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLogs(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
|
showDebug := false
|
||||||
|
debug, present := r.URL.Query()["debug"]
|
||||||
|
if present && len(debug[0]) > 0 && debug[0] != "0" {
|
||||||
|
showDebug = true
|
||||||
|
}
|
||||||
|
|
||||||
|
text := ""
|
||||||
|
for _, log := range daulog.LogEntries {
|
||||||
|
if !showDebug && log.Type == daulog.LogTypeDebug {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
text = text + fmt.Sprintf(
|
||||||
|
"%-6s %-19s %s\n", log.Type, log.Timestamp.Format("2006-01-02 15:04:05"), log.Entry,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// js, _ := json.Marshal(daulog.LogEntries)
|
||||||
|
w.Write([]byte(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUploads(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
ups := uploads.Uploads
|
||||||
|
text, _ := json.Marshal(ups)
|
||||||
|
w.Write([]byte(text))
|
||||||
|
}
|
||||||
|
|
||||||
func StartWebServer() {
|
func StartWebServer() {
|
||||||
|
|
||||||
http.HandleFunc("/", getStatic)
|
http.HandleFunc("/", getStatic)
|
||||||
http.HandleFunc("/rest/config/webhook", getSetWebhook)
|
http.HandleFunc("/rest/config/webhook", getSetWebhook)
|
||||||
http.HandleFunc("/rest/config/username", getSetUsername)
|
http.HandleFunc("/rest/config/username", getSetUsername)
|
||||||
@@ -280,11 +312,14 @@ func StartWebServer() {
|
|||||||
http.HandleFunc("/rest/config/directory", getSetDirectory)
|
http.HandleFunc("/rest/config/directory", getSetDirectory)
|
||||||
http.HandleFunc("/rest/config/exclude", getSetExclude)
|
http.HandleFunc("/rest/config/exclude", getSetExclude)
|
||||||
|
|
||||||
|
http.HandleFunc("/rest/logs", getLogs)
|
||||||
|
http.HandleFunc("/rest/uploads", getUploads)
|
||||||
|
|
||||||
|
go func() {
|
||||||
log.Print("Starting web server on http://localhost:9090")
|
log.Print("Starting web server on http://localhost:9090")
|
||||||
err := http.ListenAndServe(":9090", nil) // set listen port
|
err := http.ListenAndServe(":9090", nil) // set listen port
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("ListenAndServe: ", err)
|
log.Fatal("ListenAndServe: ", err)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user