update compression parameters and resolution choices

This commit is contained in:
2026-02-12 21:40:37 +01:00
parent 28eaf9feaa
commit e4baa929f2
2 changed files with 148 additions and 56 deletions

View File

@@ -9,6 +9,7 @@ import re
import sys
import markdown2
import numpy as np
import html
# --- 1. CONFIGURATION ---
base_dir = sys.argv[1] if len(sys.argv) > 1 else "./"
@@ -51,16 +52,47 @@ def create_pin(color, icon_name):
def inject_common_assets(m):
custom_js = """
<script>
document.addEventListener('click', function (e) {
setTimeout(function() {
var videos = document.querySelectorAll('video');
videos.forEach(function(video) {
if (video.hasAttribute('autoplay')) {
video.play().catch(function(error) { console.log("Autoplay bloqué"); });
// --- GESTION DES BOUTONS 720p / 1080p ---
function changeQuality(videoId, newSrc, btnElement) {
var video = document.getElementById(videoId);
if (video.src.includes(newSrc)) return;
var savedTime = video.currentTime;
var wasPlaying = !video.paused; // On regarde si c'était en lecture
video.src = newSrc;
// On attend que les métadonnées soient prêtes pour remettre le temps
video.onloadedmetadata = function() {
this.currentTime = savedTime;
if (wasPlaying) {
var playPromise = this.play();
if (playPromise !== undefined) {
playPromise.catch(error => { console.log("Lecture bloquée"); });
}
});
}, 300);
}, true);
}
this.onloadedmetadata = null;
};
video.load();
// Mise à jour visuelle des boutons
var container = btnElement.parentElement;
var buttons = container.getElementsByClassName('quality-btn');
for (var i = 0; i < buttons.length; i++) {
buttons[i].classList.remove('active-720', 'active-1080');
buttons[i].style.opacity = "0.6";
}
btnElement.style.opacity = "1";
if (btnElement.innerText.includes("720p")) {
btnElement.classList.add('active-720');
} else {
btnElement.classList.add('active-1080');
}
}
// ----------------------------------------
function toggleJournal(open) {
var panel = document.getElementById('journal-panel');
@@ -73,7 +105,6 @@ def inject_common_assets(m):
}
}
// Persistance du journal sur toutes les pages
window.addEventListener('DOMContentLoaded', function() {
if (localStorage.getItem('journalOpen') === 'true') {
var panel = document.getElementById('journal-panel');
@@ -95,6 +126,24 @@ def inject_common_assets(m):
"""
custom_css = """
<style>
.header-row {
display: flex; justify-content: space-between; align-items: center;
background: #f0f0f0; padding: 5px 10px; border-radius: 4px; margin-bottom: 5px;
}
.file-name {
font-size: 11px; font-family: monospace; font-weight: bold; color: #333;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60%;
}
.quality-controls { display: flex; gap: 6px; }
.quality-btn {
padding: 3px 8px; border-radius: 12px; font-size: 10px; font-weight: bold; cursor: pointer;
border: 1px solid #ccc; background: #fff; opacity: 0.6; transition: 0.2s; font-family: sans-serif;
text-transform: uppercase;
}
.quality-btn:hover { opacity: 1; background: #eee; }
.active-720 { background-color: #2ECC71 !important; color: white; border-color: #27ae60 !important; opacity: 1 !important; }
.active-1080 { background-color: #007AFF !important; color: white; border-color: #0056b3 !important; opacity: 1 !important; }
.leaflet-top.leaflet-left { top: auto !important; bottom: 20px !important; left: 15px !important; }
.leaflet-popup-content-wrapper { border-radius: 12px; max-width: 95vw !important; }
#journal-panel {
@@ -106,7 +155,6 @@ def inject_common_assets(m):
#journal-panel.open { right: 0; }
@media (max-width: 600px) { #journal-panel { width: 85%; } }
.close-btn { position: absolute; top: 15px; right: 15px; font-size: 24px; cursor: pointer; border: none; background: none; }
.file-header { background: #f0f0f0; padding: 4px 8px; border-radius: 4px; margin-bottom: 8px; font-size: 11px; font-family: monospace; display: block; overflow: hidden; text-overflow: ellipsis; }
.slider-container { position: relative; width: calc(85vw - 60px); max-width: 800px; text-align: center; min-height: 200px; }
.slide img { max-width: 100%; max-height: 65vh; border-radius: 8px; display: block; margin: auto; }
.nav-btn { position: absolute; top: 50%; transform: translateY(-50%); background: rgba(0,0,0,0.6); color: white; border: 2px solid white; padding: 12px; cursor: pointer; border-radius: 50%; z-index: 10; font-size: 18px; }
@@ -178,8 +226,6 @@ for i, jour in enumerate(tous_les_jours):
for track in gpx.tracks:
pts = []
for segment in track.segments:
# OPTIMISATION : On ne garde qu'un point sur 5
# pts.extend([[p.latitude, p.longitude] for i, p in enumerate(segment.points) if i % 5 == 0])
pts.extend([[p.latitude, p.longitude] for p in segment.points])
if pts:
day_coords.extend(pts); all_global_coords.extend(pts)
@@ -204,9 +250,6 @@ for i, jour in enumerate(tous_les_jours):
groupe = day_p[masque]
fichiers = groupe['Fichier'].tolist()
nb = len(fichiers)
# slides = "".join([f'<div class="slide" style="display:{"block" if idx == 0 else "none"};"><div class="file-header">{p.strip()}</div><a href="../photos/{p.strip()}" target="_blank"><img src="../photos/{p.strip()}"></a></div>' for idx, p in enumerate(fichiers)])
# OPTIMISATION : Ajout de loading="lazy" dans la balise img
slides = "".join([f'<div class="slide" style="display:{"block" if idx == 0 else "none"};"><div class="file-header">{p.strip()}</div><a href="../photos/{p.strip()}" target="_blank"><img src="../photos/{p.strip()}" loading="lazy"></a></div>' for idx, p in enumerate(fichiers)])
btns = f'<button class="nav-btn prev" onclick="moveSlide(this, -1)">&#10094;</button><button class="nav-btn next" onclick="moveSlide(this, 1)">&#10095;</button><div class="slide-counter">1/{nb}</div>' if nb > 1 else ""
folium.Marker(location=[ref['Latitude'], ref['Longitude']], popup=folium.Popup(f'<div class="slider-container"><div class="slides">{slides}</div>{btns}</div>', max_width="100%"), icon=create_pin("#FF3B30", "camera" if nb==1 else "images")).add_to(marker_cluster)
@@ -216,8 +259,34 @@ for i, jour in enumerate(tous_les_jours):
day_v = df_v[df_v['Jour'] == jour]
for v_name, group in day_v.groupby('Fichier'):
pts_v = group[['Latitude', 'Longitude']].values.tolist()
# v_pop = f'<div style="width:calc(85vw - 40px); max-width:1000px; text-align:center;"><div class="file-header">{v_name.strip()}</div><video style="width:100%; max-height:70vh; border-radius:8px; background:black;" controls playsinline webkit-playsinline autoplay muted><source src="../videos/{v_name.strip()}" type="video/mp4"></video></div>'
v_pop = f'<div style="width:calc(85vw - 40px); max-width:1000px; text-align:center;"><div class="file-header">{v_name.strip()}</div><video style="width:100%; max-height:70vh; border-radius:8px; background:black;" controls playsinline webkit-playsinline autoplay muted preload="auto"><source src="../videos/{v_name.strip()}" type="video/mp4"></video></div>'
base_name = os.path.splitext(v_name.strip())[0]
clean_id = re.sub(r'[^a-zA-Z0-9]', '', base_name)
video_id = f"vid_{clean_id}"
desktop_file = f"../videos/{base_name}.mp4"
mobile_file = f"../videos/{base_name}_mobile.mp4"
# Ajout 'autoplay muted' pour le lancement au clic
# Ajout 'preload=none' pour ne pas charger les autres
v_pop = (
f'<div style="width:calc(85vw - 40px); max-width:1000px; text-align:center;">'
f'<div class="header-row">'
f'<span class="file-name" title="{v_name.strip()}">{v_name.strip()}</span>'
f'<div class="quality-controls">'
f'<span class="quality-btn active-720" onclick="changeQuality(\'{video_id}\', \'{mobile_file}\', this)">720p</span>'
f'<span class="quality-btn" onclick="changeQuality(\'{video_id}\', \'{desktop_file}\', this)">1080p</span>'
f'</div>'
f'</div>'
f'<video id="{video_id}" style="width:100%; max-height:70vh; border-radius:8px; background:black;" '
f'controls playsinline webkit-playsinline autoplay muted preload="none" '
f'src="{mobile_file}">'
f'</video></div>'
)
folium.Marker(location=pts_v[0], popup=folium.Popup(v_pop, max_width="100%"), icon=create_pin("#007AFF", "play")).add_to(marker_cluster)
if day_coords: m_day.fit_bounds(day_coords, padding=(50, 50))
@@ -236,3 +305,6 @@ folium.LayerControl().add_to(m_global)
m_global.save(os.path.join(base_dir, "index.html"))
m_mini.save(os.path.join(base_dir, "mini.html"))