This commit is contained in:
cangui 2025-06-21 19:50:12 +02:00
parent aa2433bee8
commit 12e9c11536

View File

@ -1057,7 +1057,7 @@ func MediaDetail(db *gorm.DB) http.HandlerFunc {
DurationFmt: "", // on ne probe pas ici DurationFmt: "", // on ne probe pas ici
ThumbURL: "/static/thumbs/" + base + ".jpg", ThumbURL: "/static/thumbs/" + base + ".jpg",
// on passe le path en query pour le streaming // on passe le path en query pour le streaming
HLSURL: fmt.Sprintf("/hls/%d/index.m3u8", partID), HLSURL: "/hls/0/index.m3u8?path=" + url.QueryEscape(path),
} }
} }
@ -1101,25 +1101,38 @@ func Stream(db *gorm.DB) http.HandlerFunc {
// renders/media.go (ajoutez cette fonction) // renders/media.go (ajoutez cette fonction)
func HLSStream(db *gorm.DB) http.HandlerFunc { func HLSStream(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// 1) identifier le média vars := mux.Vars(r)
partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64) partID, _ := strconv.ParseInt(vars["partID"], 10, 64)
var part models.MediaPart
if err := db.First(&part, partID).Error; err != nil { // Déterminer le fichier source
http.Error(w, "Média introuvable", http.StatusNotFound) var filePath string
return if partID > 0 {
// cas BDD
var part models.MediaPart
if err := db.First(&part, partID).Error; err != nil {
http.Error(w, "Média introuvable", http.StatusNotFound)
return
}
filePath = part.File
} else {
// cas FS-only
filePath = r.URL.Query().Get("path")
if filePath == "" {
http.Error(w, "Média introuvable", http.StatusNotFound)
return
}
} }
// 2) dossier temporaire / cache // Préparer le dossier de cache HLS
tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("hls_%d", partID)) tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("hls_%d", partID))
os.MkdirAll(tmpDir, 0755) os.MkdirAll(tmpDir, 0755)
playlist := filepath.Join(tmpDir, "index.m3u8") playlist := filepath.Join(tmpDir, "index.m3u8")
// 3) si besoin, (re)générer lHLS via ffmpeg // (Re)générer si nécessaire
if _, err := os.Stat(playlist); os.IsNotExist(err) { 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(), cmd := exec.CommandContext(r.Context(),
"ffmpeg", "ffmpeg",
"-i", part.File, "-i", filePath,
"-c:v", "copy", "-c:a", "copy", "-c:v", "copy", "-c:a", "copy",
"-f", "hls", "-f", "hls",
"-hls_time", "4", "-hls_time", "4",
@ -1129,14 +1142,14 @@ func HLSStream(db *gorm.DB) http.HandlerFunc {
) )
if out, err := cmd.CombinedOutput(); err != nil { if out, err := cmd.CombinedOutput(); err != nil {
log.Println("ffmpeg HLS error:", err, string(out)) log.Println("ffmpeg HLS error:", err, string(out))
http.Error(w, "Erreur de transcodage", 500) http.Error(w, "Erreur de transcodage", http.StatusInternalServerError)
return return
} }
} }
// 4) servir le dossier HLS en statique // Servir le dossier HLS
http.StripPrefix( prefix := fmt.Sprintf("/hls/%d/", partID)
fmt.Sprintf("/hls/%d/", partID), http.StripPrefix(prefix,
http.FileServer(http.Dir(tmpDir)), http.FileServer(http.Dir(tmpDir)),
).ServeHTTP(w, r) ).ServeHTTP(w, r)
} }
@ -1145,6 +1158,7 @@ func HLSStream(db *gorm.DB) http.HandlerFunc {
func renderPartial(w http.ResponseWriter, templ string, data map[string]interface{}) { func renderPartial(w http.ResponseWriter, templ string, data map[string]interface{}) {
// Exécute directement le define `<templ>.pages.tmpl` // Exécute directement le define `<templ>.pages.tmpl`
if err := templates.ExecuteTemplate(w, templ+".pages.tmpl", data); err != nil { if err := templates.ExecuteTemplate(w, templ+".pages.tmpl", data); err != nil {