Compare commits

..

22 commits

Author SHA1 Message Date
coon 1b694b3a9e static: add custom style to range input control 2023-12-02 18:15:55 +01:00
coon c6cd31423d static: add shiny borders to bottom controls 2023-12-02 18:15:55 +01:00
coon 56dc5f3ca9 static: adjust sanic logo 2023-12-02 18:15:55 +01:00
coon a07a7a65a4 static: add gradient background for top controls 2023-12-02 18:15:55 +01:00
coon 49c1ba5ea0 static: add table header gradient 2023-12-02 18:15:55 +01:00
coon e6578d4ba1 static: comment out dashed debug boarder for div containers 2023-12-02 18:15:54 +01:00
coon 383fea7cb7 static: use different font 2023-12-02 18:15:54 +01:00
coon 8a6c4c0567 static: add playback arrow image + red highlight background color 2023-12-02 18:15:54 +01:00
coon c633905561 static: some formatting on table entries 2023-12-02 18:15:54 +01:00
coon 4d10f41ffe static: add playback arrow to position row 2023-12-02 18:15:54 +01:00
coon 88179a5f8b static: use "old school" way for alternate coloring of tables 2023-12-02 18:15:52 +01:00
coon a3faf4423e static: use different color for footer 2023-12-02 18:14:05 +01:00
coon bcdcc2750d static: use alternating colors on table 2023-12-02 18:14:05 +01:00
coon 21f1acb699 static: make tables occupy whole width 2023-12-02 18:14:03 +01:00
coon e50e54e8d8 static: add basic file tree view 2023-12-02 18:13:04 +01:00
coon 3b3e95bd7a static: w3c compliance stuff 2023-12-02 18:13:04 +01:00
coon 30ce2e6a52 static: add dummy track lists for queue and playlist tracklist 2023-12-02 18:13:03 +01:00
coon 292e4b1d63 static: index.html: add playlist_controls + playlist_tracklist div containers 2023-12-02 18:13:03 +01:00
coon ff93d57e28 static: work on basic layout + top controls 2023-12-02 18:13:03 +01:00
coon 983e73adc3 static: add sanic logo image 2023-12-02 18:11:28 +01:00
coon 52e37fcacb static: start of flexbox implementation 2023-12-02 18:11:28 +01:00
XenGi 32291bccb8
added some api calls 2023-12-02 17:53:44 +01:00
5 changed files with 250 additions and 26 deletions

3
Makefile Normal file
View file

@ -0,0 +1,3 @@
mpd:
mkdir -p /tmp/sanic/{music,playlists}
mpd --no-daemon ./mpd.conf

20
NOTES.md Normal file
View file

@ -0,0 +1,20 @@
# mpd commands
- [x] previous track
- [x] next track
- [x] stop
- [x] play/pause
- [x] set track progress
- [x] set volume
- [x] repeat queue
- [x] shuffle queue
- [ ] set fade
- [ ] add track to queue
- [ ] rm track from queue
- [ ] move track in queue
- [ ] clear queue
- [ ] list tracks in music db
- [ ] list playlists
- [ ] save playlist
- [ ] delete playlist

View file

@ -28,11 +28,11 @@
]
},
"locked": {
"lastModified": 1694616124,
"narHash": "sha256-c49BVhQKw3XDRgt+y+uPAbArtgUlMXCET6VxEBmzHXE=",
"lastModified": 1699950847,
"narHash": "sha256-xN/yVtqHb7kimHA/WvQFrEG5WS38t0K+A/W+j/WhQWM=",
"owner": "tweag",
"repo": "gomod2nix",
"rev": "f95720e89af6165c8c0aa77f180461fe786f3c21",
"rev": "05c993c9a5bd55a629cd45ed49951557b7e9c61a",
"type": "github"
},
"original": {
@ -43,11 +43,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1697915759,
"narHash": "sha256-WyMj5jGcecD+KC8gEs+wFth1J1wjisZf8kVZH13f1Zo=",
"lastModified": 1701237617,
"narHash": "sha256-Ryd8xpNDY9MJnBFDYhB37XSFIxCPVVVXAbInNPa95vs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "51d906d2341c9e866e48c2efcaac0f2d70bfd43e",
"rev": "85306ef2470ba705c97ce72741d56e42d0264015",
"type": "github"
},
"original": {

214
server.go
View file

@ -1,13 +1,17 @@
package main
import (
"fmt"
"github.com/fhs/gompd/v2/mpd"
"github.com/labstack/echo-contrib/echoprometheus"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"golang.org/x/net/websocket"
"log"
"net/http"
"strconv"
"strings"
"github.com/labstack/echo/v4"
"time"
)
func main() {
@ -25,6 +29,7 @@ func main() {
e.GET("/metrics", echoprometheus.NewHandler())
e.GET("/", func(c echo.Context) (err error) {
// HTTP/2 Server Push
pusher, ok := c.Response().Writer.(http.Pusher)
if ok {
if err = pusher.Push("/style.css", nil); err != nil {
@ -40,6 +45,17 @@ func main() {
return c.File("index.html")
})
g := e.Group("/api")
g.GET("/previous_track", previousTrack)
g.GET("/next_track", nextTrack)
g.GET("/stop", stopPlayback)
g.GET("/play", resumePlayback)
g.GET("/pause", pausePlayback)
g.GET("/seek/:seconds", seek)
g.GET("/repeat", toggleRepeat)
g.GET("/random", toggleRandom)
g.GET("/volume/:level", setVolume)
e.GET("/ws", wsServe)
e.Logger.Fatal(e.StartTLS(":1323", "cert.pem", "key.pem"))
@ -47,33 +63,217 @@ func main() {
}
func wsServe(c echo.Context) error {
fmt.Println("wsServe")
websocket.Handler(func(ws *websocket.Conn) {
defer ws.Close()
fmt.Println("handler")
for {
// Read
msg := ""
err := websocket.Message.Receive(ws, &msg)
if err != nil {
c.Logger().Error(err)
}
// Forward MPD communication
break
} else {
if strings.HasPrefix(strings.ToUpper(msg), "MPD#") {
// Forward MPD communication
// TODO: forward request to mpd and response back to client
err := websocket.Message.Send(ws, "MPD command received, processing... processing...")
if err != nil {
c.Logger().Error(err)
}
}
} else if strings.HasPrefix(strings.ToUpper(msg), "YT#") {
// Download video link as audio file
if strings.HasPrefix(strings.ToUpper(msg), "YT#") {
// TODO: implement yt-dlp integration
err := websocket.Message.Send(ws, "YT-DLP command received, processing... processing...")
if err != nil {
c.Logger().Error(err)
}
}
//fmt.Printf("%s\n", msg)
}
//fmt.Println(msg)
}
}).ServeHTTP(c.Response(), c.Request())
return nil
}
// API calls
func previousTrack(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
err = conn.Previous()
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func nextTrack(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
err = conn.Next()
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func stopPlayback(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
err = conn.Stop()
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func resumePlayback(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
err = conn.Pause(false)
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func pausePlayback(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
err = conn.Pause(true)
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func seek(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
seconds, err := strconv.Atoi(c.Param("seconds"))
if err != nil {
log.Fatalln(err)
}
if seconds < 0 {
return c.String(http.StatusBadRequest, "seconds must be positive integer")
}
err = conn.SeekCur(time.Duration(seconds)*time.Second, false)
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func toggleRepeat(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
status, err := conn.Status()
if err != nil {
log.Fatalln(err)
}
if status["repeat"] == "1" {
err = conn.Repeat(false)
} else {
err = conn.Repeat(true)
}
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func toggleRandom(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
status, err := conn.Status()
if err != nil {
log.Fatalln(err)
}
if status["toggleRandom"] == "1" {
err = conn.Random(false)
} else {
err = conn.Random(true)
}
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}
func setVolume(c echo.Context) error {
// Connect to MPD server
conn, err := mpd.Dial("tcp", "localhost:6600")
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
level, err := strconv.Atoi(c.Param("level"))
if err != nil {
log.Fatalln(err)
}
if level > 100 || level < 0 {
return c.String(http.StatusBadRequest, "Volume must be between 0 and 100")
}
err = conn.SetVolume(level)
if err != nil {
log.Fatalln(err)
}
return c.String(http.StatusNoContent, "")
}

View file

@ -53,8 +53,8 @@ td {
}
/* This is probably a better way to generate alternate coloring on tables. However,
background color for selected track is overwritten this way. Therefore the old
schoon way of alternate coloring is used for now.
background color for selected track is overwritten this way. Therefore the "old
school" way of alternate coloring is used for now.
table tr:nth-child(odd) td {
background:#1e1f1a;
@ -185,6 +185,7 @@ td.playing {
#playlist_controls {
background-color: #171812;;
/* flex-grow: 1; */
width: 20%; /* frickel? */
border-right: 4px ridge #3a506b;
}