I have found the following code to insert only the audio instead of embedding a YouTube video on your website:
I have made some modifications to try to understand it better and adapt it to my situation:
The HTML:
<span class="ml-auto"> <!--Reproductor de sonido-->
<span class="audio-youtube" data-video="<?=$id_youtube?>"></span>
<span class="caja-youtube"></span>
</span>
The JS:
/* 1. Carga asíncrona de la API Iframe de YouTube */
var tag = document.createElement('script'); //Creación de un elemento <script>
tag.src = "https://www.youtube.com/iframe_api"; //Definición del src del <script>
var firstScriptTag = document.getElementsByTagName('script')[0]; //Se toma el primero de todos los elementos <script> que hay en <head>;
//en mi caso es uno de jQuery que necesita Bootstrap para su funcionamiento
var newNode = firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); //Inserta un nodo (tag) antes del nodo de referencia (firstScriptTag) como hijo de un nodo padre (firstScriptTag.parentNode) indicado
//tag es el <script> creado
//firstScriptTag es el primer <script> del <head>
//firstScriptTag.parentNode es todo el <head>
//newNode equivale a tag
//Creo que lo que hace es simplemente insertar el nuevo <script> como el primero del <head>
/* 2. Función que crea un <iframe> conteniendo el reproductor de YouTube */
function onYouTubeIframeAPIReady()
{
var caja = document.getElementsByClassName("caja-youtube"); //<span> vacío
var enlaceYT = document.getElementsByClassName("audio-youtube"); //<span> con el enlace de YouTube de cada canción
var imagen = document.createElement("img"); //Creación de un elemento <img>
imagen.setAttribute("class", "imagen-youtube"); //Le adjudica un id a la imagen
imagen.style.cssText = "cursor: pointer; width: 40px; margin-top: 1.5px;"; //Le da estilos CSS a la imagen
enlaceYT.appendChild(imagen); //Añade la imagen al <span> que contiene el enlace de YouTube
var div = document.createElement("div"); //Creación de un <div>
div.setAttribute("class", "reproductor-youtube"); //Le adjudica un id al div
caja.appendChild(div); //Añade el div al <span> vacío
var toggleButton = function(play) //Controla que se muestre el botón de encendido o de pausa
{
var boton = play ? "GddldI3.png" : "XrAWYmu.png"; //Si play = true muestra una imagen (botón de encendido) y si no otra (botón de pausa)
imagen.setAttribute("src", "https://i.imgur.com/" + boton); //Le añade el src apropiado al elemento <img> creado antes
}
var reproductor = new YT.Player("reproductor-youtube", //Creación de un objeto "reproductor" a partir de la clase YT.Player proporcionada por la API, que además relaciona con el <div> creado antes mediante su id
{
height: "0", //Características del objeto
width: "0", //Altura y anchura nulas
videoId: enlaceYT.dataset.video, //Id del vídeo
playerVars:
{
autoplay: enlaceYT.dataset.autoplay, //Inicio automático
loop: enlaceYT.dataset.loop, //Reproducción en bucle
},
events: //Eventos
{
'onReady': function(e) //Creo que hace referencia a cuando se termina de cargar el DOM
{
reproductor.setPlaybackQuality("small");
toggleButton(reproductor.getPlayerState() !== YT.PlayerState.CUED);
},
'onStateChange': function(e) //Si termina el vídeo, se cambia la imagen a pausa
{
if(e.data === YT.PlayerState.ENDED) toggleButton(false);
}
}
});
enlaceYT.onclick = function() //Al hacer click en el <span> que contiene el enlace de YouTube
{
if(reproductor.getPlayerState() === YT.PlayerState.PLAYING || reproductor.getPlayerState() === YT.PlayerState.BUFFERING)
{
reproductor.pauseVideo(); //Se pausa el objeto reproductor
toggleButton(false);
}
else
{
reproductor.playVideo(); //Se enciende el objeto reproductor
toggleButton(true);
};
};
};
There is also CSS code, but in my case I am not using it.
Well, the problem is that this code works according to id
and does not class
, so it only paints a video; my intention is that several can be displayed, coming from a PHP loop, each one with its data-video
loaded in a variable:
<span id="youtube-audio" data-video="<?=$id_youtube?>"></span>
I've tried changing the getElementById
ones from the JS script to getElementsByClassName
and the ones id
from the HTML to class
but, surprise, it doesn't work.
I suppose that you have to create, through a JS loop, an object reproductor
from the class YT.Player
for each song that the PHP loop paints...
Hope someone can guide me on what to do. Thanks in advance.
EDIT 1 :
I have modified the function to incorporate a loop for
:
function onYouTubeIframeAPIReady()
{
/* Las dos siguiente variables son conjuntos de elementos, no estrictamente arrays */
var cajas = document.getElementsByClassName("caja-youtube"); //<span> vacío que albergará el reproductor de audio
var enlacesYT = document.getElementsByClassName("enlace-youtube"); //<span> con el enlace de YouTube de cada canción
for(var i = 0; i < enlacesYT.length; ++i)
{
var imagen = document.createElement("img"); //Creación de un elemento <img>
imagen.setAttribute("id", `imagen-youtube-${i}`); //Le adjudica un id al <img>
imagen.style.cssText = "cursor: pointer; width: 40px; margin-top: 1.5px;"; //Le da estilos CSS al <img>
enlacesYT[i].appendChild(imagen); //Incluye el <img> dentro del <span> "enlace"; posteriormente, la función toggleButton lo convierte en la imagen del botón de YouTube
var div = document.createElement("div"); //Creación de un <div> que albergará el reproductor de audio
div.setAttribute("id", `reproductor-youtube-${i}`); //Le adjudica un id al div
cajas[i].appendChild(div); //Incluye el div en el <span> vacío "caja"
var toggleButton = function(play) //Controla que se muestre el botón de encendido o de pausa
{
var boton = play ? "GddldI3.png" : "XrAWYmu.png"; //Si play = true muestra una imagen (botón de encendido) y si no otra (botón de pausa)
imagen.setAttribute("src", "https://i.imgur.com/" + boton); //Le añade el src apropiado al elemento <img> creado antes
}
var reproductor = new YT.Player(`reproductor-youtube-${i}`, //Creación de un objeto "reproductor" a partir de la clase YT.Player proporcionada por la API, que además relaciona con el <div> creado antes mediante su id
{
height: "0", //Características del objeto
width: "0", //Altura y anchura nulas
videoId: enlacesYT[i].dataset.video, //Id del vídeo
playerVars:
{
autoplay: enlacesYT[i].dataset.autoplay, //Inicio automático
loop: enlacesYT[i].dataset.loop, //Reproducción en bucle
},
events: //Eventos
{
'onReady': function(e) //Creo que hace referencia a cuando se termina de cargar el DOM
{
reproductor.setPlaybackQuality("small");
toggleButton(reproductor.getPlayerState() !== YT.PlayerState.CUED);
},
'onStateChange': function(e) //Si termina el vídeo, se cambia la imagen a pausa
{
if(e.data === YT.PlayerState.ENDED) toggleButton(false);
}
}
});
enlacesYT[i].onclick = function() //Al hacer click en el <span> que contiene el enlace de YouTube
{
if(reproductor.getPlayerState() === YT.PlayerState.PLAYING || reproductor.getPlayerState() === YT.PlayerState.BUFFERING)
{
reproductor.pauseVideo(); //Se pausa el objeto reproductor
toggleButton(false);
}
else
{
reproductor.playVideo(); //Se enciende el objeto reproductor
toggleButton(true);
};
};
}
};
Being the HTML, which is included in a PHP loop, the following:
<span class="ml-auto"> <!--Reproductor de sonido-->
<span class="enlace-youtube" data-video="<?=$id_youtube?>"></span>
<span class="caja-youtube"></span>
</span>
If we add a console.log(reproductor)
after creating the var reproductor
, it seems to work; in case the PHP loop paints three songs:
However, the JS loop seems to grind through the elements and only paints the last one:
This for three different lists; if it is a single list with three songs, the same:
The only error that appears in relation to the script is the following:
The error repeats, but there doesn't seem to be n-1 errors (that is, it just didn't fail for the last song), but a certain number that I can't relate to the number of songs; sometimes it is n-1, but other times it is not, it is n-2 or even n-3.
EDIT 2 :
Inside the onReady
, I have commented //reproductor.setPlaybackQuality("small");
out and set toggleButton()
to false
, and the error messages go away, but the player still appears for only the last song.
EDIT 3 :
I've found that when I click where the YouTube player button should be for any song, the last song starts playing. One is missing this
somewhere.
Let's see if we can help you.
First Search for the video of which you want to insert the audio only on a website. When you have it, look in the browser for the web address, as you need to know the video ID, the set of letters that comes after 'v='. In this case it would be ' BtV1-gJ_bm0 ' since we have chosen a theme song by The Cranberries (one of the best songs of all time ;) ).
Now we need to add these lines to the HTML code:
on the website where you want to implement the video, and modify the part that says ' VIDEO_ID ' for the video you took from the browser.
Edit: If you need it inside a php loop to paint multiple songs, you can do it with the " ForEach " Loop:
Assuming you have the Videos ID stored in an array ($array):
With this you should already have the window, with all the inserted conditions (or VideoID) of YouTube that you have inside the $array , and when you hit Play start playing. If you want it to play automatically, you can do it simply by changing the data-autoplay="0" section of the code to 1. If you want the audio to play in a continuous loop, change the value of the data-loop= section to 1 “0”. This code internally renders YouTube using the IFRAME player, so it will work on both desktop and smartphone browsers.
Good luck and success brother!
I'm not sure this will work, but the proposal is:
.getElementsByClassName()
uses.querySelectorAll()
, which allows you to loop through.forEach()
and makes the code a bit easier, accessing only the variable, with no indextoggleButton()
outside of the loop, so you only have one, instead of one for each player. You must send the link and status as a parameterlet
instead ofvar
to limit the context where they will be available; an easy way to explain it is that each variable will only be visible in the corresponding player, because it is created in each iteration of the loop, while withvar
uses the same variable for all, updating value in each iterationUnique functions could also be created for the player events, but I can't remember how to access the DOM elements from the player.