This commit is contained in:
cangui 2025-06-21 18:58:02 +02:00
parent dddf56a2d6
commit 7f332aa88b
2 changed files with 86 additions and 24 deletions

View File

@ -980,21 +980,32 @@ func PathMedia(db *gorm.DB) http.HandlerFunc {
}) })
} }
} }
type mediaDetailView struct {
Title string
Summary string
DurationFmt string
ThumbURL string
StreamURL string
}
// MediaDetail affiche la page détail + player // MediaDetail affiche la page détail + player
func MediaDetail(db *gorm.DB) http.HandlerFunc { func MediaDetail(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// 1) Extraire le partID
partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64) partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64)
// on récupère 1 metadata + file pour ce media_part var view mediaDetailView
if partID > 0 {
// --- CAS BDD ---
var item struct { var item struct {
models.MetadataItem models.MetadataItem
MediaPartID int64 MediaPartID int64
File string File string
UserThumbURL string
} }
db.Table("metadata_items"). db.Table("metadata_items").
Select("metadata_items.*, media_parts.id AS media_part_id, media_parts.file"). Select("metadata_items.*, media_parts.id AS media_part_id, media_parts.file, metadata_items.user_thumb_url").
Joins("JOIN media_items ON media_items.metadata_item_id = metadata_items.id"). Joins("JOIN media_items ON media_items.metadata_item_id = metadata_items.id").
Joins("JOIN media_parts ON media_parts.media_item_id = media_items.id"). Joins("JOIN media_parts ON media_parts.media_item_id = media_items.id").
Where("media_parts.id = ?", partID). Where("media_parts.id = ?", partID).
@ -1005,8 +1016,54 @@ func MediaDetail(db *gorm.DB) http.HandlerFunc {
return return
} }
renderTemplate(w, "media_detail", map[string]interface{}{ // formater la durée
"item": item, m := item.Duration / 60
s := item.Duration % 60
view = mediaDetailView{
Title: item.Title,
Summary: item.Summary,
DurationFmt: strconv.FormatInt(m, 10) + ":" + fmt.Sprintf("%02d", s),
ThumbURL: item.UserThumbURL,
StreamURL: "/stream/" + strconv.FormatInt(item.MediaPartID, 10),
}
} else {
// --- CAS FS-ONLY ---
path := r.URL.Query().Get("path")
if path == "" {
http.Error(w, "Média introuvable", http.StatusNotFound)
return
}
// titre
title := filepath.Base(path)
// génère un thumbnail si besoin
ext := filepath.Ext(path)
base := strings.TrimSuffix(filepath.Base(path), ext)
thumbDir := filepath.Join("static", "thumbs")
os.MkdirAll(thumbDir, 0755)
thumbPath := filepath.Join(thumbDir, base+".jpg")
if _, err := os.Stat(thumbPath); os.IsNotExist(err) {
// screenshot au 5s
exec.CommandContext(r.Context(),
"ffmpeg", "-ss", "5", "-i", path, "-frames:v", "1", thumbPath,
).Run()
}
view = mediaDetailView{
Title: title,
Summary: "", // pas de résumé en FS-only
DurationFmt: "", // on ne probe pas ici
ThumbURL: "/static/thumbs/" + base + ".jpg",
// on passe le path en query pour le streaming
StreamURL: "/stream/0?path=" + url.QueryEscape(path),
}
}
// 3) Render partial dans #content
renderPartial(w, "media_detail", map[string]interface{}{
"item": view,
}) })
} }
} }

View File

@ -1,9 +1,14 @@
<div class="detail"> <div class="detail p-4">
<img src="{{.item.UserThumbURL}}" alt="{{.item.Title}}" class="cover"> <h1 class="text-2xl font-bold mb-4">{{.item.Title}}</h1>
<h1>{{.item.Title}}</h1> {{with .item.Summary}}
{{with .item.Summary}}<p>{{.}}</p>{{end}} <p class="mb-4">{{.}}</p>
<video controls autoplay width="100%" poster="{{.item.UserThumbURL}}"> {{end}}
<source src="/stream/{{.item.MediaPartID}}" type="video/mp4"> {{with .item.DurationFmt}}
<small class="text-gray-500">{{.}}</small>
{{end}}
<img src="{{.item.ThumbURL}}" alt="{{.item.Title}}" class="cover mb-4 rounded shadow" />
<video controls autoplay width="100%" class="rounded shadow">
<source src="{{.item.StreamURL}}" type="video/mp4">
Votre navigateur ne supporte pas la vidéo. Votre navigateur ne supporte pas la vidéo.
</video> </video>
</div> </div>