Download test.html from shoom013/foxdot: direct link, hf CLI and curl.
- Browser
- Download file 6.17 kB
-
https://huggingface.co/spaces/shoom013/foxdot/resolve/main/test.html
- Command line
-
hf download hf://spaces/shoom013/foxdot/test.html
-
curl -L -o test.html https://huggingface.co/spaces/shoom013/foxdot/resolve/main/test.html
6.17 kB
| <html> | |
| <head> | |
| <title>FoxDot Stream Test</title> | |
| <style> | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| padding: 40px; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| min-height: 100vh; | |
| margin: 0; | |
| } | |
| .container { | |
| max-width: 600px; | |
| margin: 0 auto; | |
| background: rgba(255, 255, 255, 0.1); | |
| backdrop-filter: blur(10px); | |
| padding: 30px; | |
| border-radius: 15px; | |
| box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); | |
| } | |
| h1 { | |
| text-align: center; | |
| margin-bottom: 10px; | |
| } | |
| .subtitle { | |
| text-align: center; | |
| opacity: 0.8; | |
| margin-bottom: 30px; | |
| } | |
| audio { | |
| width: 100%; | |
| margin: 20px 0; | |
| border-radius: 10px; | |
| } | |
| .status { | |
| padding: 15px; | |
| background: rgba(0, 0, 0, 0.3); | |
| border-radius: 8px; | |
| margin: 15px 0; | |
| } | |
| .status-indicator { | |
| display: inline-block; | |
| width: 12px; | |
| height: 12px; | |
| border-radius: 50%; | |
| margin-right: 8px; | |
| animation: pulse 2s ease-in-out infinite; | |
| } | |
| .status-connecting { | |
| background: #ffd700; | |
| } | |
| .status-playing { | |
| background: #00ff00; | |
| } | |
| .status-error { | |
| background: #ff0000; | |
| animation: none; | |
| } | |
| .status-buffering { | |
| background: #ffa500; | |
| } | |
| @keyframes pulse { | |
| 0%, | |
| 100% { | |
| opacity: 1; | |
| } | |
| 50% { | |
| opacity: 0.5; | |
| } | |
| } | |
| .info { | |
| background: rgba(0, 0, 0, 0.2); | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin-top: 20px; | |
| font-size: 14px; | |
| } | |
| .info code { | |
| background: rgba(0, 0, 0, 0.3); | |
| padding: 2px 6px; | |
| border-radius: 3px; | |
| font-family: 'Courier New', monospace; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>🎵 FoxDot Audio Stream</h1> | |
| <p class="subtitle">Live audio streaming from SuperCollider</p> | |
| <audio id="audioPlayer" controls autoplay> | |
| <source src="http://localhost:8000/stream.mp3" type="audio/mpeg"> | |
| Your browser does not support the audio element. | |
| </audio> | |
| <div class="status"> | |
| <span id="statusIndicator" class="status-indicator status-connecting"></span> | |
| <strong>Status:</strong> <span id="statusText">Connecting...</span> | |
| </div> | |
| <div class="info"> | |
| <strong>Stream Info:</strong><br> | |
| URL: <code id="streamUrl">http://localhost:8000/stream.mp3</code><br> | |
| Format: <code>MP3 (128kbps)</code><br> | |
| Source: <code>SuperCollider → JACK → FFmpeg → Icecast</code> | |
| </div> | |
| <div class="info" id="debugInfo" style="display: none;"> | |
| <strong>Debug Info:</strong><br> | |
| <div id="debugText"></div> | |
| </div> | |
| </div> | |
| <script> | |
| const audio = document.getElementById('audioPlayer'); | |
| const statusText = document.getElementById('statusText'); | |
| const statusIndicator = document.getElementById('statusIndicator'); | |
| const debugInfo = document.getElementById('debugInfo'); | |
| const debugText = document.getElementById('debugText'); | |
| function updateStatus(status, message) { | |
| statusText.innerText = message; | |
| statusIndicator.className = 'status-indicator status-' + status; | |
| } | |
| function log(message) { | |
| const timestamp = new Date().toLocaleTimeString(); | |
| debugText.innerHTML += `[${timestamp}] ${message}<br>`; | |
| debugInfo.style.display = 'block'; | |
| console.log(message); | |
| } | |
| audio.onloadstart = () => { | |
| updateStatus('connecting', 'Loading stream...'); | |
| log('Loading stream from /stream'); | |
| }; | |
| audio.oncanplay = () => { | |
| updateStatus('playing', 'Ready to play'); | |
| log('Stream is ready to play'); | |
| }; | |
| audio.onplaying = () => { | |
| updateStatus('playing', 'Playing ♪'); | |
| log('Stream is playing'); | |
| }; | |
| audio.onwaiting = () => { | |
| updateStatus('buffering', 'Buffering...'); | |
| log('Buffering stream data'); | |
| }; | |
| audio.onpause = () => { | |
| updateStatus('connecting', 'Paused'); | |
| log('Stream paused'); | |
| }; | |
| audio.onerror = (e) => { | |
| updateStatus('error', 'Error loading stream'); | |
| const error = audio.error; | |
| let errorMsg = 'Unknown error'; | |
| if (error) { | |
| switch (error.code) { | |
| case 1: errorMsg = 'MEDIA_ERR_ABORTED - Playback aborted'; break; | |
| case 2: errorMsg = 'MEDIA_ERR_NETWORK - Network error'; break; | |
| case 3: errorMsg = 'MEDIA_ERR_DECODE - Decoding error'; break; | |
| case 4: errorMsg = 'MEDIA_ERR_SRC_NOT_SUPPORTED - Stream not supported'; break; | |
| } | |
| } | |
| log(`ERROR: ${errorMsg}`); | |
| // Try to get more info about the stream | |
| fetch('/stream', { method: 'HEAD' }) | |
| .then(response => { | |
| log(`Stream endpoint status: ${response.status}`); | |
| log(`Content-Type: ${response.headers.get('content-type')}`); | |
| }) | |
| .catch(err => { | |
| log(`Cannot reach stream endpoint: ${err.message}`); | |
| }); | |
| }; | |
| // Show current URL | |
| document.getElementById('streamUrl').innerText = window.location.origin + '/stream'; | |
| // Initial log | |
| log('Page loaded, attempting to connect to stream'); | |
| </script> | |
| </body> | |
| </html> |