Skip to content

Commit 65205f4

Browse files
author
Datanoise
committed
feat: recursive library browser, edit AutoDJ settings, and bug fixes
1 parent 6521b43 commit 65205f4

4 files changed

Lines changed: 222 additions & 37 deletions

File tree

relay/mpd.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,29 @@ import (
1111
)
1212

1313
type MPDServer struct {
14-
addr string
14+
Port string
1515
streamer *Streamer
1616
listener net.Listener
1717
}
1818

19-
func NewMPDServer(addr string, s *Streamer) *MPDServer {
19+
func NewMPDServer(port string, s *Streamer) *MPDServer {
2020
return &MPDServer{
21-
addr: addr,
21+
Port: port,
2222
streamer: s,
2323
}
2424
}
2525

2626
func (m *MPDServer) Start() error {
27-
l, err := net.Listen("tcp", m.addr)
27+
addr := m.Port
28+
if !strings.Contains(addr, ":") {
29+
addr = ":" + addr
30+
}
31+
l, err := net.Listen("tcp", addr)
2832
if err != nil {
2933
return err
3034
}
3135
m.listener = l
32-
logrus.Infof("MPD Server listening on %s", m.addr)
36+
logrus.Infof("MPD Server listening on %s", addr)
3337

3438
go func() {
3539
for {

relay/streamer.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,21 @@ func (s *Streamer) ScanMusicDir() error {
148148
return fmt.Errorf("music directory not configured")
149149
}
150150

151-
files, err := os.ReadDir(s.MusicDir)
152-
if err != nil {
153-
return err
154-
}
155-
156151
s.Playlist = []string{}
157-
for _, f := range files {
158-
ext := strings.ToLower(filepath.Ext(f.Name()))
159-
if !f.IsDir() && ext == ".mp3" {
160-
s.Playlist = append(s.Playlist, filepath.Join(s.MusicDir, f.Name()))
152+
err := filepath.Walk(s.MusicDir, func(path string, info os.FileInfo, err error) error {
153+
if err != nil {
154+
return err
161155
}
162-
}
163-
return nil
156+
if !info.IsDir() {
157+
ext := strings.ToLower(filepath.Ext(path))
158+
if ext == ".mp3" {
159+
absPath, _ := filepath.Abs(path)
160+
s.Playlist = append(s.Playlist, absPath)
161+
}
162+
}
163+
return nil
164+
})
165+
return err
164166
}
165167

166168
func (s *Streamer) GetMusicDir() string {

server/server.go

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ func (s *Server) setupRoutes() *http.ServeMux {
273273
mux.HandleFunc("/admin/autodj/add", s.handleAddAutoDJ)
274274
mux.HandleFunc("/admin/autodj/delete", s.handleDeleteAutoDJ)
275275
mux.HandleFunc("/admin/autodj/toggle", s.handleToggleAutoDJ)
276+
mux.HandleFunc("/admin/autodj/update", s.handleUpdateAutoDJ)
276277
mux.HandleFunc("/admin/add-relay", s.handleAddRelay)
277278
mux.HandleFunc("/admin/toggle-relay", s.handleToggleRelay)
278279
mux.HandleFunc("/admin/restart-relay", s.handleRestartRelay)
@@ -2385,24 +2386,36 @@ func (s *Server) handlePlayerFiles(w http.ResponseWriter, r *http.Request) {
23852386
}
23862387

23872388
mount := r.URL.Query().Get("mount")
2389+
subDir := r.URL.Query().Get("path")
23882390
streamer := s.StreamerM.GetStreamer(mount)
23892391
if streamer == nil {
23902392
http.Error(w, "Streamer not found", http.StatusNotFound)
23912393
return
23922394
}
23932395

23942396
musicDir := streamer.GetMusicDir()
2397+
fullPath := filepath.Join(musicDir, subDir)
23952398

2396-
files, err := os.ReadDir(musicDir)
2399+
entries, err := os.ReadDir(fullPath)
23972400
if err != nil {
23982401
http.Error(w, err.Error(), http.StatusInternalServerError)
23992402
return
24002403
}
24012404

2402-
var res []string
2403-
for _, f := range files {
2404-
if !f.IsDir() && strings.ToLower(filepath.Ext(f.Name())) == ".mp3" {
2405-
res = append(res, f.Name())
2405+
type fileEntry struct {
2406+
Name string `json:"name"`
2407+
IsDir bool `json:"is_dir"`
2408+
Path string `json:"path"`
2409+
}
2410+
var res []fileEntry
2411+
for _, f := range entries {
2412+
ext := strings.ToLower(filepath.Ext(f.Name()))
2413+
if f.IsDir() || ext == ".mp3" {
2414+
res = append(res, fileEntry{
2415+
Name: f.Name(),
2416+
IsDir: f.IsDir(),
2417+
Path: filepath.Join(subDir, f.Name()),
2418+
})
24062419
}
24072420
}
24082421

@@ -2421,7 +2434,7 @@ func (s *Server) handlePlayerPlaylistAction(w http.ResponseWriter, r *http.Reque
24212434

24222435
mount := r.FormValue("mount")
24232436
action := r.FormValue("action")
2424-
fileName := r.FormValue("file")
2437+
relPath := r.FormValue("file")
24252438

24262439
streamer := s.StreamerM.GetStreamer(mount)
24272440
if streamer == nil {
@@ -2430,8 +2443,23 @@ func (s *Server) handlePlayerPlaylistAction(w http.ResponseWriter, r *http.Reque
24302443
}
24312444

24322445
if action == "add" {
2433-
fullPath := filepath.Join(streamer.GetMusicDir(), fileName)
2434-
streamer.AddToPlaylist(fullPath)
2446+
fullPath := filepath.Join(streamer.GetMusicDir(), relPath)
2447+
info, err := os.Stat(fullPath)
2448+
if err == nil {
2449+
if info.IsDir() {
2450+
// Add folder recursively
2451+
filepath.Walk(fullPath, func(p string, i os.FileInfo, e error) error {
2452+
if e == nil && !i.IsDir() && strings.ToLower(filepath.Ext(p)) == ".mp3" {
2453+
abs, _ := filepath.Abs(p)
2454+
streamer.AddToPlaylist(abs)
2455+
}
2456+
return nil
2457+
})
2458+
} else {
2459+
abs, _ := filepath.Abs(fullPath)
2460+
streamer.AddToPlaylist(abs)
2461+
}
2462+
}
24352463
} else if action == "remove" {
24362464
var idx int
24372465
fmt.Sscanf(r.FormValue("index"), "%d", &idx)
@@ -2451,6 +2479,66 @@ func (s *Server) handlePlayerPlaylistAction(w http.ResponseWriter, r *http.Reque
24512479
http.Redirect(w, r, "/admin#tab-streamer", http.StatusSeeOther)
24522480
}
24532481

2482+
func (s *Server) handleUpdateAutoDJ(w http.ResponseWriter, r *http.Request) {
2483+
if !s.isCSRFSafe(r) {
2484+
http.Error(w, "Forbidden", http.StatusForbidden)
2485+
return
2486+
}
2487+
if _, ok := s.checkAuth(r); !ok {
2488+
return
2489+
}
2490+
2491+
oldMount := r.FormValue("old_mount")
2492+
name := r.FormValue("name")
2493+
newMount := r.FormValue("mount")
2494+
musicDir := r.FormValue("music_dir")
2495+
format := r.FormValue("format")
2496+
bitrateStr := r.FormValue("bitrate")
2497+
loop := r.FormValue("loop") == "on"
2498+
injectMetadata := r.FormValue("inject_metadata") == "on"
2499+
mpdEnabled := r.FormValue("mpd_enabled") == "on"
2500+
mpdPort := r.FormValue("mpd_port")
2501+
2502+
if name == "" || newMount == "" || musicDir == "" {
2503+
http.Error(w, "Name, mount, and music directory are required", http.StatusBadRequest)
2504+
return
2505+
}
2506+
2507+
if newMount[0] != '/' {
2508+
newMount = "/" + newMount
2509+
}
2510+
2511+
bitrate := 128
2512+
fmt.Sscanf(bitrateStr, "%d", &bitrate)
2513+
2514+
for _, adj := range s.Config.AutoDJs {
2515+
if adj.Mount == oldMount {
2516+
adj.Name = name
2517+
adj.Mount = newMount
2518+
adj.MusicDir = musicDir
2519+
adj.Format = format
2520+
adj.Bitrate = bitrate
2521+
adj.Loop = loop
2522+
adj.InjectMetadata = injectMetadata
2523+
adj.MPDEnabled = mpdEnabled
2524+
adj.MPDPort = mpdPort
2525+
2526+
// Restart streamer
2527+
s.StreamerM.StopStreamer(oldMount)
2528+
if adj.Enabled {
2529+
streamer, err := s.StreamerM.StartStreamer(adj.Name, adj.Mount, adj.MusicDir, adj.Loop, adj.Format, adj.Bitrate, adj.InjectMetadata, adj.Playlist, adj.MPDEnabled, adj.MPDPort)
2530+
if err == nil {
2531+
streamer.Play()
2532+
}
2533+
}
2534+
break
2535+
}
2536+
}
2537+
2538+
s.Config.SaveConfig()
2539+
http.Redirect(w, r, "/admin#tab-streamer", http.StatusSeeOther)
2540+
}
2541+
24542542
func (s *Server) handleGetStats(w http.ResponseWriter, r *http.Request) {
24552543
if _, ok := s.checkAuth(r); !ok {
24562544
http.Error(w, "Unauthorized", http.StatusUnauthorized)

0 commit comments

Comments
 (0)