Big wumbo jumbo update
This commit is contained in:
commit
a652a6c3d3
|
@ -47,3 +47,5 @@ tags
|
||||||
|
|
||||||
# channel and emote list from twitch
|
# channel and emote list from twitch
|
||||||
subscribers.json
|
subscribers.json
|
||||||
|
/.settings/
|
||||||
|
/.project
|
||||||
|
|
47
Makefile
47
Makefile
|
@ -5,52 +5,11 @@
|
||||||
# For info on installing extra versions, see this page:
|
# For info on installing extra versions, see this page:
|
||||||
# https://golang.org/doc/install#extra_versions
|
# https://golang.org/doc/install#extra_versions
|
||||||
|
|
||||||
TAGS=
|
# goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows"
|
||||||
|
# goarchList = "386 amd64 amd64p32 arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32leppc s390 s390x sparc sparc64"
|
||||||
|
include make/Makefile.common
|
||||||
|
|
||||||
# Windows needs the .exe extension.
|
# Windows needs the .exe extension.
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
EXT=.exe
|
EXT=.exe
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: fmt vet get clean dev setdev test ServerMovieNight
|
|
||||||
|
|
||||||
all: fmt vet test MovieNight$(EXT) static/main.wasm settings.json
|
|
||||||
|
|
||||||
# Build the server deployment
|
|
||||||
server: ServerMovieNight static/main.wasm
|
|
||||||
|
|
||||||
# Bulid used for deploying to my server.
|
|
||||||
ServerMovieNight: *.go common/*.go
|
|
||||||
GOOS=linux GOARCH=386 go$(GO_VERSION) build -o MovieNight $(TAGS)
|
|
||||||
|
|
||||||
setdev:
|
|
||||||
$(eval export TAGS=-tags "dev")
|
|
||||||
|
|
||||||
dev: setdev all
|
|
||||||
|
|
||||||
MovieNight$(EXT): *.go common/*.go
|
|
||||||
go$(GO_VERSION) build -o $@ $(TAGS)
|
|
||||||
|
|
||||||
static/js/wasm_exec.js:
|
|
||||||
cp $$(go env GOROOT)/misc/wasm/wasm_exec.js $@
|
|
||||||
|
|
||||||
static/main.wasm: static/js/wasm_exec.js wasm/*.go common/*.go
|
|
||||||
GOOS=js GOARCH=wasm go$(GO_VERSION) build -o $@ $(TAGS) wasm/*.go
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm MovieNight$(EXT) ./static/main.wasm ./static/js/wasm_exec.js
|
|
||||||
|
|
||||||
fmt:
|
|
||||||
gofmt -w .
|
|
||||||
|
|
||||||
vet:
|
|
||||||
go$(GO_VERSION) vet $(TAGS) ./...
|
|
||||||
GOOS=js GOARCH=wasm go$(GO_VERSION) vet $(TAGS) ./...
|
|
||||||
|
|
||||||
test:
|
|
||||||
go$(GO_VERSION) test $(TAGS) ./...
|
|
||||||
|
|
||||||
# Do not put settings_example.json here as a prereq to avoid overwriting
|
|
||||||
# the settings if the example is updated.
|
|
||||||
settings.json:
|
|
||||||
cp settings_example.json settings.json
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
# If a different version of Go is installed (via `go get`) set the GO_VERSION
|
||||||
|
# environment variable to that version. For example, setting it to "1.13.7"
|
||||||
|
# will run `go1.13.7 build [...]` instead of `go build [...]`.
|
||||||
|
#
|
||||||
|
# For info on installing extra versions, see this page:
|
||||||
|
# https://golang.org/doc/install#extra_versions
|
||||||
|
|
||||||
|
# goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows"
|
||||||
|
# goarchList = "386 amd64 amd64p32 arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32leppc s390 s390x sparc sparc64"
|
||||||
|
include make/Makefile.common
|
||||||
|
|
||||||
|
GOOS=freebsd
|
|
@ -1,10 +1,12 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DataInterface interface {
|
type DataInterface interface {
|
||||||
|
@ -89,38 +91,51 @@ type DataMessage struct {
|
||||||
Type MessageType
|
Type MessageType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
cmdme = template.Must(template.New("cmdme").Parse(`<span style="color:{{.Color}}"><span class="name">{{.From}}</span> <span class="cmdme">{{.Message}}</span></span>`))
|
||||||
|
announcement = template.Must(template.New("announcement").Parse(`<span class="announcement">{{.Message}}</span>`))
|
||||||
|
errormsg = template.Must(template.New("error").Parse(`<span class="error">{{.Message}}</span>`))
|
||||||
|
notice = template.Must(template.New("notice").Parse(`<span class="notice">{{.Message}}</span>`))
|
||||||
|
command = template.Must(template.New("command").Parse(`<span class="command">{{.Message}}</span>`))
|
||||||
|
commanderror = template.Must(template.New("commanderror").Parse(`<span class="commanderror">{{.Message}}</span>`))
|
||||||
|
cmdlMod = template.Must(template.New("cmdlMod").Parse(`<span><img src="/static/img/mod.png" class="badge" /><span class="name" style="color:{{.Color}}">{{.From}}</span><b>:</b> <span class="msg">{{.Message}}</span></span>`))
|
||||||
|
cmdlAdmin = template.Must(template.New("CmdlAdmin").Parse(`<span><img src="/static/img/admin.png" class="badge" /><span class="name" style="color:{{.Color}}">{{.From}}</span><b>:</b> <span class="msg">{{.Message}}</span></span>`))
|
||||||
|
defaultMsg = template.Must(template.New("defaultMsg").Parse(`<span><span class="name" style="color:{{.Color}}">{{.From}}</span><b>:</b> <span class="msg">{{.Message}}</span></span>`))
|
||||||
|
)
|
||||||
|
|
||||||
// TODO: Read this HTML from a template somewhere
|
// TODO: Read this HTML from a template somewhere
|
||||||
func (dc DataMessage) HTML() string {
|
func (dc DataMessage) HTML() string {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
switch dc.Type {
|
switch dc.Type {
|
||||||
case MsgAction:
|
case MsgAction:
|
||||||
return `<span style="color:` + dc.Color + `"><span class="name">` + dc.From +
|
cmdme.Execute(buf, dc)
|
||||||
`</span> <span class="cmdme">` + dc.Message + `</span></span>`
|
return buf.String()
|
||||||
|
|
||||||
case MsgServer:
|
case MsgServer:
|
||||||
return `<span class="announcement">` + dc.Message + `</span>`
|
announcement.Execute(buf, dc)
|
||||||
|
return buf.String()
|
||||||
case MsgError:
|
case MsgError:
|
||||||
return `<span class="error">` + dc.Message + `</span>`
|
errormsg.Execute(buf, dc)
|
||||||
|
return buf.String()
|
||||||
case MsgNotice:
|
case MsgNotice:
|
||||||
return `<span class="notice">` + dc.Message + `</span>`
|
notice.Execute(buf, dc)
|
||||||
|
return buf.String()
|
||||||
case MsgCommandResponse:
|
case MsgCommandResponse:
|
||||||
return `<span class="command">` + dc.Message + `</span>`
|
command.Execute(buf, dc)
|
||||||
|
return buf.String()
|
||||||
case MsgCommandError:
|
case MsgCommandError:
|
||||||
return `<span class="commanderror">` + dc.Message + `</span>`
|
commanderror.Execute(buf, dc)
|
||||||
|
return buf.String()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
badge := ""
|
|
||||||
switch dc.Level {
|
switch dc.Level {
|
||||||
case CmdlMod:
|
case CmdlMod:
|
||||||
badge = `<img src="/static/img/mod.png" class="badge" />`
|
cmdlMod.Execute(buf, dc)
|
||||||
case CmdlAdmin:
|
case CmdlAdmin:
|
||||||
badge = `<img src="/static/img/admin.png" class="badge" />`
|
cmdlAdmin.Execute(buf, dc)
|
||||||
|
default:
|
||||||
|
defaultMsg.Execute(buf, dc)
|
||||||
}
|
}
|
||||||
return `<span>` + badge + `<span class="name" style="color:` + dc.Color + `">` + dc.From +
|
return buf.String()
|
||||||
`</span><b>:</b> <span class="msg">` + dc.Message + `</span></span>`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,42 +180,51 @@ type DataEvent struct {
|
||||||
Event EventType
|
Event EventType
|
||||||
User string
|
User string
|
||||||
Color string
|
Color string
|
||||||
|
Users []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
evKick = template.Must(template.New("evKick").Parse(`<span class="event"><span class="name" style="color:{{.Color}}">{{.User}}</span> has been kicked.</span>`))
|
||||||
|
evLeave = template.Must(template.New("evLeave").Parse(`<span class="event"><span class="name" style="color:{{.Color}}">{{.User}}</span> has left the chat.</span>`))
|
||||||
|
evBan = template.Must(template.New("evBan").Parse(`<span class="event"><span class="name" style="color:{{.Color}}">{{.User}}</span> has been banned.</span>`))
|
||||||
|
evJoin = template.Must(template.New("evJoin").Parse(`<span class="event"><span class="name" style="color:{{.Color}}">{{.User}}</span> has joined the chat.</span>`))
|
||||||
|
evNameChangeWC = template.Must(template.New("evNameChangeWC").Parse(`<span class="event">Somebody changed their name, but IDK who {{.}}.</span>`))
|
||||||
|
evNameChange = template.Must(template.New("evNameChange").Parse(`<span class="event"><span class="name" style="color:{{.Color}}">{{index .Users 0}}</span> has changed their name to <span class="name" style="color:{{.Color}}">{{index .Users 1}}</span>.</span>`))
|
||||||
|
evNameChangeForced = template.Must(template.New("evNameChangeForced").Parse(`<span class="event"><span class="name" style="color:{{.Color}}">{{index .Users 0}}</span> has had their name changed to <span class="name" style="color:{{.Color}}">{{index .Users 1}}</span> by an admin.</span>`))
|
||||||
|
evNameChangeForcedWC = template.Must(template.New("evNameChangeForcedWC").Parse(`<span class="event">An admin changed somebody's name, but IDK who {{.}}.</span>`))
|
||||||
|
)
|
||||||
|
|
||||||
func (de DataEvent) HTML() string {
|
func (de DataEvent) HTML() string {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
switch de.Event {
|
switch de.Event {
|
||||||
case EvKick:
|
case EvKick:
|
||||||
return `<span class="event"><span class="name" style="color:` + de.Color + `">` +
|
evKick.Execute(buf, de)
|
||||||
de.User + `</span> has been kicked.</span>`
|
return buf.String()
|
||||||
case EvLeave:
|
case EvLeave:
|
||||||
return `<span class="event"><span class="name" style="color:` + de.Color + `">` +
|
evLeave.Execute(buf, de)
|
||||||
de.User + `</span> has left the chat.</span>`
|
return buf.String()
|
||||||
case EvBan:
|
case EvBan:
|
||||||
return `<span class="event"><span class="name" style="color:` + de.Color + `">` +
|
evBan.Execute(buf, de)
|
||||||
de.User + `</span> has been banned.</span>`
|
return buf.String()
|
||||||
case EvJoin:
|
case EvJoin:
|
||||||
return `<span class="event"><span class="name" style="color:` + de.Color + `">` +
|
evJoin.Execute(buf, de)
|
||||||
de.User + `</span> has joined the chat.</span>`
|
return buf.String()
|
||||||
case EvNameChange:
|
case EvNameChange:
|
||||||
names := strings.Split(de.User, ":")
|
de.Users = strings.Split(de.User, ":")
|
||||||
if len(names) != 2 {
|
if len(de.Users) < 2 {
|
||||||
return `<span class="event">Somebody changed their name, but IDK who ` +
|
evNameChangeWC.Execute(buf, ParseEmotes("Jebaited"))
|
||||||
ParseEmotes("Jebaited") + `.</span>`
|
} else {
|
||||||
|
evNameChange.Execute(buf, de)
|
||||||
}
|
}
|
||||||
|
return buf.String()
|
||||||
return `<span class="event"><span class="name" style="color:` + de.Color + `">` +
|
|
||||||
names[0] + `</span> has changed their name to <span class="name" style="color:` +
|
|
||||||
de.Color + `">` + names[1] + `</span>.</span>`
|
|
||||||
case EvNameChangeForced:
|
case EvNameChangeForced:
|
||||||
names := strings.Split(de.User, ":")
|
de.Users = strings.Split(de.User, ":")
|
||||||
if len(names) != 2 {
|
if len(de.Users) < 2 {
|
||||||
return `<span class="event">An admin changed somebody's name, but IDK who ` +
|
evNameChangeForcedWC.Execute(buf, ParseEmotes("Jebaited"))
|
||||||
ParseEmotes("Jebaited") + `.</span>`
|
} else {
|
||||||
|
evNameChangeForced.Execute(buf, de)
|
||||||
}
|
}
|
||||||
|
return buf.String()
|
||||||
return `<span class="event"><span class="name" style="color:` + de.Color + `">` +
|
|
||||||
names[0] + `</span> has had their name changed to <span class="name" style="color:` +
|
|
||||||
de.Color + `">` + names[1] + `</span> by an admin.</span>`
|
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (em EmotesMap) Add(fullpath string) EmotesMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
func EmoteToHtml(file, title string) string {
|
func EmoteToHtml(file, title string) string {
|
||||||
return fmt.Sprintf(`<img src="%s" height="28px" title="%s" />`, file, title)
|
return fmt.Sprintf(`<img src="%s" class="emote" title="%s" />`, file, title)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used with a regexp.ReplaceAllStringFunc() call. Needs to lookup the value as it
|
// Used with a regexp.ReplaceAllStringFunc() call. Needs to lookup the value as it
|
||||||
|
@ -56,7 +56,7 @@ func EmoteToHtml(file, title string) string {
|
||||||
func emoteToHmtl2(key string) string {
|
func emoteToHmtl2(key string) string {
|
||||||
key = strings.Trim(key, ":[]")
|
key = strings.Trim(key, ":[]")
|
||||||
if val, ok := Emotes[key]; ok {
|
if val, ok := Emotes[key]; ok {
|
||||||
return fmt.Sprintf(`<img src="%s" height="28px" title="%s" />`, val, key)
|
return fmt.Sprintf(`<img src="%s" class="emote" title="%s" />`, val, key)
|
||||||
}
|
}
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,31 +6,31 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var data_good = map[string]string{
|
var data_good = map[string]string{
|
||||||
"one": `<img src="/emotes/one.png" height="28px" title="one" />`,
|
"one": `<img src="/emotes/one.png" class="emote" title="one" />`,
|
||||||
"two": `<img src="/emotes/two.png" height="28px" title="two" />`,
|
"two": `<img src="/emotes/two.png" class="emote" title="two" />`,
|
||||||
"three": `<img src="/emotes/three.gif" height="28px" title="three" />`,
|
"three": `<img src="/emotes/three.gif" class="emote" title="three" />`,
|
||||||
|
|
||||||
":one:": `<img src="/emotes/one.png" height="28px" title="one" />`,
|
":one:": `<img src="/emotes/one.png" class="emote" title="one" />`,
|
||||||
":two:": `<img src="/emotes/two.png" height="28px" title="two" />`,
|
":two:": `<img src="/emotes/two.png" class="emote" title="two" />`,
|
||||||
":three:": `<img src="/emotes/three.gif" height="28px" title="three" />`,
|
":three:": `<img src="/emotes/three.gif" class="emote" title="three" />`,
|
||||||
|
|
||||||
":one::one:": `<img src="/emotes/one.png" height="28px" title="one" /><img src="/emotes/one.png" height="28px" title="one" />`,
|
":one::one:": `<img src="/emotes/one.png" class="emote" title="one" /><img src="/emotes/one.png" class="emote" title="one" />`,
|
||||||
":one:one:": `<img src="/emotes/one.png" height="28px" title="one" />one:`,
|
":one:one:": `<img src="/emotes/one.png" class="emote" title="one" />one:`,
|
||||||
"oneone": "oneone",
|
"oneone": "oneone",
|
||||||
"one:one:": `one<img src="/emotes/one.png" height="28px" title="one" />`,
|
"one:one:": `one<img src="/emotes/one.png" class="emote" title="one" />`,
|
||||||
|
|
||||||
"[one]": `<img src="/emotes/one.png" height="28px" title="one" />`,
|
"[one]": `<img src="/emotes/one.png" class="emote" title="one" />`,
|
||||||
"[two]": `<img src="/emotes/two.png" height="28px" title="two" />`,
|
"[two]": `<img src="/emotes/two.png" class="emote" title="two" />`,
|
||||||
"[three]": `<img src="/emotes/three.gif" height="28px" title="three" />`,
|
"[three]": `<img src="/emotes/three.gif" class="emote" title="three" />`,
|
||||||
|
|
||||||
"[one][one]": `<img src="/emotes/one.png" height="28px" title="one" /><img src="/emotes/one.png" height="28px" title="one" />`,
|
"[one][one]": `<img src="/emotes/one.png" class="emote" title="one" /><img src="/emotes/one.png" class="emote" title="one" />`,
|
||||||
"[one]one": `<img src="/emotes/one.png" height="28px" title="one" />one`,
|
"[one]one": `<img src="/emotes/one.png" class="emote" title="one" />one`,
|
||||||
|
|
||||||
":one: two [three]": `<img src="/emotes/one.png" height="28px" title="one" /> <img src="/emotes/two.png" height="28px" title="two" /> <img src="/emotes/three.gif" height="28px" title="three" />`,
|
":one: two [three]": `<img src="/emotes/one.png" class="emote" title="one" /> <img src="/emotes/two.png" class="emote" title="two" /> <img src="/emotes/three.gif" class="emote" title="three" />`,
|
||||||
|
|
||||||
"nope one what": `nope <img src="/emotes/one.png" height="28px" title="one" /> what`,
|
"nope one what": `nope <img src="/emotes/one.png" class="emote" title="one" /> what`,
|
||||||
"nope :two: what": `nope <img src="/emotes/two.png" height="28px" title="two" /> what`,
|
"nope :two: what": `nope <img src="/emotes/two.png" class="emote" title="two" /> what`,
|
||||||
"nope [three] what": `nope <img src="/emotes/three.gif" height="28px" title="three" /> what`,
|
"nope [three] what": `nope <img src="/emotes/three.gif" class="emote" title="three" /> what`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var data_wrapped = map[string]string{
|
var data_wrapped = map[string]string{
|
||||||
|
|
|
@ -16,14 +16,6 @@ var chatTemplates map[string]*text.Template
|
||||||
|
|
||||||
var isServer bool = false
|
var isServer bool = false
|
||||||
|
|
||||||
// keys and files to load for that template
|
|
||||||
var serverTemplateDefs map[string][]string = map[string][]string{
|
|
||||||
"pin": []string{"./static/base.html", "./static/thedoor.html"},
|
|
||||||
"main": []string{"./static/base.html", "./static/main.html"},
|
|
||||||
"help": []string{"./static/base.html", "./static/help.html"},
|
|
||||||
"emotes": []string{"./static/base.html", "./static/emotes.html"},
|
|
||||||
}
|
|
||||||
|
|
||||||
var chatTemplateDefs map[string]string = map[string]string{
|
var chatTemplateDefs map[string]string = map[string]string{
|
||||||
fmt.Sprint(DTInvalid, 0): "wot",
|
fmt.Sprint(DTInvalid, 0): "wot",
|
||||||
|
|
||||||
|
@ -38,6 +30,15 @@ func InitTemplates() error {
|
||||||
isServer = true
|
isServer = true
|
||||||
serverTemplates = make(map[string]*html.Template)
|
serverTemplates = make(map[string]*html.Template)
|
||||||
chatTemplates = make(map[string]*text.Template)
|
chatTemplates = make(map[string]*text.Template)
|
||||||
|
var runPath string = RunPath()
|
||||||
|
|
||||||
|
// keys and files to load for that template
|
||||||
|
var serverTemplateDefs map[string][]string = map[string][]string{
|
||||||
|
"pin": []string{runPath + "/static/base.html", runPath + "/static/thedoor.html"},
|
||||||
|
"main": []string{runPath + "/static/base.html", runPath + "/static/main.html"},
|
||||||
|
"help": []string{runPath + "/static/base.html", runPath + "/static/help.html"},
|
||||||
|
"emotes": []string{runPath + "/static/base.html", runPath + "/static/emotes.html"},
|
||||||
|
}
|
||||||
|
|
||||||
// Parse server templates
|
// Parse server templates
|
||||||
for key, files := range serverTemplateDefs {
|
for key, files := range serverTemplateDefs {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package common
|
||||||
// Misc utils
|
// Misc utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,3 +18,26 @@ func IsValidName(name string) bool {
|
||||||
return 3 <= len(name) && len(name) <= 36 &&
|
return 3 <= len(name) && len(name) <= 36 &&
|
||||||
usernameRegex.MatchString(name)
|
usernameRegex.MatchString(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the absolut directory containing the MovieNight binary
|
||||||
|
func RunPath() string {
|
||||||
|
ex, er := os.Executable()
|
||||||
|
if er != nil {
|
||||||
|
panic(er)
|
||||||
|
}
|
||||||
|
return filepath.Dir(ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Substr(input string, start int, length int) string {
|
||||||
|
asRunes := []rune(input)
|
||||||
|
|
||||||
|
if start >= len(asRunes) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if start+length > len(asRunes) {
|
||||||
|
length = len(asRunes) - start
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(asRunes[start : start+length])
|
||||||
|
}
|
||||||
|
|
44
emotes.go
44
emotes.go
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/zorchenhimer/MovieNight/common"
|
"github.com/zorchenhimer/MovieNight/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const emoteDir = "./static/emotes/"
|
const emoteDir = "/static/emotes/"
|
||||||
|
|
||||||
type TwitchUser struct {
|
type TwitchUser struct {
|
||||||
ID string
|
ID string
|
||||||
|
@ -28,8 +28,7 @@ type EmoteInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadEmotes() error {
|
func loadEmotes() error {
|
||||||
//fmt.Println(processEmoteDir(emoteDir))
|
newEmotes, err := processEmoteDir(common.RunPath() + emoteDir)
|
||||||
newEmotes, err := processEmoteDir(emoteDir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -71,7 +70,7 @@ func processEmoteDir(path string) (common.EmotesMap, error) {
|
||||||
}
|
}
|
||||||
for _, d := range subd {
|
for _, d := range subd {
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
//emotes = append(emotes, findEmotes(filepath.Join(path, dir, d.Name()))...)
|
// emotes = append(emotes, findEmotes(filepath.Join(path, dir, d.Name()))...)
|
||||||
p := filepath.Join(path, dir, d.Name())
|
p := filepath.Join(path, dir, d.Name())
|
||||||
em, err = findEmotes(p, em)
|
em, err = findEmotes(p, em)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -81,33 +80,50 @@ func processEmoteDir(path string) (common.EmotesMap, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("processEmoteDir: %d\n", len(em))
|
common.LogInfof("processEmoteDir: %d\n", len(em))
|
||||||
return em, nil
|
return em, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findEmotes(dir string, em common.EmotesMap) (common.EmotesMap, error) {
|
func substr(input string, start int, length int) string {
|
||||||
//em := NewEmotesMap()
|
asRunes := []rune(input)
|
||||||
|
|
||||||
fmt.Printf("finding emotes in %q\n", dir)
|
if start >= len(asRunes) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if start+length > len(asRunes) {
|
||||||
|
length = len(asRunes) - start
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(asRunes[start : start+length])
|
||||||
|
}
|
||||||
|
|
||||||
|
func findEmotes(dir string, em common.EmotesMap) (common.EmotesMap, error) {
|
||||||
|
var runPathLength = len(common.RunPath() + "/static/")
|
||||||
|
|
||||||
|
common.LogDebugf("finding emotes in %q\n", dir)
|
||||||
emotePNGs, err := filepath.Glob(filepath.Join(dir, "*.png"))
|
emotePNGs, err := filepath.Glob(filepath.Join(dir, "*.png"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return em, fmt.Errorf("unable to glob emote directory: %s\n", err)
|
return em, fmt.Errorf("unable to glob emote directory: %s\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("%d emotePNGs\n", len(emotePNGs))
|
common.LogInfof("Found %d emotePNGs\n", len(emotePNGs))
|
||||||
|
|
||||||
emoteGIFs, err := filepath.Glob(filepath.Join(dir, "*.gif"))
|
emoteGIFs, err := filepath.Glob(filepath.Join(dir, "*.gif"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return em, errors.Wrap(err, "unable to glob emote directory:")
|
return em, errors.Wrap(err, "unable to glob emote directory:")
|
||||||
}
|
}
|
||||||
fmt.Printf("%d emoteGIFs\n", len(emoteGIFs))
|
common.LogInfof("Found %d emoteGIFs\n", len(emoteGIFs))
|
||||||
|
|
||||||
for _, file := range emotePNGs {
|
for _, file := range emotePNGs {
|
||||||
em = em.Add(file)
|
png := strings.ReplaceAll(common.Substr(file, runPathLength, len(file)), "\\", "/")
|
||||||
//emotes = append(emotes, common.Emote{FullPath: dir, Code: file})
|
//common.LogDebugf("Emote PNG: %s", png)
|
||||||
|
em = em.Add(png)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range emoteGIFs {
|
for _, file := range emoteGIFs {
|
||||||
em = em.Add(file)
|
gif := strings.ReplaceAll(common.Substr(file, runPathLength, len(file)), "\\", "/")
|
||||||
|
//common.LogDebugf("Emote GIF: %s", gif)
|
||||||
|
em = em.Add(gif)
|
||||||
}
|
}
|
||||||
|
|
||||||
return em, nil
|
return em, nil
|
||||||
|
@ -123,7 +139,7 @@ func getEmotes(names []string) error {
|
||||||
return errors.Wrapf(err, "could not get emote data for \"%s\"", user.ID)
|
return errors.Wrapf(err, "could not get emote data for \"%s\"", user.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
emoteUserDir := filepath.Join(emoteDir, "twitch", user.Login)
|
emoteUserDir := filepath.Join(common.RunPath()+emoteDir, "twitch", user.Login)
|
||||||
if _, err := os.Stat(emoteUserDir); os.IsNotExist(err) {
|
if _, err := os.Stat(emoteUserDir); os.IsNotExist(err) {
|
||||||
os.MkdirAll(emoteUserDir, os.ModePerm)
|
os.MkdirAll(emoteUserDir, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
21
go.mod
21
go.mod
|
@ -3,21 +3,8 @@ module github.com/zorchenhimer/MovieNight
|
||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.4.12 // indirect
|
github.com/gorilla/sessions v1.2.1
|
||||||
github.com/cenkalti/backoff v2.1.1+incompatible // indirect
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/chromedp/cdproto v0.0.0-20190412020601-c4267f5c421a // indirect
|
github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 // indirect
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/gorilla/sessions v1.1.3
|
|
||||||
github.com/gorilla/websocket v1.4.0
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983 // indirect
|
|
||||||
github.com/nareix/joy4 v0.0.0-20181022032202-3ddbc8f9d431
|
|
||||||
github.com/ory/dockertest v3.3.4+incompatible // indirect
|
|
||||||
github.com/pkg/errors v0.8.1
|
|
||||||
github.com/sirupsen/logrus v1.4.1 // indirect
|
|
||||||
github.com/stretchr/objx v0.2.0 // indirect
|
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a // indirect
|
|
||||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f // indirect
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
|
|
||||||
)
|
)
|
||||||
|
|
107
go.sum
107
go.sum
|
@ -1,101 +1,10 @@
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
|
||||||
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
|
|
||||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
|
||||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
|
||||||
github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
|
|
||||||
github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
|
||||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
|
||||||
github.com/chromedp/cdproto v0.0.0-20190217000753-2d8e8962ceb2 h1:4Ck8YOuS0G3+0xMb80cDSff7QpUolhSc0PGyfagbcdA=
|
|
||||||
github.com/chromedp/cdproto v0.0.0-20190217000753-2d8e8962ceb2/go.mod h1:xquOK9dIGFlLaIGI4c6IyfLI/Gz0LiYYuJtzhsUODgI=
|
|
||||||
github.com/chromedp/cdproto v0.0.0-20190412020601-c4267f5c421a/go.mod h1:xquOK9dIGFlLaIGI4c6IyfLI/Gz0LiYYuJtzhsUODgI=
|
|
||||||
github.com/chromedp/chromedp v0.1.3 h1:Nkqt42/7tvzg57mexc4LbM8nZbx7vSZ+eiUpeczGGL8=
|
|
||||||
github.com/chromedp/chromedp v0.1.3/go.mod h1:ZahQlJx8YBfDtuFN80zn6P7fskSotBkdhgKDoLWFANk=
|
|
||||||
github.com/containerd/continuity v0.0.0-20181027224239-bea7585dbfac h1:PThQaO4yCvJzJBUW1XoFQxLotWRhvX2fgljJX8yrhFI=
|
|
||||||
github.com/containerd/continuity v0.0.0-20181027224239-bea7585dbfac/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/dennwc/dom v0.3.0 h1:u89+QvT1OPRSSTFf54o9RuK7C0Uoq2jFo4VCa4rnjtI=
|
|
||||||
github.com/dennwc/dom v0.3.0/go.mod h1:/z5w9Stx19m8RUwolsmsqTs9rDxKgJO5T9UEumilgk4=
|
|
||||||
github.com/dennwc/testproxy v1.0.1 h1:mQhNVWHPolTYjJrDZYKcugIplWRSlFAis6k/Zf1s0c0=
|
|
||||||
github.com/dennwc/testproxy v1.0.1/go.mod h1:EHGV9tzWhMPLmEoVJ2KGyC149XqwKZwBDViCjhKD5d8=
|
|
||||||
github.com/disintegration/imaging v1.6.0 h1:nVPXRUUQ36Z7MNf0O77UzgnOb1mkMMor7lmJMJXc/mA=
|
|
||||||
github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ=
|
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
|
||||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
|
||||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
|
||||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
|
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
|
github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369 h1:Yp0zFEufLz0H7jzffb4UPXijavlyqlYeOg7dcyVUNnQ=
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369/go.mod h1:aFJ1ZwLjvHN4yEzE5Bkz8rD8/d8Vlj3UIuvz2yfET7I=
|
||||||
github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307 h1:vl4eIlySbjertFaNwiMjXsGrFVK25aOWLq7n+3gh2ls=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190221075403-6243d8e04c3f h1:B6PQkurxGG1rqEX96oE14gbj8bqvYC5dtks9r5uGmlE=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190221075403-6243d8e04c3f/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/nareix/joy4 v0.0.0-20181022032202-3ddbc8f9d431 h1:nWhrOsCKdV6bivw03k7MROF2tYzCFGfYBYFrTEHyucs=
|
|
||||||
github.com/nareix/joy4 v0.0.0-20181022032202-3ddbc8f9d431/go.mod h1:aFJ1ZwLjvHN4yEzE5Bkz8rD8/d8Vlj3UIuvz2yfET7I=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
|
||||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
|
||||||
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
|
||||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
|
||||||
github.com/ory/dockertest v3.3.2+incompatible h1:uO+NcwH6GuFof/Uz8yzjNi1g0sGT5SLAJbdBvD8bUYc=
|
|
||||||
github.com/ory/dockertest v3.3.2+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
|
||||||
github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
|
||||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
|
||||||
|
|
79
handlers.go
79
handlers.go
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
@ -46,22 +45,23 @@ func (self writeFlusher) Flush() error {
|
||||||
|
|
||||||
// Serving static files
|
// Serving static files
|
||||||
func wsStaticFiles(w http.ResponseWriter, r *http.Request) {
|
func wsStaticFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var runPath string = common.RunPath()
|
||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/favicon.ico":
|
case "/favicon.ico":
|
||||||
http.ServeFile(w, r, "./favicon.png")
|
http.ServeFile(w, r, runPath+"/favicon.png")
|
||||||
return
|
return
|
||||||
case "/justchat":
|
case "/justchat":
|
||||||
http.ServeFile(w, r, "./static/justchat.html")
|
http.ServeFile(w, r, runPath+"/static/justchat.html")
|
||||||
return
|
return
|
||||||
case "/justvideo":
|
case "/justvideo":
|
||||||
http.ServeFile(w, r, "./static/justvideo.html")
|
http.ServeFile(w, r, runPath+"/static/justvideo.html")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
goodPath := r.URL.Path[8:len(r.URL.Path)]
|
goodPath := r.URL.Path[8:len(r.URL.Path)]
|
||||||
common.LogDebugf("[static] serving %q from folder ./static/\n", goodPath)
|
common.LogDebugf("[static] serving %q from folder %s\n", goodPath, runPath)
|
||||||
|
|
||||||
http.ServeFile(w, r, "./static/"+goodPath)
|
http.ServeFile(w, r, runPath+"/static/"+goodPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func wsWasmFile(w http.ResponseWriter, r *http.Request) {
|
func wsWasmFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -69,17 +69,17 @@ func wsWasmFile(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Cache-Control", "no-cache, must-revalidate")
|
w.Header().Set("Cache-Control", "no-cache, must-revalidate")
|
||||||
}
|
}
|
||||||
common.LogDebugln("[static] serving wasm file")
|
common.LogDebugln("[static] serving wasm file")
|
||||||
http.ServeFile(w, r, "./static/main.wasm")
|
http.ServeFile(w, r, common.RunPath()+"/static/main.wasm")
|
||||||
}
|
}
|
||||||
|
|
||||||
func wsImages(w http.ResponseWriter, r *http.Request) {
|
func wsImages(w http.ResponseWriter, r *http.Request) {
|
||||||
base := filepath.Base(r.URL.Path)
|
base := filepath.Base(r.URL.Path)
|
||||||
common.LogDebugln("[img] ", base)
|
common.LogDebugln("[img] ", base)
|
||||||
http.ServeFile(w, r, "./static/img/"+base)
|
http.ServeFile(w, r, common.RunPath()+"/static/img/"+base)
|
||||||
}
|
}
|
||||||
|
|
||||||
func wsEmotes(w http.ResponseWriter, r *http.Request) {
|
func wsEmotes(w http.ResponseWriter, r *http.Request) {
|
||||||
http.ServeFile(w, r, path.Join("./static/", r.URL.Path))
|
http.ServeFile(w, r, path.Join(common.RunPath()+"/static/", r.URL.Path))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling the websocket
|
// Handling the websocket
|
||||||
|
@ -190,6 +190,14 @@ func checkRoomAccess(w http.ResponseWriter, r *http.Request) bool {
|
||||||
// Pin is incorrect.
|
// Pin is incorrect.
|
||||||
handlePinTemplate(w, r, "Incorrect PIN")
|
handlePinTemplate(w, r, "Incorrect PIN")
|
||||||
return false
|
return false
|
||||||
|
} else {
|
||||||
|
qpin := r.URL.Query().Get("pin")
|
||||||
|
if qpin != "" && qpin == settings.RoomAccessPin {
|
||||||
|
// Pin is correct. Save it to session and return true.
|
||||||
|
session.Values["pin"] = settings.RoomAccessPin
|
||||||
|
session.Save(r, w)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// nope. display pin entry and return
|
// nope. display pin entry and return
|
||||||
handlePinTemplate(w, r, "")
|
handlePinTemplate(w, r, "")
|
||||||
|
@ -282,33 +290,13 @@ func handleEmoteTemplate(w http.ResponseWriter, r *http.Request) {
|
||||||
Emotes: common.Emotes,
|
Emotes: common.Emotes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
common.LogDebugf("Emotes Data: %s", data)
|
||||||
err := common.ExecuteServerTemplate(w, "emotes", data)
|
err := common.ExecuteServerTemplate(w, "emotes", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogErrorf("Error executing file, %v", err)
|
common.LogErrorf("Error executing file, %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePin(w http.ResponseWriter, r *http.Request) {
|
|
||||||
session, err := sstore.Get(r, "moviesession")
|
|
||||||
if err != nil {
|
|
||||||
common.LogDebugf("Unable to get session: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
val := session.Values["pin"]
|
|
||||||
if val == nil {
|
|
||||||
session.Values["pin"] = "1234"
|
|
||||||
err := session.Save(r, w)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(w, "unable to save session: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Fprint(w, "Pin was not set")
|
|
||||||
common.LogDebugln("pin was not set")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(w, "pin set: %v", val)
|
|
||||||
common.LogDebugf("pin is set: %v\n", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleIndexTemplate(w http.ResponseWriter, r *http.Request) {
|
func handleIndexTemplate(w http.ResponseWriter, r *http.Request) {
|
||||||
if settings.RoomAccess != AccessOpen {
|
if settings.RoomAccess != AccessOpen {
|
||||||
if !checkRoomAccess(w, r) {
|
if !checkRoomAccess(w, r) {
|
||||||
|
@ -361,34 +349,39 @@ func handlePublish(conn *rtmp.Conn) {
|
||||||
|
|
||||||
if len(urlParts) > 2 {
|
if len(urlParts) > 2 {
|
||||||
common.LogErrorln("Extra garbage after stream key")
|
common.LogErrorln("Extra garbage after stream key")
|
||||||
|
l.Unlock()
|
||||||
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(urlParts) != 2 {
|
if len(urlParts) != 2 {
|
||||||
common.LogErrorln("Missing stream key")
|
common.LogErrorln("Missing stream key")
|
||||||
|
l.Unlock()
|
||||||
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if urlParts[1] != settings.GetStreamKey() {
|
if urlParts[1] != settings.GetStreamKey() {
|
||||||
common.LogErrorln("Stream key is incorrect. Denying stream.")
|
common.LogErrorln("Stream key is incorrect. Denying stream.")
|
||||||
|
l.Unlock()
|
||||||
|
conn.Close()
|
||||||
return //If key not match, deny stream
|
return //If key not match, deny stream
|
||||||
}
|
}
|
||||||
|
|
||||||
streamPath := urlParts[0]
|
streamPath := urlParts[0]
|
||||||
ch := channels[streamPath]
|
ch, exists := channels[streamPath]
|
||||||
if ch == nil {
|
if exists {
|
||||||
|
common.LogErrorln("Stream already running. Denying publish.")
|
||||||
|
conn.Close()
|
||||||
|
l.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ch = &Channel{}
|
ch = &Channel{}
|
||||||
ch.que = pubsub.NewQueue()
|
ch.que = pubsub.NewQueue()
|
||||||
ch.que.WriteHeader(streams)
|
ch.que.WriteHeader(streams)
|
||||||
channels[streamPath] = ch
|
channels[streamPath] = ch
|
||||||
} else {
|
|
||||||
ch = nil
|
|
||||||
}
|
|
||||||
l.Unlock()
|
l.Unlock()
|
||||||
if ch == nil {
|
|
||||||
common.LogErrorln("Unable to start stream, channel is nil.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stats.startStream()
|
stats.startStream()
|
||||||
|
|
||||||
|
@ -415,7 +408,7 @@ func handlePlay(conn *rtmp.Conn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDefault(w http.ResponseWriter, r *http.Request) {
|
func handleLive(w http.ResponseWriter, r *http.Request) {
|
||||||
l.RLock()
|
l.RLock()
|
||||||
ch := channels[strings.Trim(r.URL.Path, "/")]
|
ch := channels[strings.Trim(r.URL.Path, "/")]
|
||||||
l.RUnlock()
|
l.RUnlock()
|
||||||
|
@ -433,6 +426,11 @@ func handleDefault(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
avutil.CopyFile(muxer, cursor)
|
avutil.CopyFile(muxer, cursor)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleDefault(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path != "/" {
|
if r.URL.Path != "/" {
|
||||||
// not really an error for the server, but for the client.
|
// not really an error for the server, but for the client.
|
||||||
common.LogInfoln("[http 404] ", r.URL.Path)
|
common.LogInfoln("[http 404] ", r.URL.Path)
|
||||||
|
@ -440,5 +438,4 @@ func handleDefault(w http.ResponseWriter, r *http.Request) {
|
||||||
} else {
|
} else {
|
||||||
handleIndexTemplate(w, r)
|
handleIndexTemplate(w, r)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
81
main.go
81
main.go
|
@ -1,11 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/nareix/joy4/format"
|
"github.com/nareix/joy4/format"
|
||||||
|
@ -20,11 +22,12 @@ var (
|
||||||
sKey string
|
sKey string
|
||||||
stats = newStreamStats()
|
stats = newStreamStats()
|
||||||
sAdminPass string
|
sAdminPass string
|
||||||
|
confFile string
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupSettings() error {
|
func setupSettings() error {
|
||||||
var err error
|
var err error
|
||||||
settings, err = LoadSettings("settings.json")
|
settings, err = LoadSettings(confFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to load settings: %s", err)
|
return fmt.Errorf("Unable to load settings: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -53,6 +56,7 @@ func main() {
|
||||||
flag.StringVar(&sKey, "k", "", "Stream key, to protect your stream")
|
flag.StringVar(&sKey, "k", "", "Stream key, to protect your stream")
|
||||||
flag.StringVar(&sAdminPass, "a", "", "Set admin password. Overrides configuration in settings.json. This will not write the password to settings.json.")
|
flag.StringVar(&sAdminPass, "a", "", "Set admin password. Overrides configuration in settings.json. This will not write the password to settings.json.")
|
||||||
flag.BoolVar(&pullEmotes, "e", false, "Pull emotes")
|
flag.BoolVar(&pullEmotes, "e", false, "Pull emotes")
|
||||||
|
flag.StringVar(&confFile, "f", "./settings.json", "URI of the conf file")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
format.RegisterAll()
|
format.RegisterAll()
|
||||||
|
@ -109,47 +113,64 @@ func main() {
|
||||||
common.LogInfoln("RoomAccess: ", settings.RoomAccess)
|
common.LogInfoln("RoomAccess: ", settings.RoomAccess)
|
||||||
common.LogInfoln("RoomAccessPin: ", settings.RoomAccessPin)
|
common.LogInfoln("RoomAccessPin: ", settings.RoomAccessPin)
|
||||||
|
|
||||||
go startServer()
|
rtmpServer := &rtmp.Server{
|
||||||
go startRmtpServer()
|
|
||||||
|
|
||||||
<-exit
|
|
||||||
}
|
|
||||||
|
|
||||||
func startRmtpServer() {
|
|
||||||
server := &rtmp.Server{
|
|
||||||
HandlePlay: handlePlay,
|
HandlePlay: handlePlay,
|
||||||
HandlePublish: handlePublish,
|
HandlePublish: handlePublish,
|
||||||
Addr: rtmpAddr,
|
Addr: rtmpAddr,
|
||||||
}
|
}
|
||||||
err := server.ListenAndServe()
|
|
||||||
|
router := http.NewServeMux()
|
||||||
|
|
||||||
|
router.HandleFunc("/ws", wsHandler) // Chat websocket
|
||||||
|
router.HandleFunc("/static/js/", wsStaticFiles)
|
||||||
|
router.HandleFunc("/static/css/", wsStaticFiles)
|
||||||
|
router.HandleFunc("/static/img/", wsImages)
|
||||||
|
router.HandleFunc("/static/main.wasm", wsWasmFile)
|
||||||
|
router.HandleFunc("/emotes/", wsEmotes)
|
||||||
|
router.HandleFunc("/favicon.ico", wsStaticFiles)
|
||||||
|
router.HandleFunc("/chat", handleIndexTemplate)
|
||||||
|
router.HandleFunc("/video", handleIndexTemplate)
|
||||||
|
router.HandleFunc("/help", handleHelpTemplate)
|
||||||
|
router.HandleFunc("/emotes", handleEmoteTemplate)
|
||||||
|
|
||||||
|
router.HandleFunc("/live", handleLive)
|
||||||
|
router.HandleFunc("/", handleDefault)
|
||||||
|
|
||||||
|
httpServer := &http.Server{
|
||||||
|
Addr: addr,
|
||||||
|
Handler: router,
|
||||||
|
}
|
||||||
|
|
||||||
|
// RTMP Server
|
||||||
|
go func() {
|
||||||
|
err := rtmpServer.ListenAndServe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the server cannot start, don't pretend we can continue.
|
// If the server cannot start, don't pretend we can continue.
|
||||||
panic("Error trying to start rtmp server: " + err.Error())
|
panic("Error trying to start rtmp server: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
|
|
||||||
func startServer() {
|
// HTTP Server
|
||||||
// Chat websocket
|
go func() {
|
||||||
http.HandleFunc("/ws", wsHandler)
|
err := httpServer.ListenAndServe()
|
||||||
http.HandleFunc("/static/js/", wsStaticFiles)
|
if err != nil && err != http.ErrServerClosed {
|
||||||
http.HandleFunc("/static/css/", wsStaticFiles)
|
|
||||||
http.HandleFunc("/static/img/", wsImages)
|
|
||||||
http.HandleFunc("/static/main.wasm", wsWasmFile)
|
|
||||||
http.HandleFunc("/emotes/", wsEmotes)
|
|
||||||
http.HandleFunc("/favicon.ico", wsStaticFiles)
|
|
||||||
http.HandleFunc("/chat", handleIndexTemplate)
|
|
||||||
http.HandleFunc("/video", handleIndexTemplate)
|
|
||||||
http.HandleFunc("/help", handleHelpTemplate)
|
|
||||||
http.HandleFunc("/pin", handlePin)
|
|
||||||
http.HandleFunc("/emotes", handleEmoteTemplate)
|
|
||||||
|
|
||||||
http.HandleFunc("/", handleDefault)
|
|
||||||
|
|
||||||
err := http.ListenAndServe(addr, nil)
|
|
||||||
if err != nil {
|
|
||||||
// If the server cannot start, don't pretend we can continue.
|
// If the server cannot start, don't pretend we can continue.
|
||||||
panic("Error trying to start chat/http server: " + err.Error())
|
panic("Error trying to start chat/http server: " + err.Error())
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-exit
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := httpServer.Shutdown(ctx); err != nil && err != http.ErrServerClosed {
|
||||||
|
panic("Gracefull HTTP server shutdown failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// I don't think the RTMP server can be shutdown cleanly. Apparently the author
|
||||||
|
// of joy4 want's everyone to use joy5, but that one doesn't seem to allow clean
|
||||||
|
// shutdowns either? Idk, the documentation on joy4 and joy5 are non-existent.
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleInterrupt(exit chan bool) {
|
func handleInterrupt(exit chan bool) {
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
TAGS=
|
||||||
|
|
||||||
|
.PHONY: fmt vet get clean dev setdev test ServerMovieNight
|
||||||
|
|
||||||
|
all: fmt vet test MovieNight static/main.wasm settings.json
|
||||||
|
|
||||||
|
server: ServerMovieNight static/main.wasm
|
||||||
|
|
||||||
|
ServerMovieNight: *.go common/*.go
|
||||||
|
GOOS=${TARGET} GOARCH=${ARCH} go$(GO_VERSION) build -o MovieNight $(TAGS)
|
||||||
|
|
||||||
|
setdev:
|
||||||
|
$(eval export TAGS=-tags "dev")
|
||||||
|
|
||||||
|
dev: setdev all
|
||||||
|
|
||||||
|
MovieNight: *.go common/*.go
|
||||||
|
GOOS=${TARGET} GOARCH=${ARCH} go$(GO_VERSION) build -o MovieNight${EXT} $(TAGS)
|
||||||
|
|
||||||
|
static/js/wasm_exec.js:
|
||||||
|
cp $$(go$(GO_VERSION) env GOROOT)/misc/wasm/wasm_exec.js $@
|
||||||
|
|
||||||
|
static/main.wasm: static/js/wasm_exec.js wasm/*.go common/*.go
|
||||||
|
GOOS=js GOARCH=wasm go$(GO_VERSION) build -o $@ $(TAGS) wasm/*.go
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm MovieNight${EXT} ./static/main.wasm ./static/js/wasm_exec.js
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
gofmt -w .
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go$(GO_VERSION) vet $(TAGS) ./...
|
||||||
|
GOOS=js GOARCH=wasm go$(GO_VERSION) vet $(TAGS) ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
go$(GO_VERSION) test $(TAGS) ./...
|
||||||
|
|
||||||
|
# Do not put settings_example.json here as a prereq to avoid overwriting
|
||||||
|
# the settings if the example is updated.
|
||||||
|
settings.json:
|
||||||
|
cp settings_example.json settings.json
|
24
readme.md
24
readme.md
|
@ -1,6 +1,5 @@
|
||||||
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
|
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
|
||||||
**Table of Contents**
|
**Table of Contents**
|
||||||
|
|
||||||
- [MovieNight stream server](#movienight-stream-server)
|
- [MovieNight stream server](#movienight-stream-server)
|
||||||
- [Build requirements](#build-requirements)
|
- [Build requirements](#build-requirements)
|
||||||
- [Older Go Versions](#older-go-versions)
|
- [Older Go Versions](#older-go-versions)
|
||||||
|
@ -10,6 +9,7 @@
|
||||||
- [Running the Container](#running-the-container)
|
- [Running the Container](#running-the-container)
|
||||||
- [docker-compose](#docker-compose)
|
- [docker-compose](#docker-compose)
|
||||||
- [Notes for Running Using docker-compose](#notes-for-running-using-docker-compose)
|
- [Notes for Running Using docker-compose](#notes-for-running-using-docker-compose)
|
||||||
|
- [FreeNAS / TrueNAS / FreeBSD build and run](#freenas-freebsd-build-and-run)
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Configuration](#configuration)
|
- [Configuration](#configuration)
|
||||||
|
|
||||||
|
@ -21,12 +21,10 @@ replace Rabbit as the platform for watching movies with a group of people
|
||||||
online.
|
online.
|
||||||
|
|
||||||
## Build requirements
|
## Build requirements
|
||||||
|
|
||||||
- Go 1.13 or newer
|
- Go 1.13 or newer
|
||||||
- GNU Make
|
- GNU Make
|
||||||
|
|
||||||
### Older Go Versions
|
### Older Go Versions
|
||||||
|
|
||||||
You can install a newer version of Go alongside your OS's distribution by
|
You can install a newer version of Go alongside your OS's distribution by
|
||||||
following the guide here: [https://golang.org/doc/manage-install](https://golang.org/doc/manage-install)
|
following the guide here: [https://golang.org/doc/manage-install](https://golang.org/doc/manage-install)
|
||||||
|
|
||||||
|
@ -35,13 +33,18 @@ set it to the version you installed (eg, `1.14.1`). The Makefile will now use
|
||||||
the newer version.
|
the newer version.
|
||||||
|
|
||||||
### Compile and install
|
### Compile and install
|
||||||
|
You have to :
|
||||||
|
- download `git clone https://github.com/zorchenhimer/MovieNight`, go into the source directory `cd MovieNight`;
|
||||||
|
- choose your `TARGET` oneof "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows";
|
||||||
|
- choose your `ARCH` oneof "386 amd64 amd64p32 arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32leppc s390 s390x sparc sparc64";
|
||||||
|
- build `make TARGET=windows ARCH=386`;
|
||||||
|
- and run `./MovieNight`;
|
||||||
|
|
||||||
To just download and run:
|
Example :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git clone https://git.mentality.rip/sjw/MovieNight.git
|
$ git clone https://git.mentality.rip/sjw/MovieNight.git
|
||||||
$ cd MovieNight
|
$ cd MovieNight
|
||||||
$ make
|
$ make TARGET=windows ARCH=386
|
||||||
$ ./MovieNight
|
$ ./MovieNight
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -82,8 +85,11 @@ This docker-compose file will create a volume called *movienight-config* and aut
|
||||||
#### Notes for Running Using docker-compose
|
#### Notes for Running Using docker-compose
|
||||||
The container needs to be restarted to apply any changes you make to *settings.json*.
|
The container needs to be restarted to apply any changes you make to *settings.json*.
|
||||||
|
|
||||||
## Usage
|
### FreeNAS-FreeBSD build and run
|
||||||
|
A [FreeNAS & TrueNAS plugin](https://github.com/zorglube/iocage-plugin-movienight) had been released. You should find MovieNight into the plugin section of you management GUI. However you still can make an manual plugin deployment, documentation [here](https://github.com/freenas/iocage-ix-plugins)
|
||||||
|
If you prefer to make an Jail without using the plugin management, a script wich setup an Jail and build and run MovieNight into that Jail as been written, you'll find it here [freenas-iocage-movienight](https://github.com/zorglube/freenas-iocage-movienight)
|
||||||
|
|
||||||
|
## Usage
|
||||||
Now you can use OBS to push a stream to the server. Set the stream URL to
|
Now you can use OBS to push a stream to the server. Set the stream URL to
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
@ -123,10 +129,11 @@ Usage of .\MovieNight.exe:
|
||||||
host:port of the MovieNight (default ":8089")
|
host:port of the MovieNight (default ":8089")
|
||||||
-r string
|
-r string
|
||||||
host:port of the RTMP server (default ":1935")
|
host:port of the RTMP server (default ":1935")
|
||||||
|
-f string
|
||||||
|
the settings file you want to use (default "./settings.json")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
MovieNight’s configuration is controlled by `settings.json`:
|
MovieNight’s configuration is controlled by `settings.json`:
|
||||||
|
|
||||||
- `AdminPassword`: users can enter `/auth <value>` into chat to grant themselves
|
- `AdminPassword`: users can enter `/auth <value>` into chat to grant themselves
|
||||||
|
@ -166,5 +173,4 @@ MovieNight’s configuration is controlled by `settings.json`:
|
||||||
header, to prevent caching responses.
|
header, to prevent caching responses.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
`flv.js` is Licensed under the Apache 2.0 license. This project is licened under the MIT license.
|
`flv.js` is Licensed under the Apache 2.0 license. This project is licened under the MIT license.
|
||||||
|
|
|
@ -85,7 +85,9 @@ func LoadSettings(filename string) (*Settings, error) {
|
||||||
}
|
}
|
||||||
s.filename = filename
|
s.filename = filename
|
||||||
|
|
||||||
if err = common.SetupLogging(s.LogLevel, s.LogFile); err != nil {
|
var logFileDir string = s.LogFile
|
||||||
|
fmt.Printf("Log file: %s\n", logFileDir)
|
||||||
|
if err = common.SetupLogging(s.LogLevel, logFileDir); err != nil {
|
||||||
return nil, fmt.Errorf("Unable to setup logger: %s", err)
|
return nil, fmt.Errorf("Unable to setup logger: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,10 @@ input[type=text] {
|
||||||
width: 112px;
|
width: 112px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emote {
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
.notice {
|
.notice {
|
||||||
color: #595959;
|
color: #595959;
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
|
|
Loading…
Reference in New Issue