Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <link rel="shortcut icon" href="#"> | |
| <title>Beat Finder</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-color: #00a8e8; | |
| --secondary-color: #00c4ff; | |
| --background-start: #0d1b2a; | |
| --background-end: #1b263b; | |
| --container-bg: rgba(255, 255, 255, 0.05); | |
| --text-color: #f0f0f0; | |
| --text-muted-color: #c0c0c0; | |
| --success-color: #57cc99; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: 'Poppins', sans-serif; | |
| background: linear-gradient(135deg, var(--background-start), var(--background-end)); | |
| background-attachment: fixed; | |
| color: var(--text-color); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| width: 100%; | |
| max-width: 800px; | |
| background: var(--container-bg); | |
| padding: 2rem 3rem; | |
| border-radius: 20px; | |
| box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); | |
| backdrop-filter: blur(10px); | |
| -webkit-backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.18); | |
| text-align: center; | |
| } | |
| h1 { | |
| font-size: 2.5rem; | |
| font-weight: 700; | |
| margin-bottom: 0.5rem; | |
| color: #fff; | |
| } | |
| p { | |
| font-size: 1.1rem; | |
| font-weight: 300; | |
| color: var(--text-muted-color); | |
| margin-bottom: 2rem; | |
| line-height: 1.6; | |
| } | |
| #upload-form { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 1.5rem; | |
| margin-bottom: 2rem; | |
| } | |
| input[type="file"] { | |
| display: none; | |
| } | |
| .file-label { | |
| display: inline-block; | |
| padding: 12px 25px; | |
| background-color: var(--primary-color); | |
| color: white; | |
| border-radius: 50px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | |
| } | |
| .file-label:hover { | |
| background-color: var(--secondary-color); | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); | |
| } | |
| #selected-file-name { | |
| color: var(--text-muted-color); | |
| margin: -0.5rem 0; | |
| font-size: 0.9rem; | |
| min-height: 1.2rem; | |
| font-style: italic; | |
| } | |
| #submitButton { | |
| width: 100%; | |
| max-width: 200px; | |
| } | |
| .btn, input[type="submit"] { | |
| background-color: transparent; | |
| color: var(--text-color); | |
| border: 2px solid var(--primary-color); | |
| padding: 12px 25px; | |
| border-radius: 50px; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| font-family: 'Poppins', sans-serif; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .btn:disabled, input[type="submit"]:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| background-color: transparent ; | |
| color: var(--text-color) ; | |
| } | |
| .btn:hover, input[type="submit"]:hover { | |
| background-color: var(--primary-color); | |
| color: white; | |
| } | |
| .btn:disabled:hover, input[type="submit"]:disabled:hover { | |
| transform: none; | |
| box-shadow: none; | |
| } | |
| .btn.primary { | |
| background-color: var(--primary-color); | |
| color: white; | |
| } | |
| .btn.primary:hover { | |
| background-color: var(--secondary-color); | |
| } | |
| #buttonAddClicks, #buttonNewSong { | |
| margin-top: 1rem; | |
| } | |
| #song_uploaded_succesfully { | |
| color: var(--success-color); | |
| font-weight: 600; | |
| font-size: 1.1rem; | |
| margin-top: 1rem; | |
| margin-bottom: 1rem; | |
| min-height: 1.5rem; | |
| } | |
| .audio-players-container { | |
| display: flex; | |
| justify-content: center; | |
| align-items: flex-start; | |
| gap: 2rem; | |
| width: 100%; | |
| margin-top: 1.5rem; | |
| flex-wrap: wrap; | |
| transition: justify-content 0.5s ease; | |
| } | |
| .audio-players-container.two-up { | |
| justify-content: space-between; | |
| } | |
| .player-wrapper { | |
| flex: 1 1 250px; | |
| min-width: 250px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .player-wrapper h3 { | |
| font-weight: 400; | |
| color: var(--text-muted-color); | |
| font-size: 1rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| audio { | |
| width: 100%; | |
| filter: invert(1) hue-rotate(180deg); | |
| } | |
| .modal-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.6); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 1000; | |
| backdrop-filter: blur(5px); | |
| } | |
| .modal-content { | |
| background: var(--container-bg); | |
| padding: 2rem; | |
| border-radius: 20px; | |
| box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); | |
| border: 1px solid rgba(255, 255, 255, 0.18); | |
| text-align: center; | |
| max-width: 90%; | |
| width: 450px; | |
| } | |
| .modal-content h2 { | |
| margin-bottom: 1rem; | |
| color: #fff; | |
| } | |
| .modal-content p { | |
| font-size: 1rem; | |
| } | |
| .modal-buttons { | |
| display: flex; | |
| justify-content: center; | |
| gap: 1rem; | |
| margin-top: 2rem; | |
| } | |
| .spinner { | |
| border: 4px solid rgba(255, 255, 255, 0.3); | |
| border-radius: 50%; | |
| border-top: 4px solid var(--primary-color); | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| margin: 1.5rem auto; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .modal-content .spinner + p { | |
| margin-top: 0; | |
| } | |
| [hidden] { | |
| display: none ; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>Beat Finder</h1> | |
| <p>After uploading your music track, it will be preprocessed, passed to a neural network, and postprocessed to add the beats to it. For optimal performance, upload a music track of about 10 seconds.</p> | |
| <form action="/upload" method="post" enctype="multipart/form-data" id="upload-form"> | |
| <label for="file_id" class="file-label">Select a file</label> | |
| <input type="file" name="file" id="file_id"> | |
| <p id="selected-file-name" hidden></p> | |
| <input type="submit" id="submitButton" value="Upload File" hidden> | |
| </form> | |
| <p id='song_uploaded_succesfully' aria-live="polite"></p> | |
| <div id="audio-players-container" class="audio-players-container" hidden> | |
| <div id="player1-wrapper" class="player-wrapper" hidden> | |
| <h3>Original Song</h3> | |
| <audio controls id="audioPlayer1"> | |
| Your browser does not support the audio element. | |
| </audio> | |
| </div> | |
| <div id="player2-wrapper" class="player-wrapper" hidden> | |
| <h3>Song with Beats</h3> | |
| <audio id="audioPlayer" controls> | |
| Your browser does not support the audio element. | |
| </audio> | |
| </div> | |
| </div> | |
| <button type="button" id='buttonAddClicks' class="btn" hidden>Add beats</button> | |
| <button type="button" id='buttonNewSong' class="btn" hidden>New song</button> | |
| </div> | |
| <div id="confirmation-modal" class="modal-overlay" hidden> | |
| <div class="modal-content"> | |
| <h2>Are you sure?</h2> | |
| <p>Starting a new song will discard the current one and its processed version. This action cannot be undone.</p> | |
| <div class="modal-buttons"> | |
| <button id="cancel-new-song" class="btn">No, go back</button> | |
| <button id="confirm-new-song" class="btn primary">Yes, new song</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="loading-modal" class="modal-overlay" hidden> | |
| <div class="modal-content"> | |
| <h2>Processing Song...</h2> | |
| <div class="spinner"></div> | |
| <p>Adding beats, please wait a moment.</p> | |
| </div> | |
| </div> | |
| <script> | |
| let song_name = 'placeholder'; | |
| const fileInput = document.getElementById('file_id'); | |
| const fileLabel = document.querySelector('.file-label'); | |
| const playersContainer = document.getElementById('audio-players-container'); | |
| const selectedFileNameP = document.getElementById('selected-file-name'); | |
| fileInput.addEventListener('change', function() { | |
| const submitButton = document.getElementById('submitButton'); | |
| if (this.files && this.files.length > 0) { | |
| selectedFileNameP.textContent = `You selected ${this.files[0].name}`; | |
| selectedFileNameP.hidden = false; | |
| submitButton.hidden = false; | |
| } else { | |
| selectedFileNameP.textContent = ''; | |
| selectedFileNameP.hidden = true; | |
| submitButton.hidden = true; | |
| } | |
| }); | |
| function showElement(elementId) { | |
| const element = document.getElementById(elementId); | |
| element.hidden = false; | |
| } | |
| function hideElement(elementId) { | |
| const element = document.getElementById(elementId); | |
| element.hidden = true; | |
| } | |
| function setControlsDisabled(disabled) { | |
| document.getElementById('file_id').disabled = disabled; | |
| document.getElementById('submitButton').disabled = disabled; | |
| document.getElementById('buttonAddClicks').disabled = disabled; | |
| document.getElementById('buttonNewSong').disabled = disabled; | |
| const fileLabel = document.querySelector('.file-label'); | |
| if (disabled) { | |
| fileLabel.style.opacity = '0.5'; | |
| fileLabel.style.cursor = 'not-allowed'; | |
| } else { | |
| fileLabel.style.opacity = '1'; | |
| fileLabel.style.cursor = 'pointer'; | |
| } | |
| } | |
| document.getElementById('upload-form').addEventListener('submit', function(event) { | |
| event.preventDefault(); | |
| if (!fileInput.files || fileInput.files.length === 0) { | |
| alert('Please select a file first!'); | |
| return; | |
| } | |
| const form = event.target; | |
| const formData = new FormData(form); | |
| song_name = document.getElementById('file_id').files[0].name; | |
| fetch('/upload', { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| .then(response => response.text()) | |
| .then(message => { | |
| console.log(message); | |
| form.reset(); | |
| document.getElementById('submitButton').hidden = true; | |
| selectedFileNameP.textContent = ''; | |
| selectedFileNameP.hidden = true; | |
| const successMessage = song_name + ' song uploaded successfully'; | |
| document.getElementById('song_uploaded_succesfully').innerText = successMessage; | |
| showElement('buttonAddClicks'); | |
| showElement('audio-players-container'); | |
| showElement('player1-wrapper'); | |
| const audioSourceUrl = "/static/uploaded_songs/" + song_name; | |
| const audioPlayer1 = document.getElementById('audioPlayer1'); | |
| audioPlayer1.src = audioSourceUrl; | |
| audioPlayer1.load(); | |
| }); | |
| }); | |
| document.getElementById('buttonAddClicks').addEventListener('click', function(event) { | |
| showElement('loading-modal'); | |
| setControlsDisabled(true); | |
| fetch('/get_beat', { | |
| method: 'POST', | |
| body: JSON.stringify(song_name) | |
| }) | |
| .then(response => response.text()) | |
| .then(message => { | |
| console.log(message); | |
| hideElement('loading-modal'); | |
| const audioSourceUrl = "/static/" + song_name.slice(0, -4) + '_clicks.wav'; | |
| const audioPlayer = document.getElementById('audioPlayer'); | |
| audioPlayer.src = audioSourceUrl; | |
| audioPlayer.load(); | |
| audioPlayer.addEventListener('canplaythrough', function() { | |
| showElement('player2-wrapper'); | |
| playersContainer.classList.add('two-up'); | |
| const newSongButton = document.getElementById('buttonNewSong'); | |
| newSongButton.hidden = false; | |
| newSongButton.disabled = false; | |
| hideElement('buttonAddClicks'); | |
| hideElement('upload-form'); | |
| }, { once: true }); | |
| }) | |
| .catch(error => { | |
| console.error("Error adding beats:", error); | |
| hideElement('loading-modal'); | |
| setControlsDisabled(false); | |
| alert('An error occurred while adding beats. Please try again.'); | |
| }); | |
| }); | |
| function resetApp() { | |
| document.getElementById('song_uploaded_succesfully').innerText = ''; | |
| const addBeatsButton = document.getElementById('buttonAddClicks'); | |
| addBeatsButton.innerText = 'Add beats'; | |
| addBeatsButton.disabled = false; | |
| hideElement('buttonAddClicks'); | |
| const audioPlayer = document.getElementById('audioPlayer'); | |
| audioPlayer.pause(); | |
| audioPlayer.src = ''; | |
| const audioPlayer1 = document.getElementById('audioPlayer1'); | |
| audioPlayer1.pause(); | |
| audioPlayer1.src = ''; | |
| hideElement('player1-wrapper'); | |
| hideElement('player2-wrapper'); | |
| hideElement('audio-players-container'); | |
| playersContainer.classList.remove('two-up'); | |
| hideElement('buttonNewSong'); | |
| showElement('upload-form'); | |
| setControlsDisabled(false); | |
| document.getElementById('submitButton').hidden = true; | |
| fileInput.value = ''; | |
| selectedFileNameP.textContent = ''; | |
| selectedFileNameP.hidden = true; | |
| } | |
| document.getElementById('buttonNewSong').addEventListener('click', function() { | |
| showElement('confirmation-modal'); | |
| }); | |
| document.getElementById('cancel-new-song').addEventListener('click', function() { | |
| hideElement('confirmation-modal'); | |
| }); | |
| document.getElementById('confirm-new-song').addEventListener('click', function() { | |
| hideElement('confirmation-modal'); | |
| resetApp(); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |