up
This commit is contained in:
parent
88aad929db
commit
4b5028e9f9
@ -995,6 +995,14 @@ func MediaDetail(db *gorm.DB) http.HandlerFunc {
|
|||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64)
|
partID, _ := strconv.ParseInt(mux.Vars(r)["partID"], 10, 64)
|
||||||
|
|
||||||
|
// 2) Récupérer pathID et sub depuis la query string
|
||||||
|
pathIDStr := r.URL.Query().Get("pathID")
|
||||||
|
sub := r.URL.Query().Get("sub")
|
||||||
|
var pathID int64
|
||||||
|
if pathIDStr != "" {
|
||||||
|
pathID, _ = strconv.ParseInt(pathIDStr, 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
var view mediaDetailView
|
var view mediaDetailView
|
||||||
|
|
||||||
if partID > 0 {
|
if partID > 0 {
|
||||||
@ -1061,43 +1069,15 @@ func MediaDetail(db *gorm.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPartial(w, "media_detail", map[string]interface{}{
|
renderPartial(w, "media_detail", map[string]interface{}{
|
||||||
"item": view,
|
"PathID": pathID,
|
||||||
})
|
"CurrentSub": sub,
|
||||||
|
"item": view,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Stream : transcode à la volée en MP4 progressif et pipe directement dans la réponse
|
|
||||||
func Stream(db *gorm.DB) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
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, "Not found", http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "video/mp4")
|
|
||||||
// ffmpeg en pipe
|
|
||||||
cmd := exec.CommandContext(r.Context(),
|
|
||||||
"ffmpeg",
|
|
||||||
"-i", part.File,
|
|
||||||
"-c:v", "libx264",
|
|
||||||
"-c:a", "aac",
|
|
||||||
"-movflags", "frag_keyframe+empty_moov+faststart",
|
|
||||||
"-f", "mp4",
|
|
||||||
"pipe:1",
|
|
||||||
)
|
|
||||||
cmd.Stdout = w
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
log.Println("ffmpeg:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// renders/media.go (ajoutez cette fonction)
|
// renders/media.go (ajoutez cette fonction)
|
||||||
// rend le HLS pour BDD (partID>0) et FS-only (partID==0)
|
// rend le HLS pour BDD (partID>0) et FS-only (partID==0)
|
||||||
func HLSStream(db *gorm.DB) http.HandlerFunc {
|
func HLSStream(db *gorm.DB) http.HandlerFunc {
|
||||||
|
|||||||
@ -1,7 +1,30 @@
|
|||||||
|
{{define "media_detail.pages.tmpl"}}
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="box">
|
<!-- Fil d’Ariane -->
|
||||||
|
<nav class="breadcrumb mb-4" aria-label="breadcrumbs">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
hx-get="/api/paths/{{.PathID}}/media"
|
||||||
|
hx-push-url="/api/paths/{{.PathID}}/media"
|
||||||
|
hx-target="#content"
|
||||||
|
hx-swap="innerHTML">
|
||||||
|
Accueil
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{if .CurrentSub}}
|
||||||
|
<li>
|
||||||
|
<a>{{.CurrentSub}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
<li class="is-active">
|
||||||
|
<a aria-current="page">{{.item.Title}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
<!-- Bloc détail -->
|
<!-- Bloc détail -->
|
||||||
<div id="detail-block">
|
<div id="detail-block">
|
||||||
<div class="columns is-vcentered">
|
<div class="columns is-vcentered">
|
||||||
@ -34,43 +57,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.body.addEventListener('click', function(e) {
|
// Gestion des boutons Play et Fermer
|
||||||
// Play
|
document.body.addEventListener('click', function(e) {
|
||||||
const playBtn = e.target.closest('.js-play-btn');
|
const playBtn = e.target.closest('.js-play-btn');
|
||||||
if (playBtn) {
|
if (playBtn) {
|
||||||
const detailBlock = document.getElementById('detail-block');
|
document.getElementById('detail-block').style.display = 'none';
|
||||||
const playerBlock = document.querySelector('.js-player-block');
|
document.querySelector('.js-player-block').style.display = 'block';
|
||||||
const video = document.getElementById('hls-video');
|
const video = document.getElementById('hls-video');
|
||||||
const url = playBtn.dataset.hlsurl;
|
const url = playBtn.dataset.hlsurl;
|
||||||
|
if (Hls.isSupported()) {
|
||||||
detailBlock.style.display = 'none';
|
const hls = new Hls(); hls.loadSource(url); hls.attachMedia(video);
|
||||||
playerBlock.style.display = 'block';
|
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
|
video.src = url;
|
||||||
if (Hls.isSupported()) {
|
}
|
||||||
const hls = new Hls();
|
return;
|
||||||
hls.loadSource(url);
|
|
||||||
hls.attachMedia(video);
|
|
||||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
|
||||||
video.src = url;
|
|
||||||
} else {
|
|
||||||
console.error('HLS non supporté');
|
|
||||||
}
|
}
|
||||||
return;
|
const closeBtn = e.target.closest('.js-close-btn');
|
||||||
}
|
if (closeBtn) {
|
||||||
|
const video = document.getElementById('hls-video');
|
||||||
// Fermer
|
video.pause(); video.src = '';
|
||||||
const closeBtn = e.target.closest('.js-close-btn');
|
document.querySelector('.js-player-block').style.display = 'none';
|
||||||
if (closeBtn) {
|
document.getElementById('detail-block').style.display = 'block';
|
||||||
const detailBlock = document.getElementById('detail-block');
|
}
|
||||||
const playerBlock = document.querySelector('.js-player-block');
|
});
|
||||||
const video = document.getElementById('hls-video');
|
|
||||||
|
|
||||||
video.pause();
|
|
||||||
video.src = '';
|
|
||||||
playerBlock.style.display = 'none';
|
|
||||||
detailBlock.style.display = 'block';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
{{end}}
|
||||||
|
|||||||
@ -28,8 +28,12 @@
|
|||||||
<div class="column is-one-quarter">
|
<div class="column is-one-quarter">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content has-text-centered">
|
<div class="card-content has-text-centered">
|
||||||
<a hx-get="/api/paths/{{$.PathID}}/media?sub={{.SubPath | urlquery}}"
|
<a
|
||||||
hx-target="#content" hx-swap="innerHTML">
|
hx-get="/media/{{.MediaPartID}}?path={{.FilePath | urlquery}}&pathID={{$.PathID}}&sub={{$.CurrentSub}}"
|
||||||
|
hx-push-url="/media/{{.MediaPartID}}?path={{.FilePath | urlquery}}&pathID={{$.PathID}}&sub={{$.CurrentSub}}"
|
||||||
|
hx-target="#content"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
>
|
||||||
<span class="icon is-large">
|
<span class="icon is-large">
|
||||||
<i class="fas fa-folder fa-2x"></i>
|
<i class="fas fa-folder fa-2x"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user