I'm working on building a custom YouTube player to embed a video feed on a website. I'm new to this, and I haven't had much luck searching around the Web.
Using snippets of useful code from tutorials, I've created a main video player and a carousel of thumbnails for users to click on to load that video into the player. The only thing missing, however, is I want the currently selected video's title to appear below the iframe tag. Any help on this? Or can anybody point me in the right direction?
Here's my script:
<script>
(function() {
function createPlayer(jqe, video, options) {
var ifr = $('iframe', jqe);
if (ifr.length === 0) {
ifr = $('<iframe scrolling="no">');
ifr.addClass('player');
}
var src = 'http://www.youtube.com/embed/' + video.id;
if (options.playopts) {
src += '?';
for (var k in options.playopts) {
src+= k + '=' + options.playopts[k] + '&';
}
src += '_a=b';
}
ifr.attr('src', src);
jqe.append(ifr);
}
function createCarousel(jqe, videos, options) {
var car = $('div.carousel', jqe);
if (car.length === 0) {
car = $('<div>');
car.addClass('carousel');
jqe.append(car);
}
$.each(videos, function(i,video) {
options.thumbnail(car, video, options);
});
}
function createThumbnail(jqe, video, options) {
var imgurl = video.thumbnails[0].url;
var img = $('img[src="' + imgurl + '"]');
if (img.length !== 0) return;
img = $('<img>');
img.addClass('thumbnail');
jqe.append(img);
img.attr('src', imgurl);
img.attr('title', video.title);
img.click(function() {
options.player(options.maindiv, video, $.extend(true,{},options,{playopts:{autoplay:1}}));
});
}
var defoptions = {
autoplay: false,
user: null,
player: createPlayer,
carousel: createCarousel,
thumbnail: createThumbnail,
loaded: function() {},
playopts: {
autoplay: 0,
egm: 1,
autohide: 1,
fs: 1,
showinfo: 0
}
};
$.fn.extend({
youTubeChannel: function(options) {
var md = $(this);
md.addClass('youtube');
var allopts = $.extend(true, {}, defoptions, options);
allopts.maindiv = md;
$.getJSON('http://gdata.youtube.com/feeds/users/' + allopts.user + '/uploads?alt=json-in-script&format=5&callback=?', null, function(data) {
var feed = data.feed;
var videos = [];
$.each(feed.entry, function(i, entry) {
var video = {
title: entry.title.$t,
id: entry.id.$t.match('[^/]*$'),
thumbnails: entry.media$group.media$thumbnail
};
videos.push(video);
});
allopts.allvideos = videos;
allopts.carousel(md, videos, allopts);
allopts.player(md, videos[0], allopts);
allopts.loaded(videos, allopts);
});
}
});
})();
$(function() {
$('#player').youTubeChannel({user:'oklahomadaily'});
});
</script>
And here's my HTML:
<div class="video">
<div class="boxTitle">Featured videos</div>
<div id="player"></div>
<div id="title"><p class="multimedia">Could not find a description...</p></div>
</div>
Thanks for your patience and assistance.
Related
I've created a website that allows users to display multiple YouTube videos, and I'm trying to buttons that pause and play every video by using JS.
The website functions correctly until the page is refreshed. Once the page is refreshed, the display button outputs empty divs rather than a video until the 3rd attempt. Meanwhile, the play and pause buttons only work after the display button is clicked.
$(document).ready(function() {
let input = document.getElementById("video-url");
let displayButton = document.getElementById("display-video");
let containerDiv = document.getElementById("video-container");
let stateList = [];
let player;
let players = [];
// Load the YT library
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
displayButton.addEventListener("click", function() {
let videoID = input.value.split("watch?v=")[1];
let innerDiv = document.createElement("div");
innerDiv.className = "inner";
innerDiv.id = "video-" + players.length;
let outerDiv = document.createElement("div");
outerDiv.className = "window draggable resizable";
outerDiv.style.transform = "translate3d(100px, 100px, 0)";
outerDiv.appendChild(innerDiv);
init();
containerDiv.appendChild(outerDiv);
player = new YT.Player("video-" + players.length, {
height: "100%",
width: "100%",
videoId: videoID,
events: {
'onReady': onPlayerReady
}
});
players.push(player);
init();
saveState();
});
function onPlayerReady(event) {
let playButton = document.getElementById("play-button");
playButton.addEventListener("click", function() {
event.target.playVideo();
});
let pauseButton = document.getElementById("pause-button");
pauseButton.addEventListener("click", function() {
event.target.pauseVideo();
});
let stopButton = document.getElementById("stop-button");
stopButton.addEventListener("click", function() {
event.target.stopVideo();
});
}
function init() {
// the ui-resizable-handles are added here
$('.resizable').resizable();
// makes GSAP Draggable avoid clicks on the resize handles
$('.ui-resizable-handle').attr('data-clickable', true);
// make the element draggable
Draggable.create('.draggable', {
onPress: function () {
$(this.target).addClass('ui-resizable-resizing');
},
onRelease: function() {
$(this.target).removeClass('ui-resizable-resizing');
saveState();
}
});
$('.resizable').dblclick(function () {
var win = $(this);
toggleSize(win);
saveState();
});
}
function createHandleBar() {
// create handlebar
let handleBar = document.createElement('div');
handleBar.className = 'handleBar';
$(handleBar).css({
position: 'absolute',
top: '0px',
width: '100%', height: '43px',
padding: '4px',
boxSizing: 'border-box'
});
saveState();
return handleBar;
}
function saveState() {
let state = {
id: stateList.length,
state: containerDiv.innerHTML
};
stateList.push(state);
window.localStorage.setItem('videoState', JSON.stringify(stateList));
window.history.pushState({}, '', '#' + btoa(JSON.stringify(stateList)));
}
if (window.location.hash) {
let stateListFromStorage = JSON.parse(atob(window.location.hash.substring(1)));
let stateToRestore = stateListFromStorage[stateListFromStorage.length - 1];
containerDiv.innerHTML = stateToRestore.state;
init();
}
});
GitHub Code: https://github.com/RyanOliverV/Video_Viewer
Page: https://ryanoliverv.github.io/Video_Viewer/
I am trying to write a function that will take an id of a div and play a given video from for example 2/10th of the way through to 3/10th of the way through and return an event so I can do something else.
I am not to clever with events as yet, and the video duration is not working out for me, any help appreciated. I have jQuery installed.
Some improvement since last time...
Updated, just need the listener to work next.
var finished_event = new Event('finished');
$(document).ready(function(){
class Player {
constructor(pos, vid, part, parts){
this.pos = pos;
this.vid = vid;
this.part = part;
this.parts = parts;
}
start(){
var it = this;
var html = '<video class="video-fit" controls>';
html += '<source src="';
html += it.vid;
html += '" type="video/mp4">';
html += '</video>';
$(it.pos).html(html);
var video = $(it.pos + ' video')[0];
video.addEventListener('loadeddata', function(){
var dur = video.duration;
var fra = dur / it.parts;
var beg = it.part * fra;
var end = it.part * (fra + 1);
video.currentTime = beg;
video.play();
video.addEventListener('timeupdate', function() {
if (video.currentTime >= end) {
video.pause();
this.dispatchEvent(finished_event);
}
}, false);
}, false);
return it;
}
}
$('body').click(function(){
let player_1 = new Player('#pos-1', 'videos/576p.mp4', 5, 10);
player_1.start();
let player_2 = new Player('#pos-2', 'videos/576p.mp4', 5, 10);
player_2.start();
let player_3 = new Player('#pos-3', 'videos/576p.mp4', 5, 10);
player_3.start();
let player_4 = new Player('#pos-4', 'videos/576p.mp4', 5, 10);
player_4.start();
//.addEventListener('finished', function(){ console.log('Finished'); }, false)
});
});
The timeupdate event fires a lot, so it could fire multiple times within the this.currentTime >= end check.
Not changing your code too much, you would want to set a playing state/var and on canplay event change timestamp and then play, this would, in turn, trigger a seeked event which then you can set the video as playing, then on timeupdate, check your timing plus is the video playing.. and for the last video you would need to check ended event as it won't enter into your check this.currentTime >= end as end is +1 second.
Then to separate the event functions from the Player class, id would use an array and watch it for changes, then by pushing a function to the array/stack you can then do a check within the function each time its invoked if the stack matches the video length, suppose you could do it other ways.
(function () {
let video =
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/twitter_cat.mp4';
let videos = [
{ id: '#pos-1', video, part: 1, parts: 10 },
{ id: '#pos-2', video, part: 2, parts: 10 },
{ id: '#pos-3', video, part: 3, parts: 10 },
{ id: '#pos-4', video, part: 4, parts: 10 },
];
const playqueue = [];
Object.defineProperty(playqueue, 'push', {
value: function (...args) {
var arr = Array.prototype.push.apply(this, args)
if (typeof args[0] === 'function') args[0]();
return arr;
}
});
function finished_event() {
if (playqueue.length === videos.length) {
console.log('Do something, all videos have stopped playing');
}
}
function video_finished_event(player) {
console.log(
'Do something, ' + JSON.stringify(player) + ' has stopped playing'
);
playqueue.push(finished_event);
}
class Player {
constructor(pos, vid, part, parts) {
this.pos = pos;
this.vid = vid;
this.part = part;
this.parts = parts;
}
start() {
var it = this;
var html = '<video class="video-fit" data-vid="' + it.pos + '" controls>';
html += '<source src="';
html += it.vid;
html += '" type="video/mp4">';
html += '</video>';
$(it.pos).html(html);
var video = $('[data-vid="' + it.pos + '"]')[0];
video.addEventListener(
'loadeddata',
function () {
var fra = video.duration / it.parts;
var beg = it.part * fra;
var end = it.part * (fra + 1);
video.addEventListener('canplay', function () {
if (!this.playing) {
this.currentTime = beg;
this.play();
}
});
video.addEventListener('seeked', function () {
this.playing = true;
});
video.addEventListener('timeupdate', function () {
if (this.playing && this.currentTime >= end) {
this.pause();
this.playing = false;
video_finished_event(it);
}
});
video.addEventListener('ended', function () {
if (this.playing) {
this.pause();
this.playing = false;
video_finished_event(it);
}
})
},
false
);
return it;
}
}
videos.forEach(video => {
video.player = new Player(video.id, video.video, video.part, video.parts);
video.player.start();
});
})();
.videos div {
display: inline-block;
width: calc(25vw - 15px);
height: 100%;
}
.videos div video {
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="videos">
<div id="pos-1"></div>
<div id="pos-2"></div>
<div id="pos-3"></div>
<div id="pos-4"></div>
</div>
I suggest you to put an unique id on video, here i choose vpos-1/2/3/4/...
and i display video from beg to end:
var html = '<video ' + 'id="v' + it.pos + '" class="video-fit">';
html += '<source src="';
html += it.vid;
html += '" type="video/mp4">';
html += '</video>';
$(it.pos).html(html);
var video = document.getElementById('v' + it.pos);
$(video).bind('timeupdate', function() {
if(video.currentTime > end){
video.pause();
}
});
$(video).on('play', function() {
video.playbackRate = 1.0;
//calcul the value of beg
video.currentTime = beg;
video.play();//suppress if you have autoplay
});
$(video).bind('ended', function() {
// nothing yet
});
if you want to autoplay and/or display controls i suggest you to add
controls="controls" autoplay
to tag video
if you want to remove video: just do src=''
It stops the video and it saves the memory
I have a product page with images and product description that all loads dynamically from a json file. Everything works perfectly except for the owl carousel when I click on either the prev/next arrows. The main image and the data updates as it should, but the carousel does not.
I logged the new image urls and they are being updated properly.
I tried using this everywhere in the code
$("#owl-focus").trigger('refresh.owl.carousel');
This is the javascript for the page
// ========== Compile Product Data =======================================
$.getJSON("../../json/guitars.json", function(data) {
var jsonLength = data.length
// ------- Parse & Returns URL Parameters -----------------------------
function getUrlVars(guitar) {
var vars = {}
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
})
return vars
}
// ------------ Append Clicked Image -------------------------------------
var guitar = parseInt(getUrlVars()["product"], 10)
loadGuitar(guitar)
function loadGuitar(guitar) {
// Images
var image1 = data[guitar].img1
var image2 = data[guitar].img2
var image3 = data[guitar].img3
var image4 = data[guitar].img4
var alt = data[guitar].alt
// description
var title = data[guitar].title
var brand = data[guitar].brand
var code = data[guitar].code
var price = data[guitar].price
var description = data[guitar].description
var specs = data[guitar].specs
$('#clickImg').attr({src: `../${image1}`, alt: `${alt}`})
$('#img1').attr({src: `../${image1}`, alt: `${alt}`})
$('#img2').attr({src: `../${image2}`, alt: `${alt}`})
$('#img3').attr({src: `../${image3}`, alt: `${alt}`})
$('#img4').attr({src: `../${image4}`, alt: `${alt}`})
$('#title').html(title)
$('#brand').html(brand)
$('#variant-sku').html(code)
$('#price').html(price)
$('#description').html(description)
$('#specs').empty();
specs.forEach(spec => {
$("#specs"). append(`<li>${spec}</li>`)
})
}
// -------------- Owl Carousel -------------------------------------------
$(document).ready(function () {
$('#owl-focus').owlCarousel({
loop: true,
margin: 10,
nav: true,
navText: [$('.owl-navigation .owl-nav-prev'), $('.owl-navigation .owl-nav-next')],
responsiveClass: true,
responsive: {
0: {
items: 3,
},
1050: {
items: 4,
}
}
})
})
// -------- Next / Previous Arrows -------------------------------------
$("#prev-btn").click(function() {
if (guitar === 0) {
guitar = jsonLength - 1
} else {
guitar = guitar - 1
}
loadGuitar(guitar)
onPageChg()
})
$("#next-btn").click(function() {
if (guitar === jsonLength - 1) {
guitar = 0
} else {
guitar = guitar + 1
}
loadGuitar(guitar)
onPageChg()
})
})
// ========== Compile Product Data End ===================================
Figured it out. Instead of trying to reload owl I reloaded the page as I should have with new data. Similar functions that take me to that product page in the first place with a few adjustments.
$("#prev-btn").on("click", function(e) {
$.getJSON("../../json/guitars.json", function(json) {
if (guitar === 0) {
new_id = jsonLength - 1
} else {
new_id = guitar - 1
}
window.location.href = "product.html?product=" + new_id
})
})
$("#next-btn").on("click", function(e) {
$.getJSON("../../json/guitars.json", function(json) {
if (guitar === jsonLength - 1) {
new_id = 0
} else {
new_id = guitar + 1
}
window.location.href = "product.html?product=" + new_id
})
})
Before I was just changing the attributes on the photos, description, etc
I have a video tag in which I pass video data i.e src and vtt dynamically, I want to keep vtt for the current video only, and remove all other textTracks.
Right Now on switching the video, all vtt related to previously played videos start playing inside the video tag.
vtt is subtitle
function addVttInvideo(data) {
// http://www.html5rocks.com/en/tutorials/track/basics/
// https://www.iandevlin.com/blog/2015/02/javascript/dynamically-adding-text-tracks-to-html5-video
var video = document.getElementById('videoSrc');
var track = video.addTextTrack('subtitles', 'English', 'en');
track.mode = "showing";
var startTime = parse_timestamp(data.info.start);
var endTime = parse_timestamp(data.info.end);
var cue = new VTTCue(startTime, endTime, data.info.text);
// track.addEventListener("cuechange", function () {
// // get current cue, and remove it if it's number 2
// var currentCue = track.activeCues[0];
// track.removeCue(currentCue)
// },false);
track.addCue(cue);
// console.log('subtitle.innerHTML',subtitle.innerHTML);
// quick_and_dirty_vtt_or_srt_parser(subtitle.innerHTML).map(function(cue) {
// track.addCue(cue);
// });
// track.addCue(quick_and_dirty_vtt_or_srt_parser(2,55,'my profile'));
}
function parse_timestamp(s) {
var match = s.match(/^(?:([0-9]{2,}):)?([0-5][0-9]):([0-5][0-9][.,][0-9]{0,3})/);
if (match == null) {
throw 'Invalid timestamp format: ' + s;
}
var hours = parseInt(match[1] || "0", 10);
var minutes = parseInt(match[2], 10);
var seconds = parseFloat(match[3].replace(',', '.'));
return seconds + 60 * minutes + 60 * 60 * hours;
}
} catch (e) {
console.log('the exception album ' + e);
}
// load video is called when user swipe next and back
function loadVideo(way) {
var videoSrc = $('#videoSrc');
if (way === 'prev') {
videoCounter = videoCounter - 1;
if (videoCounter < 0) videoCounter = VideoData.length - 1;
videoSrc.attr('src', VideoData[videoCounter].vurl);
videoSrc.attr('poster', VideoData[videoCounter].turl)
addVttInvideo(VideoData[videoCounter].vtt)
} else if (way === 'next') {
videoCounter = videoCounter + 1;
if (videoCounter > VideoData.length - 1) videoCounter = 0;
videoSrc.attr('src', VideoData[videoCounter].vurl);
videoSrc.attr('poster', VideoData[videoCounter].turl)
addVttInvideo(VideoData[videoCounter].vtt)
} else {
videoSrc.attr('src', VideoData[0].vurl);
videoSrc.attr('poster', VideoData[0].turl)
addVttInvideo(VideoData[0].vtt)
// document.getElementById('vsrc').onloadeddata = function() {
// debugger
//
// };
}
$("#videoAlbumCaption").text(videoCounter + 1 + " / " + VideoData.length);
}
A bit confusing as your question is for removing vtt cue, but from what you described is removing all other textTracks.
I will explain how to remove all other textTracks.
HTML
<video src="foo.ogv">
<track kind="subtitles" label="English subtitles" src="subtitles_en.vtt" srclang="en" default>
</track>
<track kind="subtitles" label="Deutsche Untertitel" src="subtitles_de.vtt" srclang="de">
</track>
</video>
videoElement.textTracks console output
var videoElement = document.querySelector("video");
console.log(videoElement);
TextTrackList {0: TextTrack, 1: TextTrack, length: 2, onchange: null, onaddtrack: null, onremovetrack: null}
0: TextTrack {kind: "subtitles", label: "English subtitles", language: "en", id: "", mode: "showing", …}
1: TextTrack {kind: "subtitles", label: "Deutsche Untertitel", language: "de", id: "", mode: "disabled", …}
length: 2
Remove Track
var videoElement = document.querySelector("video");
videoElement.removeChild(videoElement.children[0]); //remove English subtitle
// you need iterlate videoElement.textTracks and find index according to language
var i =0;
var targetLanguage = "de";
for (let track of videoElement.textTracks){
if(track.language !== targetLanguage){
videoElement.removeChild(videoElement.children[i]);
}
i++;
}
As #Heretic Monkey commented, please refer to this for TextTrackList Implementation.
Delete a TextTrack from a video
Hi there I am trying to have a video autoplay and mute. But on mobile devices it doesn't show due to flash.
here is my code.
<div id="vimeo"> </div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script type="text/javascript">
function vimeo_player_loaded() {
moogaloop3 = document.getElementById('vimeo');
moogaloop3.api_setVolume(0);
}
var flashvars = {
'clip_id': '138036294', // <--vimeo video ID
'server': 'vimeo.com',
'show_title': 0,
'show_byline': 0,
'show_portrait': 0,
'fullscreen': 0,
'autoplay': 1,
'js_api': 1,
'js_onload': 'vimeo_player_loaded'
}
var parObj = {
'swliveconnect':true,
'fullscreen': 1,
'allowscriptaccess': 'always',
'allowfullscreen':true
};
var attObj = {}
attObj.id="vimeo";
swfobject.embedSWF("http://www.vimeo.com/moogaloop.swf", "vimeo", "343", "193", "9.0.28", '',flashvars,parObj, attObj );
</script>
How would I go about making it default to html5?
Found another way of doing it using
<div id="vimeo"> <div>
<script>
// URL of the video
var videoUrl = 'http://www.vimeo.com/76979871';
var endpoint = 'http://www.vimeo.com/api/oembed.json';
var callback = 'embedVideo';
var url = endpoint + '?url=' + encodeURIComponent(videoUrl)+ '&autoplay=true' + '&callback=' + callback + '&width=420';
function embedVideo(video) {
document.getElementById('vimeo').innerHTML = unescape(video.html);
}
function init() {
var js = document.createElement('script');
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', url);
document.getElementsByTagName('head').item(0).appendChild(js);
}
window.onload = init;