Je souhaite lire un livre audio sur ma page Web. Le livre audio est un fichier .zip, qui contient plusieurs fichiers .mp3, un pour chaque chapitre du livre. La durée d'exécution de tous les fichiers est de plusieurs heures et leur taille cumulée est de 60 Mo. Le .zip est stocké côté serveur (Express.js)

Comment puis-je lire chaque fichier successivement dans le client (dans un élément <audio> par exemple), pour que le livre audio soit lu de manière fluide, comme si 1 fichier?

Dois-je utiliser un objet MediaStream? Si c'est le cas, comment?

-Merci

1
Trever Thompson 24 avril 2020 à 21:04

3 réponses

Meilleure réponse

Je jetterais un œil à cette réponse sur une autre question de dépassement de pile, mais j'ai apporté quelques modifications afin de répondre à votre question. :

var audioFileURLs= [];

function preloadAudio(url) {
    var audio = new Audio();
    // once this file loads, it will call loadedAudio()
    // the file will be kept by the browser as cache
    audio.addEventListener('canplaythrough', loadedAudio, false);
    audio.src = url;
}

var loaded = 0;
function loadedAudio() {
    // this will be called every time an audio file is loaded
    // we keep track of the loaded files vs the requested files
    loaded++;
    if (loaded == audioFileURLs.length){
        // all have loaded
        init();
    }
}

var player = document.getElementById('player');
function play(index) {
    player.src = audioFiles[index];
    player.play();
}

function init() {
    // do your stuff here, audio has been loaded
    // for example, play all files one after the other
    var i = 0;
    // once the player ends, play the next one
    player.onended = function() {
        i++;
        if (i >= audioFiles.length) {
            // end 
            return;
        }
        play(i);
    };
    // play the first file
    play(i);
}

// call node/express server to get a list of links we can hit to retrieve each audio file
fetch('/getAudioUrls/#BookNameOrIdHere#')
.then(r => r.json())
.then(arrayOfURLs => {
    audioFileURLs = arrayOfURLs
    arrayOfURLs.map(url => preloadAudio(URL))
})

Et puis juste avoir un élément audio à l'écran avec l'ID de "joueur" comme <audio id="player"></audio>

Cependant, avec cette réponse, le tableau arrayOfURLs doit contenir des URL vers une API sur votre serveur qui ouvrira le fichier zip et renverra les données mp3 spécifiées. Vous pouvez également vouloir prendre cette réponse comme référence générale et non comme une solution complète car il y a une optimisation à faire. Vous ne devriez probablement charger le premier fichier audio que dans un premier temps, et environ 5 minutes avant la fin du premier fichier, vous voudrez peut-être commencer le préchargement du suivant, puis répéter ce processus pour la totalité ... Tout sera à la hauteur vous, mais cela devrait vous mettre sur pied.

Vous pouvez également rencontrer un problème avec l'élément audio, car il n'affichera que la longueur du segment audio actuel sur lequel il se trouve, et non la longueur totale du livre audio. Je choisirais de croire que ce fichier zip a le livre séparé par chapitre correct? Si c'est le cas, vous pouvez créer un sélecteur de chapitre, cela vous permet de passer à un chapitre spécifique, également appelé URL getAudioUrls.

J'espère que ça aide!


Une autre note pour vous ... en lisant votre commentaire sur une réponse potentielle ci-dessous, vous pouvez combiner tous les fichiers audio en un seul en utilisant une sorte de module de nœud (audioconcat est celui que j'ai trouvé après une recherche rapide sur Google) et renvoyer ce fichier au client. Cependant, je ne prendrais pas personnellement cette route car l'intégralité du livre audio sera dans la mémoire du serveur pendant qu'il les combine et jusqu'à ce qu'il le retourne au client. Cela pourrait entraîner des problèmes de mémoire en cours de route, donc je l'éviterais si je le pouvais. Cependant, je dois admettre que cette option pourrait être potentiellement intéressante car la longueur totale du livre audio s'affichera dans la chronologie des éléments audio.


La meilleure option est peut-être de stocker les livres dans leur intégralité et dans les chapitres dans un fichier details.json dans le fichier zip et de l'envoyer au client lors du premier appel d'API avec les URL de chaque fichier audio. Cela vous permettrait de créer une belle interface utilisateur.

2
Darryl Huffman 24 avril 2020 à 22:20

La seule option à laquelle je peux penser est d'utiliser soit un décodeur mp3 javascript (ou compilé un décodeur C en asm.js / wasm) et d'utiliser les API audio. Ou enveloppez le mp3 dans un mp4 en utilisant quelque chose comme mux.js et utilisez des extensions de source multimédia pour la lecture.

0
szatmary 24 avril 2020 à 20:43

Peut-être que cela vous aidera

<audio controls="controls">
  <source src="track.ogg" type="audio/ogg" />
  <source src="track.mp3" type="audio/mpeg" />
Your browser does not support the audio element.
</audio>
-2
htemele 24 avril 2020 à 18:38