@@ -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+
24542542func (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