Audius MCP Server

<!DOCTYPE html> <html> <head> <title>Audius Player</title> <style> :root { --primary-color: #7E1BCC; --secondary-color: #9B4BFF; --background-color: #121212; --text-color: #FFFFFF; --text-secondary: #B3B3B3; } body { margin: 0; background: var(--background-color); color: var(--text-color); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; } #app { display: grid; grid-template-rows: 1fr auto; height: 100vh; } #track-list { padding: 20px; overflow-y: auto; } .track-item { display: flex; align-items: center; padding: 10px; margin-bottom: 8px; background: rgba(255, 255, 255, 0.05); border-radius: 4px; cursor: pointer; transition: background 0.2s; } .track-item:hover { background: rgba(255, 255, 255, 0.1); } .track-item.playing { background: rgba(126, 27, 204, 0.2); border-left: 4px solid var(--primary-color); } .track-info { flex-grow: 1; } .track-title { font-weight: 600; margin-bottom: 4px; } .track-artist { color: var(--text-secondary); font-size: 0.9em; } #player-controls { background: rgba(0, 0, 0, 0.95); padding: 20px; border-top: 1px solid rgba(255, 255, 255, 0.1); } .player-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; } .now-playing { text-align: center; } #current-title { font-weight: 600; margin-bottom: 4px; } #current-artist { color: var(--text-secondary); font-size: 0.9em; } .progress-container { width: 100%; height: 4px; background: rgba(255, 255, 255, 0.1); border-radius: 2px; cursor: pointer; margin: 10px 0; } .progress-bar { height: 100%; background: var(--primary-color); border-radius: 2px; width: 0%; transition: width 0.1s linear; } .time-info { display: flex; justify-content: space-between; font-size: 0.8em; color: var(--text-secondary); } .controls { display: flex; align-items: center; justify-content: center; gap: 20px; } .control-button { background: none; border: none; color: var(--text-color); cursor: pointer; padding: 8px; border-radius: 50%; transition: background 0.2s; } .control-button:hover { background: rgba(255, 255, 255, 0.1); } .volume-control { display: flex; align-items: center; gap: 10px; } #volume-slider { width: 100px; -webkit-appearance: none; background: rgba(255, 255, 255, 0.1); height: 4px; border-radius: 2px; } #volume-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; background: var(--primary-color); border-radius: 50%; cursor: pointer; } </style> </head> <body> <div id="app"> <div id="track-list"> <!-- Track list will be populated dynamically --> </div> <div id="player-controls"> <div class="now-playing"> <div id="current-title">Select a track</div> <div id="current-artist"></div> </div> <div class="progress-container" id="progress-container"> <div class="progress-bar" id="progress-bar"></div> </div> <div class="time-info"> <span id="current-time">0:00</span> <span id="duration">0:00</span> </div> <div class="controls"> <button class="control-button" id="prev-button">⏮</button> <button class="control-button" id="play-button">▶</button> <button class="control-button" id="next-button">⏭</button> <div class="volume-control"> <span id="volume-icon">🔊</span> <input type="range" id="volume-slider" min="0" max="1" step="0.1" value="1"> </div> </div> </div> <audio id="audio"></audio> </div> <script> class AudioPlayer { constructor() { this.audio = document.getElementById('audio'); this.trackList = document.getElementById('track-list'); this.currentTitle = document.getElementById('current-title'); this.currentArtist = document.getElementById('current-artist'); this.progressBar = document.getElementById('progress-bar'); this.progressContainer = document.getElementById('progress-container'); this.currentTime = document.getElementById('current-time'); this.duration = document.getElementById('duration'); this.playButton = document.getElementById('play-button'); this.prevButton = document.getElementById('prev-button'); this.nextButton = document.getElementById('next-button'); this.volumeSlider = document.getElementById('volume-slider'); this.volumeIcon = document.getElementById('volume-icon'); this.tracks = []; this.currentTrackIndex = -1; this.setupEventListeners(); this.loadTracks(); } setupEventListeners() { // Play/Pause button this.playButton.addEventListener('click', () => this.togglePlay()); // Previous/Next buttons this.prevButton.addEventListener('click', () => this.playPrevious()); this.nextButton.addEventListener('click', () => this.playNext()); // Progress bar this.progressContainer.addEventListener('click', (e) => { const rect = this.progressContainer.getBoundingClientRect(); const percent = (e.clientX - rect.left) / rect.width; this.audio.currentTime = this.audio.duration * percent; }); // Audio element events this.audio.addEventListener('timeupdate', () => this.updateProgress()); this.audio.addEventListener('ended', () => this.playNext()); this.audio.addEventListener('play', () => this.playButton.textContent = '⏸'); this.audio.addEventListener('pause', () => this.playButton.textContent = '▶'); // Volume control this.volumeSlider.addEventListener('input', (e) => { this.audio.volume = e.target.value; this.updateVolumeIcon(e.target.value); }); } updateVolumeIcon(value) { if (value >= 0.5) this.volumeIcon.textContent = '🔊'; else if (value > 0) this.volumeIcon.textContent = '🔉'; else this.volumeIcon.textContent = '🔇'; } async loadTracks() { try { // Fetch tracks from your Audius API endpoint const response = await fetch('/api/tracks'); const tracks = await response.json(); this.tracks = tracks; // Use the URLs directly from the test tracks config this.renderTrackList(); } catch (error) { console.error('Error loading tracks:', error); this.tracks = []; this.renderTrackList(); } } renderTrackList() { this.trackList.innerHTML = this.tracks.map((track, index) => ` <div class="track-item ${index === this.currentTrackIndex ? 'playing' : ''}" data-index="${index}"> <div class="track-info"> <div class="track-title">${track.title}</div> <div class="track-artist">${track.artist}</div> </div> </div> `).join(''); // Add click handlers to track items document.querySelectorAll('.track-item').forEach(item => { item.addEventListener('click', () => { const index = parseInt(item.dataset.index); this.playTrack(index); }); }); } playTrack(index) { if (index >= 0 && index < this.tracks.length) { this.currentTrackIndex = index; const track = this.tracks[index]; // Use the static URL directly this.audio.src = track.url; this.audio.play(); this.currentTitle.textContent = track.title; this.currentArtist.textContent = track.artist; this.renderTrackList(); // Update playing status } } togglePlay() { if (this.audio.paused) { if (this.currentTrackIndex === -1) this.playTrack(0); else this.audio.play(); } else { this.audio.pause(); } } playPrevious() { let index = this.currentTrackIndex - 1; if (index < 0) index = this.tracks.length - 1; this.playTrack(index); } playNext() { let index = this.currentTrackIndex + 1; if (index >= this.tracks.length) index = 0; this.playTrack(index); } updateProgress() { const percent = (this.audio.currentTime / this.audio.duration) * 100; this.progressBar.style.width = `${percent}%`; this.currentTime.textContent = this.formatTime(this.audio.currentTime); this.duration.textContent = this.formatTime(this.audio.duration); } formatTime(seconds) { if (isNaN(seconds)) return '0:00'; const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60).toString().padStart(2, '0'); return `${mins}:${secs}`; } } // Initialize player when the page loads window.addEventListener('load', () => { window.player = new AudioPlayer(); }); </script> </body> </html>