From 7c22e2593e5616605d96fedf96d7517bdd53a342 Mon Sep 17 00:00:00 2001
From: Alexandre <44178713+alexbelgium@users.noreply.github.com>
Date: Sat, 12 Apr 2025 10:09:03 +0200
Subject: [PATCH] New feat : Redesigned audio player (#279)
* New audio player
* New style
* Readd vertical bar
* Improve appearance safari
* Improve layout
* Improve alignement of bottom elements
* Align
---
homepage/static/custom-audio-player.js | 726 +++++++++++++++++++++++++
homepage/views.php | 22 +-
scripts/overview.php | 33 +-
scripts/play.php | 45 +-
scripts/todays_detections.php | 6 +-
5 files changed, 787 insertions(+), 45 deletions(-)
create mode 100644 homepage/static/custom-audio-player.js
diff --git a/homepage/static/custom-audio-player.js b/homepage/static/custom-audio-player.js
new file mode 100644
index 0000000..7a44655
--- /dev/null
+++ b/homepage/static/custom-audio-player.js
@@ -0,0 +1,726 @@
+function initCustomAudioPlayers() {
+ // =================== Config & Helpers ===================
+ const CONFIG = {
+ LEFT_MARGIN_PERCENT: 6,
+ RIGHT_MARGIN_PERCENT: 9,
+ PROGRESS_BAR_UPDATE_INTERVAL: 20,
+ BUFFER_TIME: 0.1,
+ };
+
+ const debounce = (func, wait) => {
+ let timeout;
+ return (...args) => {
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, args), wait);
+ };
+ };
+
+ const icons = {
+ play: ``,
+ pause: ``,
+ dots: ``,
+ spinner: `
+
+
`,
+ error: ``,
+ };
+
+ // For user preferences (gain, filters, etc.)
+ const safeGet = (k, fb) => {
+ try {
+ return localStorage.getItem(k) || fb;
+ } catch {
+ return fb;
+ }
+ };
+ const safeSet = (k, v) => {
+ try {
+ localStorage.setItem(k, v);
+ } catch {}
+ };
+
+ // Retrieve saved user preferences
+ const savedGain = safeGet("customAudioPlayerGain", "Off");
+ const savedHighpass = safeGet("customAudioPlayerFilterHigh", "Off");
+ const savedLowpass = safeGet("customAudioPlayerFilterLow", "Off");
+
+ // Helper to apply multiple style properties
+ const applyStyles = (elem, styles) => Object.assign(elem.style, styles);
+
+ // Basic styling for small control buttons
+ const styleButton = (btn, styles = {}) => {
+ applyStyles(btn, styles);
+ // Subtle hover highlight
+ btn.addEventListener("mouseover", () => (btn.style.background = "rgba(255,255,255,0.1)"));
+ btn.addEventListener("mouseout", () => (btn.style.background = "transparent"));
+ };
+
+ // Helper to create a button
+ const createButton = (
+ parent,
+ { text = "", html = "", styles = {}, data = {}, onClick = null } = {}
+ ) => {
+ const btn = document.createElement("button");
+ btn.type = "button";
+ if (text) btn.textContent = text;
+ if (html) btn.innerHTML = html;
+ Object.entries(data).forEach(([k, v]) => (btn.dataset[k] = v));
+ styleButton(btn, styles);
+ if (onClick) btn.addEventListener("click", onClick);
+ parent.appendChild(btn);
+ return btn;
+ };
+
+ // Common small‐button styling
+ const iconBtnStyle = {
+ background: "transparent",
+ border: "none",
+ cursor: "pointer",
+ width: "36px",
+ height: "36px",
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "center",
+ marginRight: "0.6rem",
+ padding: "0",
+ borderRadius: "50%",
+ };
+ const textBtnStyle = {
+ background: "none",
+ border: "none",
+ cursor: "pointer",
+ color: "white",
+ fontSize: "14px",
+ textAlign: "right",
+ width: "100%",
+ padding: "6px 12px",
+ margin: "2px 0",
+ borderRadius: "4px",
+ };
+ const optionBtnStyle = {
+ background: "none",
+ border: "none",
+ cursor: "pointer",
+ color: "white",
+ fontSize: "14px",
+ textAlign: "center",
+ width: "auto",
+ padding: "6px 8px",
+ margin: "2px 4px",
+ borderRadius: "4px",
+ };
+
+ // =================== Main Loop over all .custom-audio-player ===================
+ document.querySelectorAll(".custom-audio-player").forEach((player) => {
+ let hasLoaded = false; // set to true once metadata is available
+
+ // Audio/player data
+ const audioSrc = player.dataset.audioSrc;
+ const imageSrc = player.dataset.imageSrc;
+
+ //