UP
This commit is contained in:
parent
dddf56a2d6
commit
7f332aa88b
@ -980,33 +980,90 @@ 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
|
||||
func MediaDetail(db *gorm.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// 1) Extraire le partID
|
||||
partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64)
|
||||
|
||||
// on récupère 1 metadata + file pour ce media_part
|
||||
var item struct {
|
||||
models.MetadataItem
|
||||
MediaPartID int64
|
||||
File string
|
||||
}
|
||||
db.Table("metadata_items").
|
||||
Select("metadata_items.*, media_parts.id AS media_part_id, media_parts.file").
|
||||
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").
|
||||
Where("media_parts.id = ?", partID).
|
||||
Scan(&item)
|
||||
var view mediaDetailView
|
||||
|
||||
if item.MediaPartID == 0 {
|
||||
http.Error(w, "Média introuvable", http.StatusNotFound)
|
||||
return
|
||||
if partID > 0 {
|
||||
// --- CAS BDD ---
|
||||
var item struct {
|
||||
models.MetadataItem
|
||||
MediaPartID int64
|
||||
File string
|
||||
UserThumbURL string
|
||||
}
|
||||
db.Table("metadata_items").
|
||||
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_parts ON media_parts.media_item_id = media_items.id").
|
||||
Where("media_parts.id = ?", partID).
|
||||
Scan(&item)
|
||||
|
||||
if item.MediaPartID == 0 {
|
||||
http.Error(w, "Média introuvable", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
// formater la durée
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
renderTemplate(w, "media_detail", map[string]interface{}{
|
||||
"item": item,
|
||||
// 3) Render partial dans #content
|
||||
renderPartial(w, "media_detail", map[string]interface{}{
|
||||
"item": view,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
<div class="detail">
|
||||
<img src="{{.item.UserThumbURL}}" alt="{{.item.Title}}" class="cover">
|
||||
<h1>{{.item.Title}}</h1>
|
||||
{{with .item.Summary}}<p>{{.}}</p>{{end}}
|
||||
<video controls autoplay width="100%" poster="{{.item.UserThumbURL}}">
|
||||
<source src="/stream/{{.item.MediaPartID}}" type="video/mp4">
|
||||
<div class="detail p-4">
|
||||
<h1 class="text-2xl font-bold mb-4">{{.item.Title}}</h1>
|
||||
{{with .item.Summary}}
|
||||
<p class="mb-4">{{.}}</p>
|
||||
{{end}}
|
||||
{{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.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user