diff --git a/internal/route/main.go b/internal/route/main.go index 7dd62c5..3f745e7 100644 --- a/internal/route/main.go +++ b/internal/route/main.go @@ -14,6 +14,7 @@ import ( "github.com/gorilla/mux" "gorm.io/gorm" ) + type spaHandler struct { staticPath string indexPath string @@ -22,94 +23,116 @@ type spaHandler struct { // Routes non protégées func RoutesPublic(r *mux.Router, bd *gorm.DB) { - // Fichiers statiques (CSS, JS, etc.) - staticDir := "./templates/assets/" - r.PathPrefix("/templates/assets/").Handler( - http.StripPrefix("/templates/assets/", http.FileServer(http.Dir(staticDir))), - ) + // Fichiers statiques (CSS, JS, etc.) + staticDir := "./templates/assets/" + r.PathPrefix("/templates/assets/").Handler( + http.StripPrefix("/templates/assets/", http.FileServer(http.Dir(staticDir))), + ) - // Page de login - r.HandleFunc("/login", renders.Login) + // Page de login + r.HandleFunc("/login", renders.Login) - // Endpoint d'API pour se logger - r.HandleFunc("/api/login", login.LoginHandler(bd)).Methods("POST") - r.HandleFunc("/api/scan/{id}", library.ScanFolder(bd)).Methods("GET") - r.HandleFunc("/api/download/stream", renders.HandleJobsStream(bd)) + // Endpoint d'API pour se logger + r.HandleFunc("/api/login", login.LoginHandler(bd)).Methods("POST") + r.HandleFunc("/api/scan/{id}", library.ScanFolder(bd)).Methods("GET") + r.HandleFunc("/api/download/stream", renders.HandleJobsStream(bd)) + r.HandleFunc("/playlist.m3u", func(w http.ResponseWriter, r *http.Request) { + uploadDir := "/app/upload" + + w.Header().Set("Content-Type", "audio/x-mpegurl") + fmt.Fprintln(w, "#EXTM3U") + + err := filepath.Walk(uploadDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + // On construit l'URL HTTP complète + relPath, _ := filepath.Rel(uploadDir, path) + // Important : remplacer \ par / pour Windows + relPath = filepath.ToSlash(relPath) + fileURL := fmt.Sprintf("http://%s:4000/upload/%s", getLocalIP(), relPath) + fmt.Fprintln(w, fileURL) + return nil + }) + + if err != nil { + http.Error(w, "Erreur lors de la génération de la playlist", http.StatusInternalServerError) + } + }) } // Routes protégées func RoutesProtected(r *mux.Router, bd *gorm.DB) { - - - // Ici on place les vues et API qui doivent être protégées + // Ici on place les vues et API qui doivent être protégées r.HandleFunc("/stream", StreamHandler) - r.HandleFunc("/dashboard", renders.Dashboard(bd)) + r.HandleFunc("/dashboard", renders.Dashboard(bd)) r.HandleFunc("/settings", renders.Settings) r.HandleFunc("/library", renders.Library) - r.HandleFunc("/menuLibary", renders.Library) - r.HandleFunc("/godownloader/downloads", renders.GoDownload) - r.HandleFunc("/godownloader/linkcollectors", renders.GoDownloadLinkCollectors) - r.HandleFunc("/godownloader/settings", renders.GoDownloadSetting(bd)) - r.HandleFunc("/godownloader/poll-status", renders.PollStatusHandler(bd)) - r.HandleFunc("/godownloader/table-refresh", renders.GoDownloadPartialTable(bd)) - r.HandleFunc("/godownloader/settings/delete", renders.GoDownloadSettingDelete(bd)) + r.HandleFunc("/menuLibary", renders.Library) + r.HandleFunc("/godownloader/downloads", renders.GoDownload) + r.HandleFunc("/godownloader/linkcollectors", renders.GoDownloadLinkCollectors) + r.HandleFunc("/godownloader/settings", renders.GoDownloadSetting(bd)) + r.HandleFunc("/godownloader/poll-status", renders.PollStatusHandler(bd)) + r.HandleFunc("/godownloader/table-refresh", renders.GoDownloadPartialTable(bd)) + r.HandleFunc("/godownloader/settings/delete", renders.GoDownloadSettingDelete(bd)) r.HandleFunc("/api/download/add", renders.HandleAddJob(bd)).Methods("POST") r.HandleFunc("/api/download/all", renders.HandleListJobsPartial(bd)).Methods("GET") - r.HandleFunc("/downloads", renders.GoDownload2(bd)) - r.HandleFunc("/stream/{id}", download.HandleStreamPage()).Methods("GET") - r.HandleFunc("/api/download/start/{id}", renders.HandleStartJob(bd)).Methods("POST") - r.HandleFunc("/api/download/pause/{id}", renders.HandlePauseJob).Methods("POST") - r.HandleFunc("/api/download/resume/{id}", renders.HandleResumeJob(bd)).Methods("POST") - r.HandleFunc("/api/download/delete/{id}", renders.HandleDeleteJob(bd)).Methods("DELETE") - r.HandleFunc("/api/download/delete-multiple", renders.HandleDeleteMultipleJobs(bd)).Methods("POST") + r.HandleFunc("/downloads", renders.GoDownload2(bd)) + r.HandleFunc("/stream/{id}", download.HandleStreamPage()).Methods("GET") + r.HandleFunc("/api/download/start/{id}", renders.HandleStartJob(bd)).Methods("POST") + r.HandleFunc("/api/download/pause/{id}", renders.HandlePauseJob).Methods("POST") + r.HandleFunc("/api/download/resume/{id}", renders.HandleResumeJob(bd)).Methods("POST") + r.HandleFunc("/api/download/delete/{id}", renders.HandleDeleteJob(bd)).Methods("DELETE") + r.HandleFunc("/api/download/delete-multiple", renders.HandleDeleteMultipleJobs(bd)).Methods("POST") + // API user + r.HandleFunc("/api/user/create", users.CreateUser(bd)).Methods("POST") + r.HandleFunc("/api/user/update/{id}", users.UpdateUser(bd)).Methods("PUT") + r.HandleFunc("/api/user/delete/{id}", users.DeleteUser(bd)).Methods("DELETE") + r.HandleFunc("/api/user/all/", users.ReadAllUser(bd)).Methods("GET") + r.HandleFunc("/api/user/{id}", users.FindUserById(bd)).Methods("GET") - // API user - r.HandleFunc("/api/user/create", users.CreateUser(bd)).Methods("POST") - r.HandleFunc("/api/user/update/{id}", users.UpdateUser(bd)).Methods("PUT") - r.HandleFunc("/api/user/delete/{id}", users.DeleteUser(bd)).Methods("DELETE") - r.HandleFunc("/api/user/all/", users.ReadAllUser(bd)).Methods("GET") - r.HandleFunc("/api/user/{id}", users.FindUserById(bd)).Methods("GET") + // API download + r.HandleFunc("/api/pathDownload/create", download.CreateSavePath(bd)).Methods("POST") + r.HandleFunc("/api/pathDownload/update/{id}", download.UpdateSavePath(bd)).Methods("PUT") + r.HandleFunc("/api/pathDownload/delete/{id}", download.DeleteSavePath(bd)).Methods("DELETE") + r.HandleFunc("/api/pathDownload/all/", download.ReadAllSavePath(bd)).Methods("GET") - // API download - r.HandleFunc("/api/pathDownload/create", download.CreateSavePath(bd)).Methods("POST") - r.HandleFunc("/api/pathDownload/update/{id}", download.UpdateSavePath(bd)).Methods("PUT") - r.HandleFunc("/api/pathDownload/delete/{id}", download.DeleteSavePath(bd)).Methods("DELETE") - r.HandleFunc("/api/pathDownload/all/", download.ReadAllSavePath(bd)).Methods("GET") - - //API Check path - r.HandleFunc("/validate-path", download.PathValidationHandler) - - //API Scan folder + //API Check path + r.HandleFunc("/validate-path", download.PathValidationHandler) + //API Scan folder } func StreamHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") - flusher, ok := w.(http.Flusher) - if !ok { - http.Error(w, "Le streaming n’est pas supporté par ce serveur", http.StatusInternalServerError) - return - } + flusher, ok := w.(http.Flusher) + if !ok { + http.Error(w, "Le streaming n’est pas supporté par ce serveur", http.StatusInternalServerError) + return + } - ticker := time.NewTicker(1 * time.Second) - defer ticker.Stop() + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() - // Boucle infinie (ou jusqu'à annulation) - for { - select { - case <-ticker.C: + // Boucle infinie (ou jusqu'à annulation) + for { + select { + case <-ticker.C: fmt.Fprintf(w, "data:

Message #%d

\n\n") - flusher.Flush() - case <-r.Context().Done(): - // Le client a probablement fermé la connexion - log.Println("Client déconnecté") - return - } - } -} \ No newline at end of file + flusher.Flush() + case <-r.Context().Done(): + // Le client a probablement fermé la connexion + log.Println("Client déconnecté") + return + } + } +} diff --git a/main.go b/main.go index 011678b..3289cd7 100644 --- a/main.go +++ b/main.go @@ -33,8 +33,8 @@ func main() { route.RoutesProtected(protected, bd) //setupPortMappingWithFallback(4000, 4000) // 6.5. Exposer le dossier upload - fs := http.StripPrefix("/upload/", http.FileServer(http.Dir("/app/upload"))) - r.PathPrefix("/upload/").Handler(fs) + // fs := http.StripPrefix("/upload/", http.FileServer(http.Dir("/app/upload"))) + // r.PathPrefix("/upload/").Handler(fs) // 7. Lancer le serveur sur le port 4000 log.Fatal(http.ListenAndServe(":4000", r))