diff --git a/.gitignore b/.gitignore index d996f8d..7e1383f 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ tags # channel and emote list from twitch subscribers.json +/.settings/ +/.project diff --git a/Makefile b/Makefile index e7fa083..cf476cd 100644 --- a/Makefile +++ b/Makefile @@ -1,56 +1,15 @@ -# 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 - -TAGS= - -# Windows needs the .exe extension. -ifeq ($(OS),Windows_NT) -EXT=.exe -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 +# 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 + +# Windows needs the .exe extension. +ifeq ($(OS),Windows_NT) +EXT=.exe +endif diff --git a/Makefile.BSD b/Makefile.BSD new file mode 100644 index 0000000..f49a3f2 --- /dev/null +++ b/Makefile.BSD @@ -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 diff --git a/common/chatdata.go b/common/chatdata.go index 1fd77c7..bc7a191 100644 --- a/common/chatdata.go +++ b/common/chatdata.go @@ -1,10 +1,12 @@ package common import ( + "bytes" "encoding/json" "errors" "fmt" "strings" + "text/template" ) type DataInterface interface { @@ -89,38 +91,51 @@ type DataMessage struct { Type MessageType } +var ( + cmdme = template.Must(template.New("cmdme").Parse(`{{.From}} {{.Message}}`)) + announcement = template.Must(template.New("announcement").Parse(`{{.Message}}`)) + errormsg = template.Must(template.New("error").Parse(`{{.Message}}`)) + notice = template.Must(template.New("notice").Parse(`{{.Message}}`)) + command = template.Must(template.New("command").Parse(`{{.Message}}`)) + commanderror = template.Must(template.New("commanderror").Parse(`{{.Message}}`)) + cmdlMod = template.Must(template.New("cmdlMod").Parse(`{{.From}}: {{.Message}}`)) + cmdlAdmin = template.Must(template.New("CmdlAdmin").Parse(`{{.From}}: {{.Message}}`)) + defaultMsg = template.Must(template.New("defaultMsg").Parse(`{{.From}}: {{.Message}}`)) +) + // TODO: Read this HTML from a template somewhere func (dc DataMessage) HTML() string { + buf := &bytes.Buffer{} switch dc.Type { case MsgAction: - return `` + dc.From + - ` ` + dc.Message + `` - + cmdme.Execute(buf, dc) + return buf.String() case MsgServer: - return `` + dc.Message + `` - + announcement.Execute(buf, dc) + return buf.String() case MsgError: - return `` + dc.Message + `` - + errormsg.Execute(buf, dc) + return buf.String() case MsgNotice: - return `` + dc.Message + `` - + notice.Execute(buf, dc) + return buf.String() case MsgCommandResponse: - return `` + dc.Message + `` - + command.Execute(buf, dc) + return buf.String() case MsgCommandError: - return `` + dc.Message + `` + commanderror.Execute(buf, dc) + return buf.String() default: - badge := "" switch dc.Level { case CmdlMod: - badge = `` + cmdlMod.Execute(buf, dc) case CmdlAdmin: - badge = `` + cmdlAdmin.Execute(buf, dc) + default: + defaultMsg.Execute(buf, dc) } - return `` + badge + `` + dc.From + - `: ` + dc.Message + `` + return buf.String() } } @@ -165,42 +180,51 @@ type DataEvent struct { Event EventType User string Color string + Users []string } +var ( + evKick = template.Must(template.New("evKick").Parse(`{{.User}} has been kicked.`)) + evLeave = template.Must(template.New("evLeave").Parse(`{{.User}} has left the chat.`)) + evBan = template.Must(template.New("evBan").Parse(`{{.User}} has been banned.`)) + evJoin = template.Must(template.New("evJoin").Parse(`{{.User}} has joined the chat.`)) + evNameChangeWC = template.Must(template.New("evNameChangeWC").Parse(`Somebody changed their name, but IDK who {{.}}.`)) + evNameChange = template.Must(template.New("evNameChange").Parse(`{{index .Users 0}} has changed their name to {{index .Users 1}}.`)) + evNameChangeForced = template.Must(template.New("evNameChangeForced").Parse(`{{index .Users 0}} has had their name changed to {{index .Users 1}} by an admin.`)) + evNameChangeForcedWC = template.Must(template.New("evNameChangeForcedWC").Parse(`An admin changed somebody's name, but IDK who {{.}}.`)) +) + func (de DataEvent) HTML() string { + buf := &bytes.Buffer{} switch de.Event { case EvKick: - return `` + - de.User + ` has been kicked.` + evKick.Execute(buf, de) + return buf.String() case EvLeave: - return `` + - de.User + ` has left the chat.` + evLeave.Execute(buf, de) + return buf.String() case EvBan: - return `` + - de.User + ` has been banned.` + evBan.Execute(buf, de) + return buf.String() case EvJoin: - return `` + - de.User + ` has joined the chat.` + evJoin.Execute(buf, de) + return buf.String() case EvNameChange: - names := strings.Split(de.User, ":") - if len(names) != 2 { - return `Somebody changed their name, but IDK who ` + - ParseEmotes("Jebaited") + `.` + de.Users = strings.Split(de.User, ":") + if len(de.Users) < 2 { + evNameChangeWC.Execute(buf, ParseEmotes("Jebaited")) + } else { + evNameChange.Execute(buf, de) } - - return `` + - names[0] + ` has changed their name to ` + names[1] + `.` + return buf.String() case EvNameChangeForced: - names := strings.Split(de.User, ":") - if len(names) != 2 { - return `An admin changed somebody's name, but IDK who ` + - ParseEmotes("Jebaited") + `.` + de.Users = strings.Split(de.User, ":") + if len(de.Users) < 2 { + evNameChangeForcedWC.Execute(buf, ParseEmotes("Jebaited")) + } else { + evNameChangeForced.Execute(buf, de) } - - return `` + - names[0] + ` has had their name changed to ` + names[1] + ` by an admin.` + return buf.String() } return "" } diff --git a/common/emotes.go b/common/emotes.go index fcd3746..052e265 100644 --- a/common/emotes.go +++ b/common/emotes.go @@ -48,7 +48,7 @@ func (em EmotesMap) Add(fullpath string) EmotesMap { } func EmoteToHtml(file, title string) string { - return fmt.Sprintf(``, file, title) + return fmt.Sprintf(``, file, title) } // 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 { key = strings.Trim(key, ":[]") if val, ok := Emotes[key]; ok { - return fmt.Sprintf(``, val, key) + return fmt.Sprintf(``, val, key) } return key } diff --git a/common/emotes_test.go b/common/emotes_test.go index 0e61f87..0e3cf28 100644 --- a/common/emotes_test.go +++ b/common/emotes_test.go @@ -6,31 +6,31 @@ import ( ) var data_good = map[string]string{ - "one": ``, - "two": ``, - "three": ``, + "one": ``, + "two": ``, + "three": ``, - ":one:": ``, - ":two:": ``, - ":three:": ``, + ":one:": ``, + ":two:": ``, + ":three:": ``, - ":one::one:": ``, - ":one:one:": `one:`, + ":one::one:": ``, + ":one:one:": `one:`, "oneone": "oneone", - "one:one:": `one`, + "one:one:": `one`, - "[one]": ``, - "[two]": ``, - "[three]": ``, + "[one]": ``, + "[two]": ``, + "[three]": ``, - "[one][one]": ``, - "[one]one": `one`, + "[one][one]": ``, + "[one]one": `one`, - ":one: two [three]": ` `, + ":one: two [three]": ` `, - "nope one what": `nope what`, - "nope :two: what": `nope what`, - "nope [three] what": `nope what`, + "nope one what": `nope what`, + "nope :two: what": `nope what`, + "nope [three] what": `nope what`, } var data_wrapped = map[string]string{ diff --git a/common/templates.go b/common/templates.go index e8b3abb..448bc29 100644 --- a/common/templates.go +++ b/common/templates.go @@ -16,14 +16,6 @@ var chatTemplates map[string]*text.Template 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{ fmt.Sprint(DTInvalid, 0): "wot", @@ -38,6 +30,15 @@ func InitTemplates() error { isServer = true serverTemplates = make(map[string]*html.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 for key, files := range serverTemplateDefs { diff --git a/common/utils.go b/common/utils.go index 4f1dda2..f84900c 100644 --- a/common/utils.go +++ b/common/utils.go @@ -3,6 +3,8 @@ package common // Misc utils import ( + "os" + "path/filepath" "regexp" ) @@ -16,3 +18,26 @@ func IsValidName(name string) bool { return 3 <= len(name) && len(name) <= 36 && 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]) +} diff --git a/emotes.go b/emotes.go index f9d117c..8f681ba 100644 --- a/emotes.go +++ b/emotes.go @@ -15,7 +15,7 @@ import ( "github.com/zorchenhimer/MovieNight/common" ) -const emoteDir = "./static/emotes/" +const emoteDir = "/static/emotes/" type TwitchUser struct { ID string @@ -28,8 +28,7 @@ type EmoteInfo struct { } func loadEmotes() error { - //fmt.Println(processEmoteDir(emoteDir)) - newEmotes, err := processEmoteDir(emoteDir) + newEmotes, err := processEmoteDir(common.RunPath() + emoteDir) if err != nil { return err } @@ -71,7 +70,7 @@ func processEmoteDir(path string) (common.EmotesMap, error) { } for _, d := range subd { 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()) em, err = findEmotes(p, em) 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 } -func findEmotes(dir string, em common.EmotesMap) (common.EmotesMap, error) { - //em := NewEmotesMap() +func substr(input string, start int, length int) string { + 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")) if err != nil { 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")) if err != nil { 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 { - em = em.Add(file) - //emotes = append(emotes, common.Emote{FullPath: dir, Code: file}) + png := strings.ReplaceAll(common.Substr(file, runPathLength, len(file)), "\\", "/") + //common.LogDebugf("Emote PNG: %s", png) + em = em.Add(png) } 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 @@ -123,7 +139,7 @@ func getEmotes(names []string) error { 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) { os.MkdirAll(emoteUserDir, os.ModePerm) } diff --git a/go.mod b/go.mod index 80a73c0..eab47af 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,8 @@ module github.com/zorchenhimer/MovieNight go 1.12 require ( - github.com/Microsoft/go-winio v0.4.12 // indirect - github.com/cenkalti/backoff v2.1.1+incompatible // indirect - github.com/chromedp/cdproto v0.0.0-20190412020601-c4267f5c421a // indirect - github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 // indirect - 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 + github.com/gorilla/sessions v1.2.1 + github.com/gorilla/websocket v1.4.2 + github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369 + github.com/pkg/errors v0.9.1 ) diff --git a/go.sum b/go.sum index 6ddf141..d31e651 100644 --- a/go.sum +++ b/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/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= -github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307 h1:vl4eIlySbjertFaNwiMjXsGrFVK25aOWLq7n+3gh2ls= -github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ= -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= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369 h1:Yp0zFEufLz0H7jzffb4UPXijavlyqlYeOg7dcyVUNnQ= +github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369/go.mod h1:aFJ1ZwLjvHN4yEzE5Bkz8rD8/d8Vlj3UIuvz2yfET7I= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/handlers.go b/handlers.go index 969fa97..8b3ae68 100644 --- a/handlers.go +++ b/handlers.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "fmt" "io" "net/http" "path" @@ -46,22 +45,23 @@ func (self writeFlusher) Flush() error { // Serving static files func wsStaticFiles(w http.ResponseWriter, r *http.Request) { + var runPath string = common.RunPath() switch r.URL.Path { case "/favicon.ico": - http.ServeFile(w, r, "./favicon.png") + http.ServeFile(w, r, runPath+"/favicon.png") return case "/justchat": - http.ServeFile(w, r, "./static/justchat.html") + http.ServeFile(w, r, runPath+"/static/justchat.html") return case "/justvideo": - http.ServeFile(w, r, "./static/justvideo.html") + http.ServeFile(w, r, runPath+"/static/justvideo.html") return } 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) { @@ -69,17 +69,17 @@ func wsWasmFile(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-cache, must-revalidate") } 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) { base := filepath.Base(r.URL.Path) 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) { - 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 @@ -190,6 +190,14 @@ func checkRoomAccess(w http.ResponseWriter, r *http.Request) bool { // Pin is incorrect. handlePinTemplate(w, r, "Incorrect PIN") 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 handlePinTemplate(w, r, "") @@ -282,33 +290,13 @@ func handleEmoteTemplate(w http.ResponseWriter, r *http.Request) { Emotes: common.Emotes, } + common.LogDebugf("Emotes Data: %s", data) err := common.ExecuteServerTemplate(w, "emotes", data) if err != nil { 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) { if settings.RoomAccess != AccessOpen { if !checkRoomAccess(w, r) { @@ -361,35 +349,40 @@ func handlePublish(conn *rtmp.Conn) { if len(urlParts) > 2 { common.LogErrorln("Extra garbage after stream key") + l.Unlock() + conn.Close() return } if len(urlParts) != 2 { common.LogErrorln("Missing stream key") + l.Unlock() + conn.Close() return } if urlParts[1] != settings.GetStreamKey() { common.LogErrorln("Stream key is incorrect. Denying stream.") + l.Unlock() + conn.Close() return //If key not match, deny stream } streamPath := urlParts[0] - ch := channels[streamPath] - if ch == nil { - ch = &Channel{} - ch.que = pubsub.NewQueue() - ch.que.WriteHeader(streams) - channels[streamPath] = ch - } else { - ch = nil - } - l.Unlock() - if ch == nil { - common.LogErrorln("Unable to start stream, channel is nil.") + ch, exists := channels[streamPath] + if exists { + common.LogErrorln("Stream already running. Denying publish.") + conn.Close() + l.Unlock() return } + ch = &Channel{} + ch.que = pubsub.NewQueue() + ch.que.WriteHeader(streams) + channels[streamPath] = ch + l.Unlock() + stats.startStream() common.LogInfoln("Stream started") @@ -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() ch := channels[strings.Trim(r.URL.Path, "/")] l.RUnlock() @@ -433,12 +426,16 @@ func handleDefault(w http.ResponseWriter, r *http.Request) { avutil.CopyFile(muxer, cursor) } else { - if r.URL.Path != "/" { - // not really an error for the server, but for the client. - common.LogInfoln("[http 404] ", r.URL.Path) - http.NotFound(w, r) - } else { - handleIndexTemplate(w, r) - } + + } +} + +func handleDefault(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + // not really an error for the server, but for the client. + common.LogInfoln("[http 404] ", r.URL.Path) + http.NotFound(w, r) + } else { + handleIndexTemplate(w, r) } } diff --git a/main.go b/main.go index 3dfeeac..36f73b4 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,13 @@ package main import ( + "context" "flag" "fmt" "net/http" "os" "os/signal" + "time" "github.com/gorilla/sessions" "github.com/nareix/joy4/format" @@ -20,11 +22,12 @@ var ( sKey string stats = newStreamStats() sAdminPass string + confFile string ) func setupSettings() error { var err error - settings, err = LoadSettings("settings.json") + settings, err = LoadSettings(confFile) if err != nil { 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(&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.StringVar(&confFile, "f", "./settings.json", "URI of the conf file") flag.Parse() format.RegisterAll() @@ -109,47 +113,64 @@ func main() { common.LogInfoln("RoomAccess: ", settings.RoomAccess) common.LogInfoln("RoomAccessPin: ", settings.RoomAccessPin) - go startServer() - go startRmtpServer() - - <-exit -} - -func startRmtpServer() { - server := &rtmp.Server{ + rtmpServer := &rtmp.Server{ HandlePlay: handlePlay, HandlePublish: handlePublish, Addr: rtmpAddr, } - err := server.ListenAndServe() - if err != nil { - // If the server cannot start, don't pretend we can continue. - panic("Error trying to start rtmp server: " + err.Error()) + + 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, } -} -func startServer() { - // Chat websocket - http.HandleFunc("/ws", wsHandler) - http.HandleFunc("/static/js/", wsStaticFiles) - 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) + // RTMP Server + go func() { + err := rtmpServer.ListenAndServe() + if err != nil { + // If the server cannot start, don't pretend we can continue. + panic("Error trying to start rtmp server: " + err.Error()) + } + }() - http.HandleFunc("/", handleDefault) + // HTTP Server + go func() { + err := httpServer.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + // If the server cannot start, don't pretend we can continue. + panic("Error trying to start chat/http server: " + err.Error()) + } + }() - err := http.ListenAndServe(addr, nil) - if err != nil { - // If the server cannot start, don't pretend we can continue. - 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) { diff --git a/make/Makefile.common b/make/Makefile.common new file mode 100755 index 0000000..e179728 --- /dev/null +++ b/make/Makefile.common @@ -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 diff --git a/readme.md b/readme.md index 0759ee2..d87772a 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,5 @@ **Table of Contents** - - [MovieNight stream server](#movienight-stream-server) - [Build requirements](#build-requirements) - [Older Go Versions](#older-go-versions) @@ -10,6 +9,7 @@ - [Running the Container](#running-the-container) - [docker-compose](#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) - [Configuration](#configuration) @@ -21,12 +21,10 @@ replace Rabbit as the platform for watching movies with a group of people online. ## Build requirements - - Go 1.13 or newer - GNU Make ### Older Go Versions - 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) @@ -35,13 +33,18 @@ set it to the version you installed (eg, `1.14.1`). The Makefile will now use the newer version. ### 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 $ git clone https://git.mentality.rip/sjw/MovieNight.git $ cd MovieNight -$ make +$ make TARGET=windows ARCH=386 $ ./MovieNight ``` @@ -82,8 +85,11 @@ This docker-compose file will create a volume called *movienight-config* and aut #### Notes for Running Using docker-compose 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 ```text @@ -123,10 +129,11 @@ Usage of .\MovieNight.exe: host:port of the MovieNight (default ":8089") -r string host:port of the RTMP server (default ":1935") + -f string + the settings file you want to use (default "./settings.json") ``` ## Configuration - MovieNight’s configuration is controlled by `settings.json`: - `AdminPassword`: users can enter `/auth ` into chat to grant themselves @@ -166,5 +173,4 @@ MovieNight’s configuration is controlled by `settings.json`: header, to prevent caching responses. ## License - `flv.js` is Licensed under the Apache 2.0 license. This project is licened under the MIT license. diff --git a/settings.go b/settings.go index f19d288..34e6388 100644 --- a/settings.go +++ b/settings.go @@ -85,7 +85,9 @@ func LoadSettings(filename string) (*Settings, error) { } 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) } diff --git a/static/css/site.css b/static/css/site.css index 5f06b58..5604b2a 100644 --- a/static/css/site.css +++ b/static/css/site.css @@ -124,6 +124,10 @@ input[type=text] { width: 112px; } +.emote { + height: 28px; +} + .notice { color: #595959; font-size: 75%;