Français, voir plus bas
Source at very end
ENGLISH
Since I upgraded to Windows 11, I've had trouble easily casting the songs I want to my Google Nest, to the point that it's annoying me...
Furthermore, I sometimes have to stream games or activities where I clearly need a soundscape in the background.
That's why I'm currently creating as many songs as possible with varied rhythms, but with themes related to my universe, so that viewers can instantly find their way around and say: Ah, this music, we're definitely at Ithara's!!!
Want to listen to them ? Here they go : http://principalityofbastion.org/musiques/
So I asked Claude AI to create a web page that could play all the music I uploaded to a folder, so I could play it, on repeat, randomly.
A few seconds of thought and, he did this for me:
https://www.principalityofbastion.org/musicplayer.html
Feel free to copy the source code for your own use if you want to try modifying it, because it's not perfect. I'll explain below...
I just tested it... I can load songs from the hard drive, I can change the sound, I can navigate through the song, change the music speed, I can configure it to shuffle the songs.
However, as soon as I get to the end of a song, it loads the next one and waits for me to press play again...
Here, however, Claude is having trouble finding a solution...
@deadzy, @invest-time, would you like to test your respective AIs?
You can see the full source code below... for fun if you want, I'll have to wait until tomorrow for the rest.
(FULL SOURCE AT THE END OF THE POST)
Best regards,
≋𝕴𝖙𝖍𝖆𝖗𝖆 𝕲𝖆ï𝖆𝖓≋ Prince of Principality of Bastion
≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋
Discord : https://discord.principalityofbastion.org
Website : https://principalityofbastion.org / https://nft.bastion.city
Social Networks: See on our website.
Founder of the Principality of Bastion


Want to be seen by our manual curation services?
Interact with us by joining our discord, use our #BASTION, or #FR IF you speak french in your post.
Français
Depuis que je suis passé en windows 11, j'ai du mal à caster facilement les chansons que je veux sur mon Google nest, au point que cela m'énervait ...
De plus, je suis parfois obligé de streamer des jeux ou des activités où j'ai clairement besoin d'un univers sonore en arrière plan.
C'est d'ailleurs pour cela que je crée, en ce moment, un maximum de chansons sur des rythmes variés, mais aux thèmes liés à mon univers, pour que les viewers puissent se repérer instantanément en se disant : Ah, cette musique, on est forcément chez Ithara !!!
Envie de les écouter ? Les voici : http://principalityofbastion.org/musiques/
Alors j'ai demandé à Claude IA de me faire une page web pouvant jouer toutes les musiques que je chargerais dans un répertoire, pour pouvoir les lire, en boucle, de façon aléatoire.
Quelques secondes de réflexion et zouh, il m'a fait ceci:
https://www.principalityofbastion.org/musicplayer.html
N'hésitez pas à copier le code source pour votre propre usage si vous voulez tenter de le modifier, car il n'est pas parfait, je vous explique ci-dessous...
Je viens de le tester ... Je peux loader les chansons depuis le disque dur, je peux modifier le son, je peux surfer sur la chanson, changer la vitesse de la musique, je peux faire le setup pour mélanger les chansons.
Par contre dès que j'arrive à la fin d'une chanson, ils charge la suivante et attend qu'on appuie à nouveau sur play...
Là, par contre, claude à du mal me trouve rune solution...
@deadzy , @invest-time auriez-vous envie de tester vos IA respective?
Vous pouvez voir la source complète ci-dessous... pour vous amuser si vous voulez, moi je dois attendre demain pour la suite.
(SOURCE COMPLETE EN FIN DE POST)
Best regards,
≋𝕴𝖙𝖍𝖆𝖗𝖆 𝕲𝖆ï𝖆𝖓≋ Prince of Principality of Bastion
≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋≋
Discord : https://discord.principalityofbastion.org
Website : https://principalityofbastion.org / https://nft.bastion.city
Social Networks: See on our website.
Founder of the Principality of Bastion


Want to be seen by our manual curation services?
Interact with us by joining our discord, use our #BASTION, or #FR IF you speak french in your post.
Source
language html & JS
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lecteur MP3 Minimaliste</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: #fff;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.player-container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 30px;
max-width: 500px;
width: 100%;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.file-input-container {
margin-bottom: 30px;
text-align: center;
}
.file-input-label {
display: inline-block;
padding: 12px 24px;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 12px;
}
.file-input-label:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}
#musicFiles {
display: none;
}
.current-track {
text-align: center;
margin-bottom: 20px;
padding: 20px;
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.track-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 5px;
color: #667eea;
}
.track-info {
font-size: 12px;
opacity: 0.7;
text-transform: uppercase;
letter-spacing: 1px;
}
.audio-player {
width: 100%;
margin-bottom: 20px;
border-radius: 10px;
overflow: hidden;
}
.controls {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 20px;
}
.control-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #fff;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
font-size: 18px;
}
.control-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.1);
}
.control-btn:active {
transform: scale(0.95);
}
.progress-container {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
}
.time {
font-size: 12px;
font-weight: 500;
min-width: 40px;
text-align: center;
}
.progress-bar {
flex: 1;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 3px;
width: 0%;
transition: width 0.1s ease;
}
.playlist {
max-height: 200px;
overflow-y: auto;
background: rgba(0, 0, 0, 0.2);
border-radius: 10px;
padding: 10px;
}
.playlist-item {
padding: 8px 12px;
cursor: pointer;
border-radius: 5px;
transition: all 0.2s ease;
font-size: 14px;
margin-bottom: 2px;
}
.playlist-item:hover {
background: rgba(255, 255, 255, 0.1);
}
.playlist-item.active {
background: linear-gradient(90deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3));
border-left: 3px solid #667eea;
}
.status {
text-align: center;
margin-top: 15px;
font-size: 12px;
opacity: 0.8;
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: rgba(102, 126, 234, 0.5);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(102, 126, 234, 0.7);
}
</style>
</head>
<body>
<div class="player-container">
<div class="file-input-container">
<label for="musicFiles" class="file-input-label">
📁 Chargez vos fichiers MP3
</label>
<input type="file" id="musicFiles" accept="audio/mp3,audio/mpeg" multiple webkitdirectory>
</div>
<div class="current-track">
<div class="track-title">Aucun fichier sélectionné</div>
<div class="track-info">Choisissez un dossier contenant vos MP3</div>
</div>
<audio class="audio-player" controls id="audioPlayer">
Votre navigateur ne supporte pas l'audio HTML5.
</audio>
<div class="controls">
<button class="control-btn" id="prevBtn" title="Précédent">⏮</button>
<button class="control-btn" id="playPauseBtn" title="Lecture/Pause">▶</button>
<button class="control-btn" id="nextBtn" title="Suivant">⏭</button>
<button class="control-btn" id="shuffleBtn" title="Aléatoire">🔀</button>
</div>
<div class="progress-container">
<span class="time" id="currentTime">0:00</span>
<div class="progress-bar" id="progressBar">
<div class="progress-fill" id="progressFill"></div>
</div>
<span class="time" id="duration">0:00</span>
</div>
<div class="playlist" id="playlist"></div>
<div class="status" id="status">🔄 Lecture en boucle activée</div>
</div>
<script>
class MP3Player {
constructor() {
this.audioPlayer = document.getElementById('audioPlayer');
this.playlist = [];
this.currentIndex = 0;
this.isPlaying = false;
this.isShuffled = false;
this.originalPlaylist = [];
this.initializeElements();
this.bindEvents();
}
initializeElements() {
this.playPauseBtn = document.getElementById('playPauseBtn');
this.prevBtn = document.getElementById('prevBtn');
this.nextBtn = document.getElementById('nextBtn');
this.shuffleBtn = document.getElementById('shuffleBtn');
this.progressBar = document.getElementById('progressBar');
this.progressFill = document.getElementById('progressFill');
this.currentTimeEl = document.getElementById('currentTime');
this.durationEl = document.getElementById('duration');
this.playlistEl = document.getElementById('playlist');
this.trackTitle = document.querySelector('.track-title');
this.trackInfo = document.querySelector('.track-info');
this.fileInput = document.getElementById('musicFiles');
}
bindEvents() {
// Contrôles
this.playPauseBtn.addEventListener('click', () => this.togglePlayPause());
this.prevBtn.addEventListener('click', () => this.previousTrack());
this.nextBtn.addEventListener('click', () => this.nextTrack());
this.shuffleBtn.addEventListener('click', () => this.toggleShuffle());
// Barre de progression
this.progressBar.addEventListener('click', (e) => this.seek(e));
// Audio events
this.audioPlayer.addEventListener('loadedmetadata', () => this.updateDuration());
this.audioPlayer.addEventListener('timeupdate', () => this.updateProgress());
this.audioPlayer.addEventListener('ended', () => this.nextTrack());
this.audioPlayer.addEventListener('play', () => this.onPlay());
this.audioPlayer.addEventListener('pause', () => this.onPause());
// Chargement des fichiers
this.fileInput.addEventListener('change', (e) => this.loadFiles(e));
}
loadFiles(event) {
const files = Array.from(event.target.files);
const mp3Files = files.filter(file =>
file.type === 'audio/mp3' || file.type === 'audio/mpeg' || file.name.toLowerCase().endsWith('.mp3')
);
if (mp3Files.length === 0) {
alert('Aucun fichier MP3 trouvé dans le dossier sélectionné.');
return;
}
this.playlist = mp3Files.map((file, index) => ({
file: file,
name: this.extractFileName(file.name),
path: file.webkitRelativePath || file.name,
url: URL.createObjectURL(file),
index: index
}));
this.originalPlaylist = [...this.playlist];
this.currentIndex = 0;
this.renderPlaylist();
this.loadTrack(0);
this.updateTrackInfo();
}
extractFileName(fullPath) {
return fullPath.split('/').pop().replace('.mp3', '');
}
renderPlaylist() {
this.playlistEl.innerHTML = '';
this.playlist.forEach((track, index) => {
const item = document.createElement('div');
item.className = 'playlist-item';
item.textContent = `${track.name}`;
item.addEventListener('click', () => this.playTrack(index));
if (index === this.currentIndex) {
item.classList.add('active');
}
this.playlistEl.appendChild(item);
});
}
loadTrack(index) {
if (index >= 0 && index < this.playlist.length) {
this.currentIndex = index;
this.audioPlayer.src = this.playlist[index].url;
this.updateTrackInfo();
this.updateActivePlaylistItem();
}
}
playTrack(index) {
this.loadTrack(index);
this.play();
}
updateTrackInfo() {
if (this.playlist.length > 0) {
const track = this.playlist[this.currentIndex];
this.trackTitle.textContent = track.name;
this.trackInfo.textContent = `${this.currentIndex + 1} / ${this.playlist.length}`;
}
}
updateActivePlaylistItem() {
const items = this.playlistEl.querySelectorAll('.playlist-item');
items.forEach((item, index) => {
item.classList.toggle('active', index === this.currentIndex);
});
}
togglePlayPause() {
if (this.audioPlayer.paused) {
this.play();
} else {
this.pause();
}
}
play() {
if (this.playlist.length > 0) {
this.audioPlayer.play();
}
}
pause() {
this.audioPlayer.pause();
}
onPlay() {
this.isPlaying = true;
this.playPauseBtn.innerHTML = '⏸';
}
onPause() {
this.isPlaying = false;
this.playPauseBtn.innerHTML = '▶';
}
nextTrack() {
if (this.playlist.length === 0) return;
let nextIndex = this.currentIndex + 1;
if (nextIndex >= this.playlist.length) {
nextIndex = 0; // Boucle au début
}
this.loadTrack(nextIndex);
if (this.isPlaying) {
this.play();
}
}
previousTrack() {
if (this.playlist.length === 0) return;
// Mémoriser si on était en train de jouer
const wasPlaying = !this.audioPlayer.paused;
let prevIndex = this.currentIndex - 1;
if (prevIndex < 0) {
prevIndex = this.playlist.length - 1; // Boucle à la fin
}
this.loadTrack(prevIndex);
// Si on était en train de jouer, continuer la lecture
if (wasPlaying) {
this.shouldAutoPlay = true;
setTimeout(() => {
this.audioPlayer.play().catch(e => {
console.log('Erreur de lecture auto:', e);
});
}, 100);
}
}
toggleShuffle() {
this.isShuffled = !this.isShuffled;
if (this.isShuffled) {
this.shuffleBtn.style.background = 'linear-gradient(45deg, #667eea, #764ba2)';
this.shuffleArray(this.playlist);
} else {
this.shuffleBtn.style.background = 'rgba(255, 255, 255, 0.1)';
this.playlist = [...this.originalPlaylist];
}
this.currentIndex = 0;
this.renderPlaylist();
this.loadTrack(0);
}
shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
seek(event) {
const rect = this.progressBar.getBoundingClientRect();
const percent = (event.clientX - rect.left) / rect.width;
const newTime = percent * this.audioPlayer.duration;
this.audioPlayer.currentTime = newTime;
}
updateProgress() {
if (this.audioPlayer.duration) {
const percent = (this.audioPlayer.currentTime / this.audioPlayer.duration) * 100;
this.progressFill.style.width = percent + '%';
this.currentTimeEl.textContent = this.formatTime(this.audioPlayer.currentTime);
}
}
updateDuration() {
this.durationEl.textContent = this.formatTime(this.audioPlayer.duration);
}
formatTime(seconds) {
if (isNaN(seconds)) return '0:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
}
// Initialisation du lecteur
document.addEventListener('DOMContentLoaded', () => {
new MP3Player();
});
</script>
</body>
</html>