How do I dynamically change multiple video sources using JavaScript? - javascript

I'm trying to dynamically change the video source with the onclick event.
Here's the HTML:
<video autoplay loop poster="1.jpg" id="bg">
<source src="/static/media/1.webm" type="video/webm">
<source src="/static/media/1.mp4" type="video/mp4">
</video>
In onclick I generate a random link, then I change the source of the <video> element:
window.onclick = function() {
var randint = Math.floor(Math.random() * 10) + 1;
var srcmp4 = "http://127.0.0.1:8888/static/media/" + randint.toString() + ".mp4";
document.getElementById('bg').src=srcmp4;
};
If I try to access the source element the same way, by assigning it an id:
<source id="webmid" src="/static/media/1.webm" type="video/webm">
I get null.
I want to dynamically change both .jpg, .webm, .mp4 links. How do I access and assign multiple source elements inside video tag via JS?

The video tag is missing width, height, and controls attributes. Try this:
<video width="320" height="240" id="bg" autoplay loop controls>
<source src="/static/media/1.webm" type="video/webm">
<source src="/static/media/1.mp4" type="video/mp4">
</video>
Additionally here is the new js:
window.onclick = function() {
var randint = Math.floor(Math.random() * 10) + 1;
var srcmp4 = "http://127.0.0.1:8888/static/media/" + randint.toString() + ".mp4";
var video = document.getElementById('bg');
var source = document.getElementByTagName('source');
source = srcmp4;
video.load();
};
After changing that, the source seems to change according to this test.

So i did some reading. First i tried deleting children of video, creating new source elements and appending to video, everything worked in page source, but view didn't render any changes.
So i followed .canPlayType route to determine if client supports .webm, and if not -- assigning mp4 src directly to video element.
Also added small fix so random generated numbers won't repeat. Random video loads when page is loaded and on click events afterwards. Here is the code, it's a mess:
<video autoplay loop poster="" id="bg">
</video>
<script type="text/javascript">
function randlink(a,b){
// generate random int in range of a,b. return str
var c = Math.floor(Math.random()*b)+a;
return "/static/media/"+c.toString();
}
//assign video new random src and poster on page load
window.onload = function(){
var bgvid = document.getElementById('bg');
var randbase = randlink(1,10);
bgvid.poster = randbase + ".jpg";
//check if webm, else mp4 src
if(bgvid.canPlayType('video/webm; codecs="vp8, vorbis"') != ""){
bgvid.src = randbase+".webm";
} else { bgvid.src = randbase+".mp4"}
//change src and poster on click
window.onclick = function() {
var randbase2 = randlink(1,10);
//check if unique
do{
randbase2 = randlink(1,10)
} while (randbase2 == randbase);
randbase = randbase2;
bgvid.poster = randbase2 + ".jpg";
var webmstr = ".webm";
//check if previous was webm, else mp4
if(bgvid.src.indexOf(webmstr) > 0){
bgvid.src = randbase2 +".webm";
}else{
bgvid.src = randbase2 +".mp4";
}}
};

I've already answered this before here: Can I use javascript to dynamically change a video's source?
You have to give the source tags different ids and then add another document.getElementById("source").src = "ANOTHER_SOURCE"; after the first one

Related

Uploaded .mov video plays out of sync

After uploading the videos into the server, and you try to watch by clicking the play button the videos with the (.mp4) format plays well smoothly but the (.mov) video plays out of sync, like the voice delays, but if you download it, it plays normally with no problem. I don't know what could be the problem and the potential solution for it. I've tried Preloading but did not work.
My HTML the src is placed dynamically
<div class="video-player" id="videoPlayer">
<video width="100%" controls autoplay id="talentVideo">
<source src="" type="video/mp4">
<source src="" type="video/qt">
</video>
<i class="fas fa-times close-btn" onclick="stopVideo()"></i>
</div>
My Js code:
<script>
var videoPlayer = document.getElementById("videoPlayer");
var talentVideo = document.getElementById("talentVideo");
function stopVideo(){
videoPlayer.style.display = "none";
talentVideo.pause();
talentVideo.currentTime = 0;
}
const playVideoBtn = document.querySelectorAll('.video-tal .pathLinkToPlay');
for(let i = 0; i < playVideoBtn.length; i++){
// playVideoBtn[i].addEventListener("click", function(){ alert("Hello World!"); });
playVideoBtn[i].onclick = ()=>{
var videopath = playVideoBtn[i].getAttribute('data-id'); //getting the url of clicked video
window.videoPlayingId = playVideoBtn[i].getAttribute('id'); //getting the id of clicked video
window.roleId = playVideoBtn[i].getAttribute('data-role-id'); //getting the role_id of clicked video
window.talentId = playVideoBtn[i].getAttribute('data-talent-id'); //getting the talent_id of clicked video
playVideo(videopath);
}
}
function playVideo(videopath){
talentVideo.src = videopath;
videoPlayer.style.display = "block";
}

Change audio file on button click

I am trying to change the audio file on a button click and am getting the error
Uncaught TypeError: audio.load is not a function
My code is below, the idea is to press the button and then the audio file will change.
Without the audio.load() line, the code will run and the src will update, but the audio does not change. What am I missing?
HTML:
<!DOCTYPE HTML>
<html>
<body>
<br>
<audio controls>
<source src = "audio_file_1.mp3"
id="audio" type="audio/mpeg">
Your browser does not support the audio element!
</audio>
<br>
<button onClick="changeAudio();">Change</button>
</body>
<script src="temp.js"></script>
</html>
Javascript:
// temp js
var a = 1;
function changeAudio() {
var audio = document.getElementById('audio');
if (a==1) {
audio.src = 'audio_file_1.mp3';
a = 2;
}
else {
audio.src = 'audio_file_2.mp3';
a = 1;
}
audio.load();
}
changeAudio();
(also, if anyone knows example sound files that I can use instead of the audio_file_1.mp3 and audio_file_2.mp3, I would be happy to update the code so anyone can run it more easily)
Edit WRT Rob M's answer:
For anyone with the same problem, the solution is to change two lines:
First, in the HTML code, the <audio control> should turn to <audio control id="audio_id">
Second, in the javascript code the audio.load() should turn to document.getElementById('audio_id').load();
There is no .load() event on a <source> tag, it is on the <audio> tag - update your code to call load() on the parent <audio> tag and it should work.
Well, I think you are trying to access to <audio> element by its id attribute, but you haven't set id attribute to audio tag.
It must be something like this
<audio id="audio" controls>
<source src = "audio_file_1.mp3"
id="track" type="audio/mpeg">
Your browser does not support the audio element!
</audio>
And changing audio file:
var a = 1;
function changeAudio() {
var audio = document.getElementById('audio');
if (a==1) {
document.getElementById('track') = 'audio_file_1.mp3';
a = 2;
}
else {
document.getElementById('track') = 'audio_file_2.mp3';
a = 1;
}
audio.load();
}
changeAudio();

HTML5 video custom controls for any number of videos on the page

mates!
I was needed a simple text button – "Play". It should be hidden if video is playing and should be visible when video ends. Everything works fine, but it works only if I have one video on the page with unique ID.
HTML:
<video id="main-video" width="640" height="480">
<source src="media//mp4/video.mp4" type="video/mp4">
</video>
<span id="custom-play-button">Play</span>
And here is the JS:
window.onload = function() {
var video = document.getElementById("main-video");
var playButton = document.getElementById("custom-play-button");
playButton.addEventListener("click", function() {
document.getElementById('main-video').addEventListener('ended',myHandler,false);
video.play();
playButton.style.visibility = "hidden";
function myHandler(e) {
playButton.style.visibility = "visible";
}
});
}
But what should I do if there will be 4,5,6...100 videos on the page (and there will be)? I can't handle with 100 unique ID...
You can put every video and button in a parent div tag as below.
<div class="video-container">
<video id="main-video" width="640" height="480">
<source src="media//mp4/video.mp4" type="video/mp4">
</video>
<span id="custom-play-button">Play</span>
</div>
I'm using jQuery code, you can translate it to plain JS easily.
This should work.
$(".video-container").each(function () {
var video = $(this).find("video");
var plainVideo = video.get(0);/*DOM video object, unwrapped from jQuery*/
var playBtn = $(this).find("span");
playBtn.click(function () {
video.get(0).addEventListener('ended',myHandler,false);
plainVideo.play();
playBtn.css("visibility", "hidden");
function myHandler(e) {
playBtn.css("visibility", "visible");
}
});
});
At least this will give you an idea about the approach to this problem.
With pure Javascript (No jQuery)
You should but depend on the id, use the tag for reference, and get the nearest span. See the below code.
function closest(el, sel) {
if (el != null) return el.matches(sel) ? el : (el.querySelector(sel) || closest(el.parentNode, sel));
}
var videos = document.getElementsByTagName("video");
for (i = 0; i < videos.length; i++) {
var video = videos[i];
var playButton = closest(video, "span");
playButton.addEventListener("click", function () {
document.getElementById('main-video').addEventListener('ended', myHandler, false);
video.play();
playButton.style.visibility = "hidden";
function myHandler(e) {
playButton.style.visibility = "visible";
}
});
}
<video width="640" height="480">
<source src="media//mp4/video1.mp4" type="video/mp4">
</video>
<span class="custom-play-button">Play</span>
<video width="640" height="480">
<source src="media//mp4/video2.mp4" type="video/mp4">
</video>
<span class="custom-play-button">Play</span>
You've got to use CSS classes rather that id's and you have to use JavaScript to listen for video events and have your custom controls such as playpause button toggle. JavaScript's event.target tells you which video is doing what. MDN has a great article Creating a cross-browser video player which includes detailed instructions for custom controls for a single video.
Automated
I spent a few days creating a JavaScript that automates custom controls (Google's Material Design UI) for any number of videos on your HTML page.
The readable source code is on github at rhroyston/material-controls-for-html-video.
Fairly complex to do, but as you can see, it can be done. Live working demo is at https://hightechtele.com/articles/material-controls-for-html-video
Finally, like I said, this took me a few days. It's easy to do by hand for a single video but wanted to automate/script it. ...So view the script (and small accompanied CSS) to see how it can be done.

Get cue in HTML5 track element

In testing out the HTML5 track element, the cue comes up null. The TextTrackList and track element appear to load. Also, I am aware that VTT files aren't accessible locally, and I'm testing on a server. Can anyone help out? Thanks in advance.
This is my Javascript:
var audioElement = document.querySelector("audio");
var textTracks = audioElement.textTracks;
var textTrack = textTracks[0];
var ques = textTrack.cues;
var que = ques[0];
console.log(que);
Here's the HTML:
<audio src="Audio Files/Q_firefox.ogg" controls>
<track src="cues.vtt"></track>
</audio>
The cue value changes as the track plays so you need to listen for the value to change and run your function each time the text changes. Try this example based on your question:
var audioElement = document.querySelector("audio");
var textTrack = audioElement.textTracks[0];
// When cue value changes run your code
textTrack.oncuechange = function(e) {
var cue = this.activeCues[0];
if(cue){
console.log(cue.text);
}
}
<audio src="http://html5-demos.appspot.com/static/video/track/Google_Developer_Stories.webm" controls>
<track src="http://html5-demos.appspot.com/static/video/track/video-subtitles-en.vtt" default>
</audio>
Also note no need to close HTML track tag.

Replacing HTML5 video src strings in javascript does not replace video

I'm a javascript novice building a simple page to practice using HTML5 video. It's basically a full-page looping video and a javascript timer that tracks and updates time on page. (Inspired, of course, by Infinite Drunk Ron Swanson). Here is a live version of the page. Be careful: both links play sound.
I'd like the script to select one of seven videos to play on page load. The code should choose a random integer between 1 and 7, generate strings to the appropriate files in a "media/" directory, and replace the video <source> tag's src attribute with the new string.
This all seems to be working correctly: there are no errors in the console, locally or as uploaded to github-pages, and when I inspect the <video> element in the Chrome developer toolbar, I can see that the code is replacing the src strings correctly. But the page doesn't seem to load different videos! This is extra-aggravating, as it was working correctly a few commits ago. I've gone back through the history to see what's changed, but I can't find anything.
I come from Python, and I suspect there's something I just don't get yet, but I don't know enough to figure out what!
UPDATE: I have solved this problem with the help of this question, by using createElement and appendChild to insert the source tags instead of changing the attributes of each element in the NodeList returned by querySelectorAll. Here is the relevant new code:
function add_source(element, src, type) {
var source = document.createElement("source");
source.src = src;
source.type = type;
element.appendChild(source);
}
function main() {
var video_no = random_int(1,7);
var video_string_mpeg = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".mp4";
var video_string_webm = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".webm";
var videoplayer = document.querySelector(".videoplayer");
add_source(videoplayer, video_string_mpeg, "video/mp4");
add_source(videoplayer, video_string_mpeg, "video/webm");
get_seconds();
}
This is great, but I don't completely understand why it worked. Explanations are still welcome!
Here's the javascript:
start = new Date();
start_time = start.getTime();
function get_seconds() {
var now = new Date();
var time_now = now.getTime();
var time_diff = time_now - start_time;
var seconds = time_diff/1000;
var timer_string = Math.round(seconds);
document.getElementById("timer").innerHTML = timer_string;
window.setTimeout("get_seconds();", 1000);
}
function random_int(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min; }
function main() {
var video_no = random_int(1,7);
var video_string_mpeg = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".mp4";
var video_string_webm = "http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy" + video_no + ".webm";
var sources = document.querySelectorAll(".videoplayer source");
sources.item(0).src = video_string_mpeg;
sources.item(1).src = video_string_webm;
get_seconds();
}
And the HTML:
<html>
<link rel="stylesheet" href="charleston.css">
<script src="charleston.js" type="text/javascript">
</script>
<body onload="main();">
<video class="videoplayer" loop autoplay>
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy1.mp4" type="video/mp4" />
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/Trudy1.webm" type="video/webm" />
Christ on a cracker, Trudy! Update your web browser!
<audio loop autoplay>
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/charleston.mp3" type="audio/mpeg" />
<source src="http://ecmendenhall.github.com/Infinite-Charleston/media/charleston.ogg" type="audio/ogg" />
</audio>
</video>
<div class="timer_box">
<p>Hell's bells, Trudy! You've been dancing for <a id="timer">0</a> seconds.
Tweet
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></p>
</div>
</body>
</html>
I don't think the CSS or media files are the problem, but you can see them in the project repository if you'd like. A live version is available here. (NB: It plays sound). As you can see, it does everything right except selecting different videos.
I believe you can also call .load() on your video object to reload the <source>'s defined in the corresponding video object.
"When your listener function is triggered, it should change the media’s src property, then call the load method to load the new media and the play method to play it, as shown in Listing 3-4." - Apple

Categories

Resources