11526 sujets

JavaScript, DOM et API Web HTML5

Pages :
Bonjour,

Afin de personnaliser les lecteurs audio html5 je me suis lancé dans la création de l'un d'eux avec l'api javascript dédiée. Il me reste pas mal de choses à faire, pour l'instant j'ai rendu opérationnel les boutons lecture/pause, mute et l'affichage de la durée totale du fichier.

Pour la durée totale j'ai un soucis : parfois ça marche, parfois non, parfois en partie :
NaN:NaN:NaN

J'ai l'impression que c'est en lien avec la disponibilité des informations. Pourtant j'utilise un écouteur d'événement attendant que les données soient chargées :
audio.addEventListener('loadedmetadata', audioDuration(audio, output))

J'ai aussi essayé :
audio.addEventListener('load', audioDuration(audio, output))

Mais apparemment mon problème est plus loin ou plus avant...

Voici ma page de test en ligne (édit : lien changé) : audio test.

Un CodePen c'est un peu compliqué dans cette situation car je ne peu pas appeler toutes les ressources (notamment les sprites SVG), mais voici quand même en mode dégradé : CodePen.
Modifié par Olivier C (24 Apr 2023 - 01:14)
Mince : il s'agit d'un sujet "javascript" : si un modérateur peut faire quelque chose pour changer le tag...
Modérateur
Salut Olivier, Smiley smile

Normalement, la durée s'obtient comme ceci :

console.log(document.querySelector('audio').duration) // durée en seconde


Cependant, en faisant mes tests sur ton codepen, je n'obtiens pas les bonnes valeurs.
Salut Niuxe,

Mais les bonnes durées je les ai avec ceci (ligne 15 du code) :
const audioDuration = (audio, output) => {
  output.value = secondsToTime(audio.duration)
}

Et ça fonctionne mais... pas tout le temps. C'est ça que je n'arrive pas à comprendre.

Ça fonctionne un peu mieux sur mon site avec l'inspecteur ouvert (donc avec option "sans cache" chez moi). Je pense qu'il s'agit d'un problème de page pas finie de charger, mais je ne vois pas comment faire pour résoudre le problème pour l'instant.
Modifié par Olivier C (17 Apr 2023 - 21:36)
Modérateur
Je pense que le problème vient du fait que tu affiches alors que le calcul de la durée ne s'est pas fait. Je sais que ce que je vais te dire, c'est franchement dégueu. Mais c'est juste un test :
ajoutes un setTimeout de 2 secondes avant d'afficher.
Modifié par niuxe (17 Apr 2023 - 11:17)
Argh : oui j'avais pensé à ça, et c'est pour cela que j'avais mis un 'loadedmetadata' pour éviter cela. Je le ferais peut-être mais en dernier recours.
Modérateur
Ce que je viens de faire :
- ajouter un window.addEventListener('load' ...
- changer le calcul de la duration

ça a l'aire d'être ok : https://codepen.io/niuxe/pen/poxyXNZ

ps : tu peux placer ton html dans un élément <template> ou dans <script id="mon_template" type:"text/template"></script>
Modifié par niuxe (16 Apr 2023 - 18:40)
niuxe a écrit :
ça a l'aire d'être ok

Pas chez moi. J'ai essayé ce que tu m'as suggéré, mais ça ne marche pas mieux. Je ne l'ai peut-être pas utilisé au bon endroit :
setTimeout(audio.addEventListener('load', audioDuration(audio, output)), 2000)

Ah oui mais si j'oublie de mettre une fonction dans le setTimeout aussi... Avec 100ms ça marche et ce n'est pas trop pire :
setTimeout(() => audioDuration(audio, output), 100)

J'enlève au passage le addEventListener qui ne sert à rien a priori. Je ne voulais pas en passer par là mais ce n'est pas trop visible et je vais faire avec pour l'instant. Merci à toi Niuxe.
Modifié par Olivier C (17 May 2023 - 05:56)
Salut,
je suppose que tu veux faire ton propre développement, en partant de zéro, ce qui est une bonne chose.
Parce que sinon, j'ai en production un lecteur audio htm 5 et JavaScript très souple. Je l'ai même modifié pour en faire un lecteur avec avance sur le prochain titre, mais sans liste de lecture, qui prend toujours beaucoup de place en dessous du lecteur. Les titres s'affichent à côté des boutons avance et stop, sur la time line. Barre de progression, durée, volume, tout y est. Et tout peut être coloré à ton goût.
Quand tu auras réglé le problème actuel, tu ajouteras quelques lignes de JavaScript afin que le lecteur en cours s'arrête quand tu en enclenche un autre. Ce qui n'est pas le cas actuellement sur le modèle que tu as montré. Ça ne pose pas trop de problème sur des lecteurs disposés proches les uns des autres, mais s'ils sont loin sur la page, c'est très gênant.
Salut Bongota.

Oui, l'idée est d'avoir mes propres outils. Et, oui, il y aura à terme une option pour un seul lecteur en cours. Mais je n'en suis pas là. Il faut d'abord que je fasse une version 1.0 proche des fonctionnalités de base des lecteurs par défaut des navigateurs, on verra ensuite pour les ajouts.

Il est pas mal ton lecteur audio js, tout a fais dans la veine de ce que je veux faire en terme de fonctionnalité. Tu utilises quoi ?
niuxe a écrit :
Tu peux placer ton html dans un élément <template>

Oui, c'est le genre d'optimisation que je ferais peut-être une fois que j'aurais dégrossis le truc.

Je n'ai pas encore trouvé la soluce, mais en tout cas je te remercie pour le temps que tu m'a déjà consacré.
J'utilise : https://web.silvercherry.fr/player.html
Le javascript est conséquent, mais c'est pour justement permettre des ajustements.
Sur mon site, j'ai rajouté dès la page d'accueil le lecteur dont je parle dans mon précédent post. Ce sont tous les titres du site en version très courte, mais sans liste encombrante, que j'ai enlevée en css. Juste une indication pour le visiteur qui n'a pas le courage d'aller plus loin. Les autres lecteurs du site, du même code, sont ordinaires, plus larges et sans liste.
Moi aussi, j'envisage de faire mon lecteur audio en JavaScript, afin d'apprendre. J'ai déjà fait deux boutons, avance et stop, c'est tout. Il me faut juste le courage de m'y remettre.
Et il est sous une licence cc permettant de le modifier et de l'utiliser en production.
Le code qui permet à un lecteur de se couper quand on clique sur un autre, je l'ai trouvé sur stackoverflow.
Modifié par Bongota (16 Apr 2023 - 19:23)
Tiens, je viens de trouver un exemple MDN assez basique (que pour un lecteur, html en dur...), mais qui a le mérite de montrer un pannel de commande de l'API assez complet : le code js.

C'est un lecteur vidéo, mais je m’aperçois que les commandes sont exactement les mêmes. Tant mieux, lorsque je me collerais à coder un lecteur vidéo je pourrais sans doute tout reprendre.

Je crois bien que ton dev de DragonPlay s'en est inspiré, ou alors ils ont la même source car j'ai trouvé des similitudes dans le code (après c'est peut-être normal).
Modifié par Olivier C (16 Apr 2023 - 23:00)
Au fait pour la solution, voilà comment j'ai fais au final (pas beau...) :
// @bugfixed Retarde la fonction pour qu'elle ait le temps d'appliquer la valeur à l'output qui, lui aussi, est généré en JavaScript.
// @note Plusieurs applications pour appliquer au plus tôt dans le meilleur des cas avec des rattrapages plus éloignés au cas où.
// @todo Trouver une solution asynchrone ?
//audioDuration(audio, output)
setTimeout(() => audioDuration(audio, output), 50)
setTimeout(() => audioDuration(audio, output), 100)
setTimeout(() => audioDuration(audio, output), 500)
setTimeout(() => audioDuration(audio, output), 1000)
Olivier C a écrit :
Tiens, je viens de trouver un exemple MDN assez basique (que pour un lecteur, html en dur...), mais qui a le mérite de montrer un pannel de commande de l'API assez complet : le code js.

C'est un lecteur vidéo, mais je m’aperçois que les commandes sont exactement les mêmes. Tant mieux, lorsque je me collerais à coder un lecteur vidéo je pourrais sans doute tout reprendre.

Je crois bien que ton dev de DragonPlay s'en est inspiré, ou alors ils ont la même source car j'ai trouvé des similitudes dans le code (après c'est peut-être normal).


Oui, que ce soit de la vidéo ou de l'audio, j'ai aussi remarqué que le lecteur audio html 5 est quasiment similaire. Simplement pour l'image, il faut donner les dimensions de la vidéo, éventuellement utiliser "poster" afin de choisir l'image d'accueil qui sera affichée, sinon ce sera la première de la vidéo.

C'est possible que DragonPlay se soit inspiré. Je ne maîtrise pas assez le JavaScript pour aller le simplifier, si ça en vaut la peine. À noter que sur ce lecteur, le choix de faire un lecteur simple ou un lecteur avec liste, ou liste cachée comme le mien ne dépend que du html et css. On ne touche pas au JavaScript.
Tiens, Bongota, puisque tu es encore là : c'est quoi ton code pour mettre "pause" les éléments media sur la lecture du dernier élément cliqué ? (Quand on pose bien le problème on a quasiment déjà la réponse).

J'ai une petite idée mais ça m'évite de réinventer la roue à chaque fois.

Sinon, au final, j'ai rendu plus robuste ma fonction de calcul de l'heure, qui rend "00" si valeurs nulles :
const secondsToTime = e => { // @see  https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds
 
  let hh = Math.floor(e / 3600).toString().padStart(2, '0'),
      mm = Math.floor(e % 3600 / 60).toString().padStart(2, '0'),
      ss = Math.floor(e % 60).toString().padStart(2, '0')
  if (hh == '00') hh = null // Si pas d'heures, alors info sur les heures escamotée.
  if (isNaN(hh)) hh = null // Si valeur nulle, alors info sur les heures escamotée.
  if (isNaN(mm)) mm = '00'
  if (isNaN(ss)) ss = '00'
  return [hh, mm, ss].filter(Boolean).join(':')
}

Du coup, en cas de valeurs nulles je n'ai plus de "NaN:NaN:NaN" comme rendus mais plutôt des "00:00". Ce qui est moins moche et me permet de n'appliquer un setTimeout qu'une seule fois :
// @bugfixed Réapplication de la fonction pour qu'elle ait le temps d'appliquer la valeur à l'output qui, lui aussi, est généré en JavaScript.
// @todo Trouver une solution asynchrone ?
mediaDuration(media, output)
setTimeout(() => mediaDuration(media, output), 1000)

Notons que j'ai changé le nom d'accroche de mes variables et fonctions, "audio*" devient "media*". Dans la perspective de coder un lecteur vidéo avec le même code...
Avec les lecteurs audio html 5, il est communément admis qu'il n'y a pas de bouton stop. C'est le bouton pause qui fait office, ça revient au même.
Je viens de vérifier sur un autre de mes site où il y a un lecteur html 5 simple sans JavaScript. Il y a un bouton avance et un bouton pause, pas de stop.
Si tu veux le code, il faut aller voir le JavaScript de DragonPlay, tu connais mieux que moi le JS pour le trouver. Pour le moment, j'en suis à un bouton avance et un bouton pause. Je ne me suis pas encore attaqué à la barre de progression, ni au timing.
Modifié par Bongota (17 Apr 2023 - 11:04)
Modérateur
Olivier C a écrit :
Au fait pour la solution, voilà comment j'ai fais au final (pas beau...) :
// @bugfixed Retarde la fonction pour qu'elle ait le temps d'appliquer la valeur à l'output qui, lui aussi, est généré en JavaScript.
// @note Plusieurs applications pour appliquer au plus tôt dans le meilleur des cas avec des rattrapages plus éloignés au cas où.
// @todo Trouver une solution asynchrone ?
//audioDuration(audio, output)
setTimeout(() =&gt; audioDuration(audio, output), 50)
setTimeout(() =&gt; audioDuration(audio, output), 100)
setTimeout(() =&gt; audioDuration(audio, output), 500)
setTimeout(() =&gt; audioDuration(audio, output), 1000)


Le setTimeout c'etait un test et non une solution. C'est bien ce qu'il me semble. le contenu html se charge alors que l'audio n'est pas. Il faudrait que tu vois avec une promesse. Sinon, la solution que je t'ai soumise sur le codepen fonctionne. As tu bien vidé le cache ?