From 27032d75a5ae44a94b2a461a2dcdbe35203139a7 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Mon, 21 Nov 2022 00:37:49 +0100 Subject: [PATCH 1/8] Add makefile, clean up some docker stuff --- .gitignore | 3 ++- Dockerfile | 4 +--- Makefile | 15 +++++++++++++++ routes.go | 2 +- package.json => src/package.json | 2 +- {js => src}/script.js | 6 +++--- yarn.lock => src/yarn.lock | 0 7 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 Makefile rename package.json => src/package.json (69%) rename {js => src}/script.js (98%) rename yarn.lock => src/yarn.lock (100%) diff --git a/.gitignore b/.gitignore index f4dac66..b8cbb8a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,9 @@ js/*.min.js cache bin -ambiance/*.mp3 +ambiance *.yml public/ node_modules/ +src/node_modules diff --git a/Dockerfile b/Dockerfile index 28d6007..40f34a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,6 @@ FROM node:19-alpine3.16 WORKDIR /app -COPY . /app - RUN yarn -ENTRYPOINT ["yarn", "build"] +ENTRYPOINT ["yarn"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1bc2f29 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +APPLICATION_NAME ?= dndmusicbot +CURRENT_UID := $(shell id -u) + +default: build + +image: Dockerfile + docker build -t dndmusicbot-js-build . + touch .jsimage + +web: src/script.js + docker run --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build install + docker run --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build build + +build: *.go + go build \ No newline at end of file diff --git a/routes.go b/routes.go index 4417393..097a996 100644 --- a/routes.go +++ b/routes.go @@ -22,7 +22,7 @@ func init() { app.router.GET("/play/:playlist", app.Play) app.router.GET("/reset", app.Reset) - app.router.ServeFiles("/js/*filepath", http.Dir("public")) + app.router.ServeFiles("/js/*filepath", http.Dir("src/public")) app.router.ServeFiles("/css/*filepath", http.Dir("css")) app.router.HandlerFunc("GET", "/ws", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/package.json b/src/package.json similarity index 69% rename from package.json rename to src/package.json index b509036..474d185 100644 --- a/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "scripts": { - "build": "esbuild js/script.js --bundle --outdir=public/" + "build": "esbuild script.js --bundle --outdir=public/" }, "dependencies": { "esbuild": "^0.15.14", diff --git a/js/script.js b/src/script.js similarity index 98% rename from js/script.js rename to src/script.js index 75baa7f..e49782a 100644 --- a/js/script.js +++ b/src/script.js @@ -130,11 +130,11 @@ window.onload = function () { document.querySelector("#addambiance").addEventListener("click", (e) => { e.preventDefault() - output.innerText = "" + //output.innerText = "" var title = document.querySelector("#inputambiance > input[name='title']") var url = document.querySelector("#inputambiance > input[name='url']") if (title.value == "" || url.value == "") { - output.innerText = "Title or Url is empty!" + console.log("Title or Url is empty!") return } @@ -150,7 +150,7 @@ window.onload = function () { submit.addEventListener("click", (e) => { e.preventDefault() - output.innerText = "" + //output.innerText = "" var title = document.querySelector("#inputplaylist > input[name='title']") var url = document.querySelector("#inputplaylist > input[name='url']") if (title.value == "" || url.value == "") { diff --git a/yarn.lock b/src/yarn.lock similarity index 100% rename from yarn.lock rename to src/yarn.lock From 87b76ecd8a43c41e43a741f1a19eac50c666a946 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Mon, 21 Nov 2022 08:30:02 +0100 Subject: [PATCH 2/8] Make the Makefile functional --- Makefile | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 1bc2f29..14cd55f 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,27 @@ APPLICATION_NAME ?= dndmusicbot CURRENT_UID := $(shell id -u) +BIN := src/node_modules/.bin default: build -image: Dockerfile - docker build -t dndmusicbot-js-build . - touch .jsimage +PHONY: js image build -web: src/script.js - docker run --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build install - docker run --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build build +js: src/public/script.js -build: *.go - go build \ No newline at end of file +image: .jsimage + +.jsimage: Dockerfile + @docker build -t dndmusicbot-js-build . + @touch .jsimage + +src/yarn.lock: src/node_modules src/package.json + @docker run --rm --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build install --production=false --check-files + @touch -mr $(shell ls -Atd $? | head -1) $@ + +src/public/script.js: src/script.js src/yarn.lock + @docker run --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build build + +$(APPLICATION_NAME): *.go ffmpeg/*.go speaker/*.go + @go build + +build: image js $(APPLICATION_NAME) \ No newline at end of file From da00ab1b6643fdeee3cbf4f1d0f52c45e0d0e274 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Mon, 21 Nov 2022 09:09:01 +0100 Subject: [PATCH 3/8] Fix default target --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 14cd55f..48a9012 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ +.DEFAULT_GOAL := build APPLICATION_NAME ?= dndmusicbot CURRENT_UID := $(shell id -u) BIN := src/node_modules/.bin -default: build - PHONY: js image build js: src/public/script.js @@ -24,4 +23,4 @@ src/public/script.js: src/script.js src/yarn.lock $(APPLICATION_NAME): *.go ffmpeg/*.go speaker/*.go @go build -build: image js $(APPLICATION_NAME) \ No newline at end of file +build: image js $(APPLICATION_NAME) From 8727594413365c249c312ab5db10f123ca437d53 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Mon, 21 Nov 2022 12:26:33 +0100 Subject: [PATCH 4/8] move everything into public instead of src/public --- Dockerfile | 4 ++-- Makefile | 17 ++++++++++++----- routes.go | 2 +- src/package.json | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 40f34a4..3c3bb5c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,8 +2,8 @@ # docker run -it -v $(pwd)/public:/app/public dndmusicbot-js-build FROM node:19-alpine3.16 +RUN mkdir /public && chmod 777 /public + WORKDIR /app -RUN yarn - ENTRYPOINT ["yarn"] diff --git a/Makefile b/Makefile index 48a9012..baaa8c1 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,11 @@ APPLICATION_NAME ?= dndmusicbot CURRENT_UID := $(shell id -u) BIN := src/node_modules/.bin +YARN = docker run --rm --user $(CURRENT_UID) -v $(CURDIR)/src:/app -v $(CURDIR)/public:/public dndmusicbot-js-build -PHONY: js image build +PHONY: js image build clean -js: src/public/script.js +js: image public/script.js image: .jsimage @@ -13,14 +14,20 @@ image: .jsimage @docker build -t dndmusicbot-js-build . @touch .jsimage +src/node_modules: + mkdir -p $@ + src/yarn.lock: src/node_modules src/package.json - @docker run --rm --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build install --production=false --check-files + $(YARN) @touch -mr $(shell ls -Atd $? | head -1) $@ -src/public/script.js: src/script.js src/yarn.lock - @docker run --user $(CURRENT_UID) -v $(CURDIR)/src:/app dndmusicbot-js-build build +public/script.js: src/script.js src/yarn.lock + $(YARN) build $(APPLICATION_NAME): *.go ffmpeg/*.go speaker/*.go @go build build: image js $(APPLICATION_NAME) + +clean: + rm -r public/* src/node_modules .jsimage $(APPLICATION_NAME) diff --git a/routes.go b/routes.go index 097a996..4417393 100644 --- a/routes.go +++ b/routes.go @@ -22,7 +22,7 @@ func init() { app.router.GET("/play/:playlist", app.Play) app.router.GET("/reset", app.Reset) - app.router.ServeFiles("/js/*filepath", http.Dir("src/public")) + app.router.ServeFiles("/js/*filepath", http.Dir("public")) app.router.ServeFiles("/css/*filepath", http.Dir("css")) app.router.HandlerFunc("GET", "/ws", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/src/package.json b/src/package.json index 474d185..5e65b04 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "scripts": { - "build": "esbuild script.js --bundle --outdir=public/" + "build": "esbuild script.js --bundle --outdir=/public/" }, "dependencies": { "esbuild": "^0.15.14", From 8ccc426618c9be5a274481c945c5a7f39bf51836 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Mon, 21 Nov 2022 12:28:52 +0100 Subject: [PATCH 5/8] Make sure public is created before docker is run or else it will be owned by root --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index baaa8c1..9319431 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,10 @@ image: .jsimage src/node_modules: mkdir -p $@ -src/yarn.lock: src/node_modules src/package.json +public: + mkdir -p $@ + +src/yarn.lock: public src/node_modules src/package.json $(YARN) @touch -mr $(shell ls -Atd $? | head -1) $@ From cbd1749367212d82a1c067f675b3f8b4a2502959 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Mon, 21 Nov 2022 23:49:43 +0100 Subject: [PATCH 6/8] Fix youtube api paging --- youtube.go | 1 + 1 file changed, 1 insertion(+) diff --git a/youtube.go b/youtube.go index c7d1590..885018e 100644 --- a/youtube.go +++ b/youtube.go @@ -150,6 +150,7 @@ func (app App) Playlist(playlist string) ([]string, error) { if pageToken == "" { break } + call.PageToken(pageToken) } return list, nil } From 02bceabbacc26b97721c638809a587ddd63b8864 Mon Sep 17 00:00:00 2001 From: Trond A Ekseth Date: Mon, 21 Nov 2022 23:52:07 +0100 Subject: [PATCH 7/8] Handle touch input in chrome mobile --- css/style.css | 5 ++++ src/script.js | 67 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/css/style.css b/css/style.css index 3abc00c..b7b4089 100644 --- a/css/style.css +++ b/css/style.css @@ -28,6 +28,11 @@ h2.bot { } .item { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: flex; justify-content: center; align-items: center; diff --git a/src/script.js b/src/script.js index e49782a..1b44733 100644 --- a/src/script.js +++ b/src/script.js @@ -1,6 +1,29 @@ import ReconnectingWebSocket from 'reconnecting-websocket'; import Sortable from 'sortablejs'; +const DND_DELAY = 300; + +const addInteractHandler = (source, handler) => { + source.addEventListener("click", e => { + console.log("click", e); + handler(e, false); + }); + + let touchStart; + source.addEventListener("touchstart", e => { + console.log("touch start", touchStart, e.timeStamp, e); + touchStart = e.timeStamp; + }, {passive: true}) + + source.addEventListener("touchend", e => { + console.log("touch end", touchStart, e); + console.log(e.timeStamp - touchStart) + if ((e.timeStamp - touchStart) < DND_DELAY) { + handler(e, true); + } + }, {passive: true}); +} + window.onload = function () { const ws = new ReconnectingWebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/ws"); @@ -13,19 +36,22 @@ window.onload = function () { const time = document.querySelector("#time") const waiting = document.querySelector("#waiting") - document.querySelector("input#next").addEventListener("click", (e) => { - ws.send(JSON.stringify({ - "event": "next" - })) - }) + addInteractHandler( + document.querySelector("input#next"), (e) => { + ws.send(JSON.stringify({ + "event": "next" + })) + }) - document.querySelector("input#prev").addEventListener("click", (e) => { - ws.send(JSON.stringify({ - "event": "prev" - })) - }) + addInteractHandler( + document.querySelector("input#prev"), (e) => { + ws.send(JSON.stringify({ + "event": "prev" + })) + }) Sortable.create(items, { + delay: DND_DELAY, delayOnTouchOnly: true, group: "dndmusicbot-playlists", filter: ".locked", @@ -48,6 +74,7 @@ window.onload = function () { }) Sortable.create(amb, { + delay: DND_DELAY, delayOnTouchOnly: true, group: "dndmusicbot-ambiance", filter: ".locked", @@ -127,8 +154,8 @@ window.onload = function () { } } - document.querySelector("#addambiance").addEventListener("click", (e) => { - e.preventDefault() + addInteractHandler(document.querySelector("#addambiance"), (e, isTouch) => { + isTouch && e.preventDefault() //output.innerText = "" var title = document.querySelector("#inputambiance > input[name='title']") @@ -147,8 +174,8 @@ window.onload = function () { })) }) - submit.addEventListener("click", (e) => { - e.preventDefault() + addInteractHandler(submit, (e, isTouch) => { + isTouch && e.preventDefault() //output.innerText = "" var title = document.querySelector("#inputplaylist > input[name='title']") @@ -170,8 +197,8 @@ window.onload = function () { url.innerText = "" }) - document.querySelectorAll("#items .item").forEach(item => item.addEventListener("click", (e) => { - e.preventDefault() + document.querySelectorAll("#items .item").forEach(item => addInteractHandler(item, (e, isTouch) => { + isTouch && e.preventDefault() e.target.parentElement.style.pointerEvents = 'none' const disableui = setTimeout((t) => { t.style.pointerEvents = 'auto' @@ -184,8 +211,8 @@ window.onload = function () { })) })); - document.querySelectorAll("#ambiance .item").forEach(item => item.addEventListener("click", (e) => { - e.preventDefault() + document.querySelectorAll("#ambiance .item").forEach(item => addInteractHandler(item, (e, isTouch) => { + isTouch && e.preventDefault() e.target.parentElement.style.pointerEvents = 'none' const disableui = setTimeout((t) => { t.style.pointerEvents = 'auto' @@ -205,8 +232,8 @@ function addPlaylist(payload) { newdiv.className = "item" newdiv.dataset.id = payload.url newdiv.innerText = payload.title - newdiv.addEventListener("click", (e) => { - e.preventDefault() + addInteractHandler(newdiv, (e, isTouch) => { + isTouch && e.preventDefault() var id = e.target.dataset.id ws.send(JSON.stringify({ From 4b45d14c68794e2bf665f3ce73f1c7dda355a8e5 Mon Sep 17 00:00:00 2001 From: Stein Ivar Berghei Date: Tue, 22 Nov 2022 00:33:43 +0100 Subject: [PATCH 8/8] Serve files with servecontent so that ETags etc should work. --- routes.go | 30 +++++++++++++++++++++++++++--- tmpl/index.tmpl | 2 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/routes.go b/routes.go index 4417393..190056a 100644 --- a/routes.go +++ b/routes.go @@ -3,6 +3,9 @@ package main import ( "log" "net/http" + "os" + "path" + "path/filepath" "text/template" "github.com/google/uuid" @@ -21,9 +24,8 @@ func init() { app.router.GET("/", app.Index) app.router.GET("/play/:playlist", app.Play) app.router.GET("/reset", app.Reset) - - app.router.ServeFiles("/js/*filepath", http.Dir("public")) - app.router.ServeFiles("/css/*filepath", http.Dir("css")) + app.router.GET("/public/*js", app.ServeFiles) + app.router.GET("/css/*css", app.ServeFiles) app.router.HandlerFunc("GET", "/ws", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("WS connection from %v\n", r.RemoteAddr) @@ -49,6 +51,28 @@ type IndexData struct { Ambiance []string } +func (app App) ServeFiles(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + filePath := filepath.Join(".", r.URL.Path) + + file, err := os.Open(filePath) + if err != nil { + log.Println(err) + http.Error(w, "no such file", http.StatusNotFound) + return + } + defer file.Close() + + fileStat, err := os.Stat(filePath) + if err != nil { + log.Println(err) + http.Error(w, "unable to get file stat", http.StatusInternalServerError) + } + + _, filename := path.Split(filePath) + t := fileStat.ModTime() + http.ServeContent(w, r, filename, t, file) +} + func (app App) Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { playlists, err := app.GetPlaylists() if err != nil { diff --git a/tmpl/index.tmpl b/tmpl/index.tmpl index 8c436a7..e3ffd0f 100644 --- a/tmpl/index.tmpl +++ b/tmpl/index.tmpl @@ -74,6 +74,6 @@ - +