diff --git a/internal/route/main.go b/internal/route/main.go index 8b929ff..25ed7be 100644 --- a/internal/route/main.go +++ b/internal/route/main.go @@ -228,6 +228,7 @@ func RoutesProtected(r *mux.Router, bd *gorm.DB) { r.HandleFunc("/api/paths/{id:[0-9]+}/media", renders.PathMedia(bd)).Methods("GET") r.HandleFunc("/stream/{partID:[0-9]+}", renders.Stream(bd)).Methods("GET") r.HandleFunc("/media/{partID:[0-9]+}", renders.MediaDetail(bd)).Methods("GET") +r.HandleFunc("/hls/{partID:[0-9]+}/{file}", renders.HLSStream(bd)).Methods("GET") //API Scan folder diff --git a/renders/renders.go b/renders/renders.go index 8ab83dd..ddf5e7b 100644 --- a/renders/renders.go +++ b/renders/renders.go @@ -985,7 +985,7 @@ type mediaDetailView struct { Summary string DurationFmt string ThumbURL string - StreamURL string + HLSURL string // ajouté } // MediaDetail affiche la page détail + player @@ -1024,7 +1024,7 @@ func MediaDetail(db *gorm.DB) http.HandlerFunc { Summary: item.Summary, DurationFmt: strconv.FormatInt(m, 10) + ":" + fmt.Sprintf("%02d", s), ThumbURL: item.UserThumbURL, - StreamURL: "/stream/" + strconv.FormatInt(item.MediaPartID, 10), + HLSURL: fmt.Sprintf("/hls/%d/index.m3u8", partID), } } else { @@ -1098,6 +1098,49 @@ func Stream(db *gorm.DB) http.HandlerFunc { } } +// renders/media.go (ajoutez cette fonction) +func HLSStream(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // 1) identifier le média + partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64) + var part models.MediaPart + if err := db.First(&part, partID).Error; err != nil { + http.Error(w, "Média introuvable", http.StatusNotFound) + return + } + + // 2) dossier temporaire / cache + tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("hls_%d", partID)) + os.MkdirAll(tmpDir, 0755) + playlist := filepath.Join(tmpDir, "index.m3u8") + + // 3) si besoin, (re)générer l’HLS via ffmpeg + if _, err := os.Stat(playlist); os.IsNotExist(err) { + // ffmpeg -i input -c:v copy -c:a copy -f hls -hls_time 4 -hls_list_size 0 tmp/index.m3u8 + cmd := exec.CommandContext(r.Context(), + "ffmpeg", + "-i", part.File, + "-c:v", "copy", "-c:a", "copy", + "-f", "hls", + "-hls_time", "4", + "-hls_list_size", "0", + "-hls_segment_filename", filepath.Join(tmpDir, "seg%d.ts"), + playlist, + ) + if out, err := cmd.CombinedOutput(); err != nil { + log.Println("ffmpeg HLS error:", err, string(out)) + http.Error(w, "Erreur de transcodage", 500) + return + } + } + + // 4) servir le dossier HLS en statique + http.StripPrefix( + fmt.Sprintf("/hls/%d/", partID), + http.FileServer(http.Dir(tmpDir)), + ).ServeHTTP(w, r) + } +} diff --git a/templates/media_detail.pages.tmpl b/templates/media_detail.pages.tmpl index b515c3c..d03fd9e 100644 --- a/templates/media_detail.pages.tmpl +++ b/templates/media_detail.pages.tmpl @@ -1,14 +1,39 @@
{{.}}
- {{end}} - {{with .item.DurationFmt}} - {{.}} - {{end}} + {{with .item.Summary}}{{.}}
{{end}} + {{with .item.DurationFmt}}{{.}}{{end}}