diff --git a/css/castopod-podcasts.css b/css/castopod-podcasts.css index e01c0eb..af3c48c 100644 --- a/css/castopod-podcasts.css +++ b/css/castopod-podcasts.css @@ -63,22 +63,28 @@ display: flex; padding: 8px 12px; border-bottom: 1px solid var(--border-color); - text-decoration: none; color: inherit; transition: background-color 0.2s ease; gap: 8px; + position: relative; } .castopod-episode-item:hover { background: var(--hover-bg); - text-decoration: none; - color: inherit; } .castopod-episode-item:last-child { border-bottom: none; } +.castopod-episode-item.playing { + background: var(--hover-bg); +} + +.castopod-episode-item.playing .castopod-episode-title { + color: var(--primary-red); +} + .castopod-episode-thumb { width: 60px; height: 60px; @@ -91,6 +97,14 @@ justify-content: center; color: var(--text-secondary); position: relative; + border: none; + padding: 0; + cursor: pointer; + transition: transform 0.2s ease; +} + +.castopod-episode-thumb:hover { + transform: scale(1.05); } .castopod-episode-thumb img { @@ -99,7 +113,8 @@ object-fit: cover; } -.castopod-play-icon { +.castopod-play-icon, +.castopod-pause-icon { position: absolute; top: 50%; left: 50%; @@ -116,6 +131,18 @@ opacity: 1; } +.castopod-episode-item.playing .castopod-play-icon { + opacity: 0; +} + +.castopod-episode-item.playing .castopod-pause-icon { + opacity: 1; +} + +.castopod-episode-item.playing:hover .castopod-pause-icon { + opacity: 1; +} + .castopod-episode-info { flex: 1; min-width: 0; @@ -171,6 +198,36 @@ font-size: 0.9rem; } +/* Lien externe vers Castopod */ +.castopod-external-link { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + flex-shrink: 0; + color: var(--text-secondary); + text-decoration: none; + border-radius: 50%; + transition: all 0.2s ease; + margin-left: auto; +} + +.castopod-external-link:hover { + background: var(--tag-bg); + color: var(--primary-red); + transform: scale(1.1); +} + +.castopod-external-link i { + font-size: 0.85rem; +} + +/* Masquer l'élément audio */ +.castopod-episode-item audio { + display: none; +} + /* Ajustement du layout selon les contenus présents */ /* Ordre dans le HTML : 1. Castopod, 2. Mastodon, 3. WordPress */ diff --git a/index.php b/index.php index 9dfcb7e..42a6a50 100644 --- a/index.php +++ b/index.php @@ -135,15 +135,15 @@ setSecurityHeaders(); if (empty($castopodEpisodes)) { echo '
Aucun épisode disponible
'; } else { - foreach ($castopodEpisodes as $episode): + foreach ($castopodEpisodes as $index => $episode): ?> - +
-
+
+
+ +
-
+

@@ -175,7 +178,21 @@ setSecurityHeaders();

-
+ + + + + + + + - - - + + + diff --git a/js/audio-player.js b/js/audio-player.js new file mode 100644 index 0000000..86a4493 --- /dev/null +++ b/js/audio-player.js @@ -0,0 +1,147 @@ +/** + * Lecteur audio intégré universel pour Funkwhale et Castopod + * Permet de lire les morceaux/épisodes directement dans la page + */ + +(function() { + 'use strict'; + + let currentlyPlayingItem = null; + let currentAudioElement = null; + + /** + * Arrête l'élément en cours de lecture + */ + function stopCurrentItem() { + if (currentAudioElement) { + currentAudioElement.pause(); + currentAudioElement.currentTime = 0; + } + if (currentlyPlayingItem) { + currentlyPlayingItem.classList.remove('playing'); + currentlyPlayingItem = null; + } + } + + /** + * Démarre la lecture d'un élément + */ + function playItem(item, audioElement) { + // Arrêter l'élément actuel s'il y en a un + if (currentlyPlayingItem && currentlyPlayingItem !== item) { + stopCurrentItem(); + } + + currentlyPlayingItem = item; + currentAudioElement = audioElement; + + // Marquer comme en cours de lecture + item.classList.add('playing'); + + // Démarrer la lecture + audioElement.play().catch(function(error) { + console.error('Erreur lors de la lecture:', error); + stopCurrentItem(); + }); + } + + /** + * Met en pause l'élément + */ + function pauseItem(item, audioElement) { + audioElement.pause(); + item.classList.remove('playing'); + } + + /** + * Initialise les contrôles du lecteur pour un type d'élément + */ + function initPlayerForType(itemSelector, buttonSelector) { + const items = document.querySelectorAll(itemSelector); + + items.forEach(function(item) { + const playButton = item.querySelector(buttonSelector); + const audioElement = item.querySelector('audio'); + + if (!playButton || !audioElement) { + return; + } + + // Gestion du clic sur le bouton play/pause + playButton.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + + if (item.classList.contains('playing')) { + pauseItem(item, audioElement); + } else { + playItem(item, audioElement); + } + }); + + // Gérer la fin de la lecture + audioElement.addEventListener('ended', function() { + item.classList.remove('playing'); + + // Passer automatiquement à l'élément suivant + const nextItem = item.nextElementSibling; + if (nextItem && (nextItem.classList.contains('funkwhale-track-item') || + nextItem.classList.contains('castopod-episode-item'))) { + const nextAudio = nextItem.querySelector('audio'); + if (nextAudio) { + playItem(nextItem, nextAudio); + } + } else { + // Réinitialiser si c'était le dernier élément + currentlyPlayingItem = null; + currentAudioElement = null; + } + }); + + // Gérer les erreurs de chargement + audioElement.addEventListener('error', function(e) { + console.error('Erreur de chargement audio:', e); + item.classList.remove('playing'); + + // Afficher un message d'erreur temporaire + const titleSelector = item.classList.contains('funkwhale-track-item') ? + '.funkwhale-track-title' : '.castopod-episode-title'; + const title = item.querySelector(titleSelector); + + if (title) { + const originalText = title.textContent; + title.textContent = 'Erreur de lecture'; + title.style.color = '#ff0000'; + + setTimeout(function() { + title.textContent = originalText; + title.style.color = ''; + }, 3000); + } + }); + }); + } + + /** + * Initialise tous les lecteurs + */ + function initPlayer() { + // Initialiser le lecteur Funkwhale + initPlayerForType('.funkwhale-track-item', '.funkwhale-play-btn'); + + // Initialiser le lecteur Castopod + initPlayerForType('.castopod-episode-item', '.castopod-play-btn'); + } + + // Initialiser le lecteur quand le DOM est prêt + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initPlayer); + } else { + initPlayer(); + } + + // Nettoyer à la fermeture de la page + window.addEventListener('beforeunload', function() { + stopCurrentItem(); + }); +})(); diff --git a/js/funkwhale-player.js b/js/funkwhale-player.js deleted file mode 100644 index 8e7b41f..0000000 --- a/js/funkwhale-player.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Lecteur audio intégré pour Funkwhale - * Permet de lire les morceaux directement dans la page - */ - -(function() { - 'use strict'; - - let currentlyPlayingTrack = null; - let currentAudioElement = null; - - /** - * Arrête le morceau en cours de lecture - */ - function stopCurrentTrack() { - if (currentAudioElement) { - currentAudioElement.pause(); - currentAudioElement.currentTime = 0; - } - if (currentlyPlayingTrack) { - currentlyPlayingTrack.classList.remove('playing'); - currentlyPlayingTrack = null; - } - } - - /** - * Démarre la lecture d'un morceau - */ - function playTrack(trackItem, audioElement) { - // Arrêter le morceau actuel s'il y en a un - if (currentlyPlayingTrack && currentlyPlayingTrack !== trackItem) { - stopCurrentTrack(); - } - - currentlyPlayingTrack = trackItem; - currentAudioElement = audioElement; - - // Marquer comme en cours de lecture - trackItem.classList.add('playing'); - - // Démarrer la lecture - audioElement.play().catch(function(error) { - console.error('Erreur lors de la lecture:', error); - stopCurrentTrack(); - }); - } - - /** - * Met en pause le morceau - */ - function pauseTrack(trackItem, audioElement) { - audioElement.pause(); - trackItem.classList.remove('playing'); - } - - /** - * Initialise les contrôles du lecteur - */ - function initPlayer() { - const trackItems = document.querySelectorAll('.funkwhale-track-item'); - - trackItems.forEach(function(trackItem) { - const playButton = trackItem.querySelector('.funkwhale-play-btn'); - const audioElement = trackItem.querySelector('audio'); - - if (!playButton || !audioElement) { - return; - } - - // Gestion du clic sur le bouton play/pause - playButton.addEventListener('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - - if (trackItem.classList.contains('playing')) { - pauseTrack(trackItem, audioElement); - } else { - playTrack(trackItem, audioElement); - } - }); - - // Gérer la fin de la lecture - audioElement.addEventListener('ended', function() { - trackItem.classList.remove('playing'); - - // Passer automatiquement au morceau suivant - const nextTrack = trackItem.nextElementSibling; - if (nextTrack && nextTrack.classList.contains('funkwhale-track-item')) { - const nextAudio = nextTrack.querySelector('audio'); - if (nextAudio) { - playTrack(nextTrack, nextAudio); - } - } else { - // Réinitialiser si c'était le dernier morceau - currentlyPlayingTrack = null; - currentAudioElement = null; - } - }); - - // Gérer les erreurs de chargement - audioElement.addEventListener('error', function(e) { - console.error('Erreur de chargement audio:', e); - trackItem.classList.remove('playing'); - - // Afficher un message d'erreur temporaire - const trackTitle = trackItem.querySelector('.funkwhale-track-title'); - if (trackTitle) { - const originalText = trackTitle.textContent; - trackTitle.textContent = 'Erreur de lecture'; - trackTitle.style.color = '#ff0000'; - - setTimeout(function() { - trackTitle.textContent = originalText; - trackTitle.style.color = ''; - }, 3000); - } - }); - }); - } - - // Initialiser le lecteur quand le DOM est prêt - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', initPlayer); - } else { - initPlayer(); - } - - // Nettoyer à la fermeture de la page - window.addEventListener('beforeunload', function() { - stopCurrentTrack(); - }); -})();