Raiju/js/audio-player.js
2026-10-25 06:05:42 +03:00

232 lines
7.9 KiB
JavaScript

/**
* Custom Audio Player
* Steuert die benutzerdefinierten Audio-Player auf der Seite
*/
(function() {
'use strict';
// Alle Player initialisieren wenn DOM geladen
document.addEventListener('DOMContentLoaded', initAudioPlayers);
// Auch bei dynamisch geladenen Inhalten (für Inline-Editor)
window.initAudioPlayers = initAudioPlayers;
function initAudioPlayers() {
const players = document.querySelectorAll('.custom-audio-player');
players.forEach(initPlayer);
}
function initPlayer(playerElement) {
// Nicht doppelt initialisieren
if (playerElement.dataset.initialized) return;
playerElement.dataset.initialized = 'true';
const playerId = playerElement.dataset.playerId;
const audio = document.getElementById(playerId);
if (!audio) return;
const playBtn = playerElement.querySelector('.audio-play-btn');
const progressBar = playerElement.querySelector('.audio-progress-bar');
const progress = playerElement.querySelector('.audio-progress');
const handle = playerElement.querySelector('.audio-progress-handle');
const currentTime = playerElement.querySelector('.audio-current');
const durationDisplay = playerElement.querySelector('.audio-duration');
// Volume Controls
const volumeBtn = playerElement.querySelector('.audio-volume-btn');
const volumeSlider = playerElement.querySelector('.audio-volume-slider');
const volumeTrack = playerElement.querySelector('.audio-volume-track');
const volumeFill = playerElement.querySelector('.audio-volume-fill');
const volumeHandle = playerElement.querySelector('.audio-volume-handle');
// Zeit formatieren (mm:ss)
function formatTime(seconds) {
if (isNaN(seconds) || !isFinite(seconds)) return '0:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return mins + ':' + (secs < 10 ? '0' : '') + secs;
}
// Volume Icon aktualisieren
function updateVolumeIcon() {
playerElement.classList.remove('volume-muted', 'volume-low');
if (audio.muted || audio.volume === 0) {
playerElement.classList.add('volume-muted');
} else if (audio.volume < 0.5) {
playerElement.classList.add('volume-low');
}
}
// Volume UI aktualisieren
function updateVolumeUI() {
const percent = audio.muted ? 0 : audio.volume * 100;
volumeFill.style.width = percent + '%';
volumeHandle.style.left = percent + '%';
updateVolumeIcon();
}
// Dauer anzeigen wenn Metadaten geladen
audio.addEventListener('loadedmetadata', function() {
durationDisplay.textContent = formatTime(audio.duration);
});
// Falls Dauer schon bekannt (cached)
if (audio.duration) {
durationDisplay.textContent = formatTime(audio.duration);
}
// Initiale Volume UI
updateVolumeUI();
// Play/Pause
playBtn.addEventListener('click', function() {
// Andere Player pausieren
document.querySelectorAll('.custom-audio-player.playing').forEach(function(other) {
if (other !== playerElement) {
const otherId = other.dataset.playerId;
const otherAudio = document.getElementById(otherId);
if (otherAudio) {
otherAudio.pause();
other.classList.remove('playing');
}
}
});
if (audio.paused) {
audio.play();
playerElement.classList.add('playing');
} else {
audio.pause();
playerElement.classList.remove('playing');
}
});
// Progress Update
audio.addEventListener('timeupdate', function() {
const percent = (audio.currentTime / audio.duration) * 100 || 0;
progress.style.width = percent + '%';
handle.style.left = percent + '%';
currentTime.textContent = formatTime(audio.currentTime);
});
// Ende erreicht
audio.addEventListener('ended', function() {
playerElement.classList.remove('playing');
progress.style.width = '0%';
handle.style.left = '0%';
currentTime.textContent = '0:00';
});
// Klick auf Progress-Bar
let isDraggingProgress = false;
function seek(e) {
const rect = progressBar.getBoundingClientRect();
const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
audio.currentTime = percent * audio.duration;
}
progressBar.addEventListener('mousedown', function(e) {
isDraggingProgress = true;
seek(e);
});
document.addEventListener('mousemove', function(e) {
if (isDraggingProgress) {
seek(e);
}
});
document.addEventListener('mouseup', function() {
isDraggingProgress = false;
});
// Touch-Support für Progress
progressBar.addEventListener('touchstart', function(e) {
isDraggingProgress = true;
seek(e.touches[0]);
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (isDraggingProgress && e.touches[0]) {
seek(e.touches[0]);
}
}, { passive: true });
document.addEventListener('touchend', function() {
isDraggingProgress = false;
});
// ========== VOLUME CONTROLS ==========
let previousVolume = 1;
// Mute/Unmute beim Klick auf Volume-Button
volumeBtn.addEventListener('click', function() {
if (audio.muted || audio.volume === 0) {
audio.muted = false;
audio.volume = previousVolume || 0.5;
} else {
previousVolume = audio.volume;
audio.muted = true;
}
updateVolumeUI();
});
// Volume Slider
let isDraggingVolume = false;
function setVolume(e) {
const rect = volumeTrack.getBoundingClientRect();
const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
audio.volume = percent;
audio.muted = false;
updateVolumeUI();
}
volumeTrack.addEventListener('mousedown', function(e) {
isDraggingVolume = true;
volumeSlider.classList.add('active');
setVolume(e);
});
document.addEventListener('mousemove', function(e) {
if (isDraggingVolume) {
setVolume(e);
}
});
document.addEventListener('mouseup', function() {
if (isDraggingVolume) {
isDraggingVolume = false;
setTimeout(function() {
volumeSlider.classList.remove('active');
}, 300);
}
});
// Touch-Support für Volume
volumeTrack.addEventListener('touchstart', function(e) {
isDraggingVolume = true;
volumeSlider.classList.add('active');
setVolume(e.touches[0]);
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (isDraggingVolume && e.touches[0]) {
setVolume(e.touches[0]);
}
}, { passive: true });
document.addEventListener('touchend', function() {
if (isDraggingVolume) {
isDraggingVolume = false;
setTimeout(function() {
volumeSlider.classList.remove('active');
}, 300);
}
});
}
})();