2017-07-27 1 views
1

Je voudrais être en mesure de sélectionner un dossier de musique et de mélanger toutes les chansons une fois sur charger et avoir un bouton de saut + retourner le nom du fichier de la chanson au visualiseur afin qu'il puisse visualiser chaque chanson. J'apprends encore les tableaux et les boucles, donc je ne sais pas comment faire. Je veux aussi éviter les bibliothèques supplémentaires pour l'instant car tout est déjà fourni. Voici un extrait de code de ce que j'ai jusqu'à présentSélection de dossier de musique 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

Quel problème vous avez avec le code HTML et JavaScript à la question? – guest271314

+0

Je ne sais tout simplement pas comment configurer les tableaux et les boucles pour cela. Je suis très sûr que je devrais configurer une forme de tableau pour rassembler tous les fichiers audio dans le dossier que j'ai sélectionné et dans les dossiers enfants. Je dois également modifier ces tableaux ou en faire un nouveau avec l'emplacement de chaque chanson et l'ordre aléatoire. J'ai l'idée de base dans ma tête, je ne suis pas sûr de savoir comment l'exécuter. – Nickh90

+0

Vous pouvez définir les attributs 'webkitdirectory' et' allowdirs' dans l'élément '' pour activer le téléchargement d'annuaire. Itérer tous les répertoires téléchargés pour obtenir tous les objets 'File' téléchargés dans les répertoires, définis comme éléments d'un tableau, voir [Comment télécharger et lister les répertoires sur firefox et chrome/chrome en utilisant les changements et les abandons] (https: // stackoverflow. com/q/39664662 /) – guest271314

Répondre

1

Vous pouvez définir webkitdirectory et allowdirs attributs à l'élément <input type="file"> pour permettre le téléchargement de répertoire. De manière récursive, ou en utilisant Promise itérer de façon répétée les répertoires, y compris les répertoires dans les répertoires, pousser tous les fichiers dans les répertoires vers un tableau globalement défini d'objets File, voir How to upload and list directories at firefox and chrome/chromium using change and drop events; où JavaScript à la réponse est modifié pour supprimer le gestionnaire d'événements drop, qui n'est spécifiquement pas une partie de l'exigence.

Utilisation Array.prototype.reduce() et Promise pour appeler une fonction pour chaque objet File en séquence pour lire les médias et renvoyer un événement rempli Promise à ended de HTMLMediaElement; par exemple, la fonction anonyme du gestionnaire change de Question, modifiée si nécessaire pour atteindre l'exigence attendue d'une liste de lecture créée à partir du téléchargement de N répertoires ou de N répertoires imbriqués. Notez que lorsque vous appelez AudioContent.createMediaElementSource() plus d'une fois avec le même élément <audio> comme paramètre une exception sera levée

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

voir remove createMediaElementSource. Vous pouvez définir les variables globalement et référencer la variable en utilisant OU || pour éviter l'exception.

Le créé Blob URL est affecté à une variable et révocable à l'événement ended de HTMLMediaElement et avant d'être réaffecté lorsque la fonction est appelée à nouveau, si l'événement est ended pas atteint.

Inclus <select> élément pour pouvoir sélectionner et lire l'un des fichiers téléchargés.

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

Cela fonctionne très bien mais maintenant comment je l'empêcherais de pouvoir sélectionner certaines extensions de fichiers comme jpg et png pour éviter le "DOMException: Impossible de charger car aucune source prise en charge a été trouvé." erreur – Nickh90

+0

@NickHewitt Vous ne pouvez pas empêcher un utilisateur de sélectionner certains types de fichiers. Ce que vous pouvez faire est d'utiliser 'if..else' pour vérifier si la propriété' File' de l'objet '.type' commence par' 'audio '' à la fonction 'playMusic' à la première ligne de la fonction de résolution du constructeur' Promise' avant le réglage Propriété '.src' de'