2017-07-27 2 views
1

Ich möchte in der Lage sein, einen Musikordner auszuwählen und alle Titel einmal beim Laden zu mischen und einen Skip-Button + den Namen der Song-Datei an den Visualizer zu senden, so dass jeder Song angezeigt werden kann. Ich lerne immer noch Arrays und For-Schleifen, daher bin ich nicht sicher, wie ich das anstellen soll. Ich möchte mich auch jetzt von zusätzlichen Bibliotheken fernhalten, da alles bereits vorhanden ist. Heres ein Code-Schnipsel von dem, was ich bisherAuswählen von Musikordner html

window.onload = function() { 
 
    
 
    var file = document.getElementById("file"); 
 
    var audio = document.getElementById("audio"); 
 
    
 
    file.onchange = function() { 
 
    var files = this.files; 
 
    audio.src = URL.createObjectURL(files[0]); 
 
    audio.load(); 
 
    audio.play(); 
 
    var context = new AudioContext(); 
 
    var src = context.createMediaElementSource(audio); 
 
    var analyser = context.createAnalyser(); 
 

 
    var canvas = document.getElementById("canvas"); 
 
    canvas.width = window.innerWidth; 
 
    canvas.height = window.innerHeight; 
 
    var ctx = canvas.getContext("2d"); 
 

 
    src.connect(analyser); 
 
    analyser.connect(context.destination); 
 

 
    analyser.fftSize = 256; 
 

 
    var bufferLength = analyser.frequencyBinCount; 
 
    console.log(bufferLength); 
 

 
    var dataArray = new Uint8Array(bufferLength); 
 

 
    var WIDTH = canvas.width; 
 
    var HEIGHT = canvas.height; 
 

 
    var barWidth = (WIDTH/bufferLength) * 1; 
 
    var barHeight; 
 
    var x = 0; 
 

 
    function renderFrame() { 
 
     requestAnimationFrame(renderFrame); 
 
     x = 0; 
 

 
     analyser.getByteFrequencyData(dataArray); 
 

 
     ctx.fillStyle = "#1b1b1b"; 
 
     ctx.fillRect(0, 0, WIDTH, HEIGHT); 
 

 
     for (var i = 0; i < bufferLength; i++) { 
 
     barHeight = dataArray[i]; 
 
     
 
     var r = 5; 
 
     var g = 195; 
 
     var b = 45; 
 

 
     ctx.fillStyle = "rgb(5,195,45)" 
 
     ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight); 
 

 
     x += barWidth + 2; 
 
     } 
 
    } 
 

 
    audio.play(); 
 
    renderFrame(); 
 
    }; 
 
};
#file { 
 
    position: fixed; 
 
    top: 10px; 
 
    left: 10px; 
 
    z-index: 100; 
 
} 
 

 
#canvas { 
 
    position: fixed; 
 
    left: 0; 
 
    top: 0; 
 
    width: 100%; 
 
    height: 100%; 
 
} 
 

 
audio { 
 
    position: fixed; 
 
    left: 350px; 
 
    top: 10px; 
 
    width: calc(50% - 20px); 
 
}
<div id="content"> 
 
    <input type="file" id="file" accept="audio/*" /> 
 
    <canvas id="canvas"></canvas> 
 
    <audio id="audio" controls></audio> 
 
</div>

+0

Welche Frage haben Sie mit HTML und JavaScript-Code in Frage zu haben? – guest271314

+0

Ich weiß einfach nicht, wie man dafür Arrays und for-Schleifen einrichtet. Ich bin mir sehr sicher, dass ich irgendeine Art von Array zum Sammeln aller Audiodateien in dem Ordner, den ich ausgewählt habe, und den untergeordneten Ordnern erstellen muss. Ich muss auch diese Arrays modifizieren oder eine neue mit dem Ort jedes Songs und der Shuffle-Reihenfolge erstellen. Ich habe die Grundidee in meinem Kopf, ich bin mir nur unsicher, wie ich es ausführen soll. – Nickh90

+0

Sie können die Attribute 'webkitdirectory' und' allowdirs' auf '' element setzen, um den Upload von Verzeichnissen zu ermöglichen. Iterieren Sie alle hochgeladenen Verzeichnisse, um alle hochgeladenen 'File' Objekte in den Verzeichnissen zu erhalten, die als Elemente eines Arrays gesetzt sind, siehe [Wie man Verzeichnisse auf Firefox und Chrome/Chrom hochlädt und auflistet durch Ereignisse ändern und löschen] (https: // stackoverflow. com/q/39664662 /) – guest271314

Antwort

1

Sie können webkitdirectory und allowdirs Attribute bei <input type="file"> Element gesetzt Verzeichnis-Upload zu ermöglichen.

Rekursiv oder unter Verwendung von Promise wiederholt iterieren Verzeichnisse, einschließlich Verzeichnisse innerhalb von Verzeichnissen, schieben Sie alle Dateien in Verzeichnissen zu einem global definierten Array von File Objekte, siehe How to upload and list directories at firefox and chrome/chromium using change and drop events; wobei JavaScript bei Antwort geändert wird, um den Ereignishandler drop zu entfernen, der speziell nicht Teil der Anforderung ist.

Verwenden Array.prototype.reduce() und Promise eine Funktion für jedes Objekt in File Sequenz zu nennen, die Medien und das Rück ein erfülltes Promise bei ended Falle HTMLMediaElement zu spielen; zum Beispiel die anonyme Funktion bei 10 Handler bei Frage, modifiziert, wo notwendig, um die erwartete Anforderung einer Playlist zu erreichen, die aus dem Hochladen von N Verzeichnissen oder N verschachtelten Verzeichnissen erzeugt wird. Beachten Sie, dass, wenn mehr AudioContent.createMediaElementSource() als einmal mit dem gleichen <audio> Elemente als Parameter eine Ausnahme ausgelöst wird

Uncaught DOMException: Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode 

remove createMediaElementSource sieht Aufruf. Sie können die Variablen global definieren und die Variable mithilfe von OR || referenzieren, um die Ausnahme zu vermeiden.

Die erzeugte Blob URL wird einer Variablen zugewiesen und bei ended Falle HTMLMediaElement entzogen und vor dem Wieder zugewiesen wird, wenn die Funktion wieder aufgerufen wird, wenn ended Ereignis nicht erreicht wird.

Enthalten <select> Element für die Möglichkeit, eine der hochgeladenen Dateien auszuwählen und abzuspielen.

var input = document.getElementById("file"); 
 
    var audio = document.getElementById("audio"); 
 
    var selectLabel = document.querySelector("label[for=select]"); 
 
    var audioLabel = document.querySelector("label[for=audio]"); 
 
    var select = document.querySelector("select"); 
 
    var context = void 0, 
 
     src = void 0, 
 
     res = [], 
 
     url = ""; 
 

 
    function processDirectoryUpload(event) { 
 
     var webkitResult = []; 
 
     var mozResult = []; 
 
     var files; 
 
     console.log(event); 
 
     select.innerHTML = ""; 
 

 
     // do mozilla stuff 
 
     function mozReadDirectories(entries, path) { 
 
     console.log("dir", entries, path); 
 
     return [].reduce.call(entries, function(promise, entry) { 
 
      return promise.then(function() { 
 
       return Promise.resolve(entry.getFilesAndDirectories() || entry) 
 
       .then(function(dir) { 
 
        return dir 
 
       }) 
 
      }) 
 
      }, Promise.resolve()) 
 
      .then(function(items) { 
 
      var dir = items.filter(function(folder) { 
 
       return folder instanceof Directory 
 
      }); 
 
      var files = items.filter(function(file) { 
 
       return file instanceof File 
 
      }); 
 
      if (files.length) { 
 
       // console.log("files:", files, path); 
 
       mozResult = mozResult.concat.apply(mozResult, files); 
 
      } 
 
      if (dir.length) { 
 
       // console.log(dir, dir[0] instanceof Directory); 
 
       return mozReadDirectories(dir, dir[0].path || path); 
 

 
      } else { 
 
       if (!dir.length) { 
 
       return Promise.resolve(mozResult).then(function(complete) { 
 
        return complete 
 
       }) 
 
       } 
 
      } 
 

 
      }) 
 

 
     }; 
 

 
     function handleEntries(entry) { 
 
     let file = "webkitGetAsEntry" in entry ? entry.webkitGetAsEntry() : entry 
 
     return Promise.resolve(file); 
 
     } 
 

 
     function handleFile(entry) { 
 
     return new Promise(function(resolve) { 
 
      if (entry.isFile) { 
 
      entry.file(function(file) { 
 
       listFile(file, entry.fullPath).then(resolve) 
 
      }) 
 
      } else if (entry.isDirectory) { 
 
      var reader = entry.createReader(); 
 
      reader.readEntries(webkitReadDirectories.bind(null, entry, handleFile, resolve)) 
 
      } else { 
 
      var entries = [entry]; 
 
      return entries.reduce(function(promise, file) { 
 
       return promise.then(function() { 
 
        return listDirectory(file) 
 
       }) 
 
       }, Promise.resolve()) 
 
       .then(function() { 
 
       return Promise.all(entries.map(function(file) { 
 
        return listFile(file) 
 
       })).then(resolve) 
 
       }) 
 
      } 
 
     }) 
 

 
     function webkitReadDirectories(entry, callback, resolve, entries) { 
 
      console.log(entries); 
 
      return listDirectory(entry).then(function(currentDirectory) { 
 
      console.log(`iterating ${currentDirectory.name} directory`, entry); 
 
      return entries.reduce(function(promise, directory) { 
 
       return promise.then(function() { 
 
       return callback(directory) 
 
       }); 
 
      }, Promise.resolve()) 
 
      }).then(resolve); 
 
     } 
 

 
     } 
 

 
     function listDirectory(entry) { 
 
     console.log(entry); 
 
     return Promise.resolve(entry); 
 
     } 
 

 
     function listFile(file, path) { 
 
     path = path || file.webkitRelativePath || "/" + file.name; 
 
     console.log(`reading ${file.name}, size: ${file.size}, path:${path}`); 
 
     webkitResult.push(file); 
 
     return Promise.resolve(webkitResult) 
 
     }; 
 

 
     function processFiles(files) { 
 
     Promise.all([].map.call(files, function(file, index) { 
 
      return handleEntries(file, index).then(handleFile) 
 
      })) 
 
      .then(function() { 
 
      console.log("complete", webkitResult); 
 
      res = webkitResult; 
 
      res.reduce(function(promise, track) { 
 
       return promise.then(function() { 
 
       return playMusic(track) 
 
       }) 
 
      }, displayFiles(res)) 
 
      }) 
 
      .catch(function(err) { 
 
      alert(err.message); 
 
      }) 
 
     } 
 

 
     if ("getFilesAndDirectories" in event.target) { 
 
     return (event.type === "drop" ? event.dataTransfer : event.target).getFilesAndDirectories() 
 
      .then(function(dir) { 
 
      if (dir[0] instanceof Directory) { 
 
       console.log(dir) 
 
       return mozReadDirectories(dir, dir[0].path || path) 
 
       .then(function(complete) { 
 
        console.log("complete:", webkitResult); 
 
        event.target.value = null; 
 
       }); 
 
      } else { 
 
       if (dir[0] instanceof File && dir[0].size > 0) { 
 
       return Promise.resolve(dir) 
 
        .then(function() { 
 
        console.log("complete:", mozResult); 
 
        res = mozResult; 
 
        res.reduce(function(promise, track) { 
 
         return promise.then(function() { 
 
         return playMusic(track) 
 
         }) 
 
        }, displayFiles(res)) 
 
        }) 
 
       } else { 
 
       if (dir[0].size == 0) { 
 
        throw new Error("could not process '" + dir[0].name + "' directory" + " at drop event at firefox, upload folders at 'Choose folder...' input"); 
 
       } 
 
       } 
 
      } 
 
      }).catch(function(err) { 
 
      alert(err) 
 
      }) 
 
     } 
 

 
     files = event.target.files; 
 

 
     if (files) { 
 
     processFiles(files) 
 
     } 
 

 
    } 
 

 
    function displayFiles(files) { 
 
     select.innerHTML = ""; 
 
     return Promise.all(files.map(function(file, index) { 
 
     return new Promise(function(resolve) { 
 
      var option = new Option(file.name, index); 
 
      select.appendChild(option); 
 
      resolve() 
 
     }) 
 
     })) 
 
    } 
 

 
    function handleSelectedSong(event) { 
 
     if (res.length) { 
 
     var index = select.value; 
 
     var track = res[index]; 
 
     playMusic(track) 
 
      .then(function(filename) { 
 
      console.log(filename + " playback completed") 
 
      }) 
 
     } else { 
 
     console.log("No songs to play") 
 
     } 
 
    } 
 

 
    function playMusic(file) { 
 
     return new Promise(function(resolve) { 
 
     audio.pause(); 
 
     audio.onended = function() { 
 
      audio.onended = null; 
 
      if (url) URL.revokeObjectURL(url); 
 
      resolve(file.name); 
 
     } 
 
     if (url) URL.revokeObjectURL(url); 
 
     url = URL.createObjectURL(file); 
 
     audio.load(); 
 
     audio.src = url; 
 
     audio.play(); 
 
     audioLabel.textContent = file.name; 
 
     context = context || new AudioContext(); 
 
     src = src || context.createMediaElementSource(audio); 
 
     src.disconnect(context); 
 

 
     var analyser = context.createAnalyser(); 
 

 
     var canvas = document.getElementById("canvas"); 
 
     canvas.width = window.innerWidth; 
 
     canvas.height = window.innerHeight; 
 
     var ctx = canvas.getContext("2d"); 
 

 
     src.connect(analyser); 
 
     analyser.connect(context.destination); 
 

 
     analyser.fftSize = 256; 
 

 
     var bufferLength = analyser.frequencyBinCount; 
 
     console.log(bufferLength); 
 

 
     var dataArray = new Uint8Array(bufferLength); 
 

 
     var WIDTH = canvas.width; 
 
     var HEIGHT = canvas.height; 
 

 
     var barWidth = (WIDTH/bufferLength) * 1; 
 
     var barHeight; 
 
     var x = 0; 
 

 
     function renderFrame() { 
 
      requestAnimationFrame(renderFrame); 
 
      x = 0; 
 

 
      analyser.getByteFrequencyData(dataArray); 
 

 
      ctx.fillStyle = "#1b1b1b"; 
 
      ctx.fillRect(0, 0, WIDTH, HEIGHT); 
 

 
      for (var i = 0; i < bufferLength; i++) { 
 
      barHeight = dataArray[i]; 
 

 
      var r = 5; 
 
      var g = 195; 
 
      var b = 45; 
 

 
      ctx.fillStyle = "rgb(5,195,45)" 
 
      ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight); 
 

 
      x += barWidth + 2; 
 
      } 
 
     } 
 

 
     renderFrame(); 
 
     }) 
 
    } 
 

 
    input.addEventListener("change", processDirectoryUpload); 
 
    select.addEventListener("change", handleSelectedSong);
<div id="content"> 
 
    Upload directory: <input id="file" type="file" accept="audio/*" directory allowdirs webkitdirectory/><br> 
 
    <br>Now playing: <label for="audio"></label><br> 
 
    <br><label for="select">Select a song to play:</label><br> 
 
    <select id="select"> 
 
    </select> 
 
    <canvas id="canvas"></canvas> 
 
    <audio id="audio" controls></audio> 
 
</div>

+0

Das funktioniert gut, aber jetzt wie würde ich verhindern, dass es bestimmte Dateierweiterungen wie jpg und png auswählen, um die "DOMException: Fehler beim Laden, weil keine unterstützte Quelle wurde gefunden." Fehler – Nickh90

+0

@NickHewitt Sie können nicht verhindern, dass ein Benutzer bestimmte Dateitypen auswählt. Sie können 'if..else' verwenden, um zu überprüfen, ob die' File' Objekt '.type' Eigenschaft mit' "audio" 'bei' playMusic' Funktion in der ersten Zeile innerhalb der Resolverfunktion des 'Promise' Konstruktors vor der Einstellung beginnt '.src' Eigenschaft von'