feat: permit to play Funkwhale songs

This commit is contained in:
2025-10-17 21:23:44 +04:00
parent 95de788114
commit b3ee9d9837
4 changed files with 233 additions and 13 deletions
+61 -4
View File
@@ -62,22 +62,28 @@
display: flex; display: flex;
padding: 8px 12px; padding: 8px 12px;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
text-decoration: none;
color: inherit; color: inherit;
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
gap: 8px; gap: 8px;
position: relative;
} }
.funkwhale-track-item:hover { .funkwhale-track-item:hover {
background: var(--hover-bg); background: var(--hover-bg);
text-decoration: none;
color: inherit;
} }
.funkwhale-track-item:last-child { .funkwhale-track-item:last-child {
border-bottom: none; border-bottom: none;
} }
.funkwhale-track-item.playing {
background: var(--hover-bg);
}
.funkwhale-track-item.playing .funkwhale-track-title {
color: var(--primary-red);
}
.funkwhale-track-thumb { .funkwhale-track-thumb {
width: 60px; width: 60px;
height: 60px; height: 60px;
@@ -90,6 +96,14 @@
justify-content: center; justify-content: center;
color: var(--text-secondary); color: var(--text-secondary);
position: relative; position: relative;
border: none;
padding: 0;
cursor: pointer;
transition: transform 0.2s ease;
}
.funkwhale-track-thumb:hover {
transform: scale(1.05);
} }
.funkwhale-track-thumb img { .funkwhale-track-thumb img {
@@ -98,7 +112,8 @@
object-fit: cover; object-fit: cover;
} }
.funkwhale-play-icon { .funkwhale-play-icon,
.funkwhale-pause-icon {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
@@ -115,6 +130,18 @@
opacity: 1; opacity: 1;
} }
.funkwhale-track-item.playing .funkwhale-play-icon {
opacity: 0;
}
.funkwhale-track-item.playing .funkwhale-pause-icon {
opacity: 1;
}
.funkwhale-track-item.playing:hover .funkwhale-pause-icon {
opacity: 1;
}
.funkwhale-track-info { .funkwhale-track-info {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
@@ -170,6 +197,36 @@
font-size: 0.9rem; font-size: 0.9rem;
} }
/* Lien externe vers Funkwhale */
.funkwhale-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;
}
.funkwhale-external-link:hover {
background: var(--tag-bg);
color: var(--primary-red);
transform: scale(1.1);
}
.funkwhale-external-link i {
font-size: 0.85rem;
}
/* Masquer l'élément audio */
.funkwhale-track-item audio {
display: none;
}
/* Responsive Design */ /* Responsive Design */
@media (max-width: 1024px) { @media (max-width: 1024px) {
.funkwhale-section { .funkwhale-section {
+9
View File
@@ -953,6 +953,14 @@ function getFunkwhaleTracks($funkwhaleUrl = null, $count = null) {
// Ne garder que les morceaux locaux // Ne garder que les morceaux locaux
if ($isLocal) { if ($isLocal) {
// Récupérer l'URL d'écoute depuis l'API (peut être relative)
$listenUrl = $item['listen_url'] ?? '';
// Si l'URL est relative, la transformer en URL absolue
if (!empty($listenUrl) && strpos($listenUrl, 'http') !== 0) {
$listenUrl = rtrim($funkwhaleUrl, '/') . $listenUrl;
}
$track = [ $track = [
'title' => $item['title'] ?? '', 'title' => $item['title'] ?? '',
'artist' => $item['artist']['name'] ?? 'Artiste inconnu', 'artist' => $item['artist']['name'] ?? 'Artiste inconnu',
@@ -961,6 +969,7 @@ function getFunkwhaleTracks($funkwhaleUrl = null, $count = null) {
'duration' => $item['uploads'][0]['duration'] ?? 0, 'duration' => $item['uploads'][0]['duration'] ?? 0,
'link' => rtrim($funkwhaleUrl, '/') . '/library/tracks/' . ($item['id'] ?? ''), 'link' => rtrim($funkwhaleUrl, '/') . '/library/tracks/' . ($item['id'] ?? ''),
'trackId' => $item['id'] ?? 0, 'trackId' => $item['id'] ?? 0,
'audioUrl' => $listenUrl,
]; ];
// Formater la durée // Formater la durée
+31 -9
View File
@@ -208,15 +208,15 @@ setSecurityHeaders();
if (empty($funkwhaleTracks)) { if (empty($funkwhaleTracks)) {
echo '<div class="funkwhale-no-tracks">Aucun morceau disponible</div>'; echo '<div class="funkwhale-no-tracks">Aucun morceau disponible</div>';
} else { } else {
foreach ($funkwhaleTracks as $track): foreach ($funkwhaleTracks as $index => $track):
?> ?>
<a href="<?php echo htmlspecialchars($track['link']); ?>" <div class="funkwhale-track-item"
class="funkwhale-track-item" data-track-id="<?php echo $index; ?>"
target="_blank" data-audio-url="<?php echo htmlspecialchars($track['audioUrl']); ?>">
rel="noopener noreferrer"
title="<?php echo htmlspecialchars($track['title'] . ' - ' . $track['artist']); ?>">
<div class="funkwhale-track-thumb"> <button class="funkwhale-track-thumb funkwhale-play-btn"
type="button"
aria-label="Lire <?php echo htmlspecialchars($track['title']); ?>">
<?php if (!empty($track['cover'])): ?> <?php if (!empty($track['cover'])): ?>
<img src="<?php echo htmlspecialchars($track['cover']); ?>" <img src="<?php echo htmlspecialchars($track['cover']); ?>"
alt="<?php echo htmlspecialchars($track['album']); ?>" alt="<?php echo htmlspecialchars($track['album']); ?>"
@@ -224,10 +224,13 @@ setSecurityHeaders();
<div class="funkwhale-play-icon"> <div class="funkwhale-play-icon">
<i class="fas fa-play-circle"></i> <i class="fas fa-play-circle"></i>
</div> </div>
<div class="funkwhale-pause-icon">
<i class="fas fa-pause-circle"></i>
</div>
<?php else: ?> <?php else: ?>
<i class="fas fa-music"></i> <i class="fas fa-music"></i>
<?php endif; ?> <?php endif; ?>
</div> </button>
<div class="funkwhale-track-info"> <div class="funkwhale-track-info">
<h3 class="funkwhale-track-title"> <h3 class="funkwhale-track-title">
@@ -246,7 +249,21 @@ setSecurityHeaders();
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>
</a>
<a href="<?php echo htmlspecialchars($track['link']); ?>"
class="funkwhale-external-link"
target="_blank"
rel="noopener noreferrer"
title="Voir sur Funkwhale"
aria-label="Voir <?php echo htmlspecialchars($track['title']); ?> sur Funkwhale">
<i class="fas fa-external-link-alt"></i>
</a>
<!-- Élément audio caché -->
<audio preload="none">
<source src="<?php echo htmlspecialchars($track['audioUrl']); ?>" type="audio/mpeg">
</audio>
</div>
<?php <?php
endforeach; endforeach;
} }
@@ -704,5 +721,10 @@ setSecurityHeaders();
} }
}); });
</script> </script>
<?php if (defined('FUNKWHALE_ENABLED') && FUNKWHALE_ENABLED): ?>
<!-- Lecteur audio Funkwhale -->
<script src="js/funkwhale-player.js?v=<?php echo filemtime('js/funkwhale-player.js'); ?>"></script>
<?php endif; ?>
</body> </body>
</html> </html>
+132
View File
@@ -0,0 +1,132 @@
/**
* 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();
});
})();