YouTube as popup play on desktop version but not on mobile devices - javascript

I am using below script to play YouTube video as a bootstrap Modal, It play video on desktop version but same fails to play on mobile devices such as iphone and iPad.
YouTubeLoader.js
// Load & insert into DOM Youtube iframe_api
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
/* Create Player */
var player;
function onYouTubeIframeAPIReady() {
console.log('Api Loaded');
}
$(".youtubeVideoLoader").each(function() {
// Set the BG image from the youtube ID
$(this).css('background-image', 'url(//i.ytimg.com/vi/' + this.id + '/hqdefault.jpg)');
// Click the video div
$(document).delegate('#' + this.id, 'click', function() {
// Vemos le id del video
console.log(this.id);
// Create new instance of player
player = new YT.Player('videoModalContainer', {
videoId: this.id,
events: {
'onReady': OpenModal,
'onStateChange': console.log('Changed')
}
});
// Show Modal
function OpenModal() {
$("#youtubeModal").modal({backdrop: "static"});
// Set Highres
player.setPlaybackQuality('highres');
// Play Video
player.playVideo();
};
});// /click
}); // /each video
// Add a Lisener to Modal CLose Button
$('#CloseModalButton').click(function(){
console.log('Stop Preset');
player.destroy();
});
HTML
<div id="3WCMCeS7Na4" class="youtubeVideoLoader">
</div>
<!-- Modal Template -->
<div class="modal fade" id="youtubeModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-footer">
<button id="CloseModalButton" type="button" class="btn btn-default" data-dismiss="modal">X</button>
</div>
<div class="modal-content">
<div class="modal-body">
<div id="videoModalContainer">
</div>
</div>
I have tried it with other video and i face the same issue as i initially thought it might be one video which is not playing due to privileges

Issue was resolved removing following two lines of code.
//player.setPlaybackQuality('highres');
//player.playVideo();
It was not playing on mobile devices as Youtube has stopped the AutoPlay functionality of video. Not sure why it worked on desktop version...

Related

How to close camera inside the modal using Html5 QrCode Scanner ASP.NET MVC

Hello I'm working with Html5 QrCode library to use a scanner, and I'm using it inside a modal the problem that I have is when I close the modal the camera does not stop and it keeps on, I want to know if exist a function or someone did something the same to stop the camera working with this library https://github.com/mebjas/html5-qrcode
In my case will be ideal using an onClick in the close button.
Modal
<div class="modal" id="livestream_scanner" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Search Barcode Scanner</h5>
<button type="button" class="close" data-dismiss="modal" onclick="Close()" aria-label="Close"> -- >Here I would like to call some function to close the camera
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="qr-reader" style="width:450px"></div>
<div id="qr-reader-results" style="margin-bottom: 25px;"></div>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
Script
<script>
function docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete" || document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
docReady(function () {
var resultContainer = document.getElementById('qr-reader-results');
var lastResult, countResults = 0;
function onScanSuccess(decodedText, decodedResult) {
if (decodedText !== lastResult) {
++countResults;
lastResult = decodedText;
window.location.href = "#Url.Action("Run", "Search")?criteria=" + lastResult;
html5QrcodeScanner.clear();
}
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"qr-reader", { fps: 10, qrbox: 250, rememberLastUsedCamera: false });
html5QrcodeScanner.render(onScanSuccess);
});
</script>
on GitHub library description they mentioned method to stop
Stop Scanning
To stop using camera and thus stop scanning, call Html5Qrcode#stop() which returns a Promise for stopping the video feed and scanning.
html5QrCode.stop().then((ignore) => {
// QR Code scanning is stopped.
}).catch((err) => {
// Stop failed, handle it.
});
Note that the class is stateful and stop() should be called to properly tear down the video and camera objects safely after calling start() when the scan is over or the user intend to move on. stop() will stop the video feed on the viewfinder.

Migrate to Bootstrap 5 - Video Modal

I have a modal with video inside, written for Bootstrap 4. I want to migrate this to Bootstrap 5, where no jQuery is available. How may I do this? The problem is the JavaScript here:
<script>
// codepen.io/JacobLett/pen/xqpEYE
$(document).ready(function() {
var $videoSrc;
$('.video-btn').click(function() {
$videoSrc = $(this).data( "src" );
});
console.log($videoSrc);
// when the modal is opened autoplay it
$('#videoModal').on('shown.bs.modal', function (e) {
// set the video src to autoplay and not to show related video. Youtube related video is like a box of chocolates... you never know what you're gonna get
$("#video").attr('src',$videoSrc + "?autoplay=1&modestbranding=1&showinfo=0" );
})
// stop playing the youtube video when I close the modal
$('#videoModal').on('hide.bs.modal', function (e) {
// a poor man's stop video
$("#video").attr('src',$videoSrc);
})
});
</script>
The modal is using
<button type="button" class="video-btn" data-bs-toggle="modal" data-bs-target="#videoModal" data-bs-src="https://www.youtube.com/embed/EzDC8aAJln0" >
<img src="/img/video/dbschema-video.svg" class="img-fluid" alt="DbSchema Video Presentation">
</button>
<div class="modal fade" id="videoModal" tabindex="-1" role="dialog" aria-labelledby="dbschemaModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<div class="ratio ratio-16x9">
<iframe class="embed-responsive-item" src="" id="video" allowscriptaccess="always" allow="autoplay"></iframe>
</div>
</div>
</div>
</div>
</div>
See this.
So you can do something like below:
$(document).ready(function() {
var $videoSrc;
document.querySelector('.video-btn').addEventListener('click', function() {
$videoSrc = $(this).data( "src" );
});
console.log($videoSrc);
// when the modal is opened autoplay it
document.getElementById('videoModal').addEventListener('shown.bs.modal', function (e) {
// set the video src to autoplay and not to show related video. Youtube related video is like a box of chocolates... you never know what you're gonna get
$("#video").attr('src',$videoSrc + "?autoplay=1&modestbranding=1&showinfo=0" );
})
// stop playing the youtube video when I close the modal
document.getElementById('videoModal').addEventListener('hide.bs.modal', function (e) {
// a poor man's stop video
$("#video").attr('src',$videoSrc);
})
});
Also you should add -bs- to your data-attributes wherever you use bootstrap-5
For vanilla JS it would be something like this...
var videoBtn = document.querySelector('.video-btn')
var videoModal = document.getElementById('videoModal')
var video = document.getElementById('video')
var videoSrc
videoBtn.addEventListener('click',function(e){
videoSrc = videoBtn.getAttribute('data-bs-src')
})
videoModal.addEventListener('shown.bs.modal',(e)=>{
video.setAttribute('src', videoSrc + '?autoplay=1&modestbranding=1&showinfo=0')
})
videoModal.addEventListener('hide.bs.modal',(e)=>{
video.setAttribute('src', videoSrc)
})
Here's the working code

Embedded Youtube videos not playing in mobile iOS Safari

Recently we've found a bug that exists only in Safari on iPhone(s) however I cannot pinpoint the source of the issue. When pressing the play button the video appears to load but then closes immediately.
All answers I've found so far aren't recent and/or don't solve the problem. Testing in BrowserStack is giving me this error: Invalid CSS property declaration at: * from the www-embed-player-sprite-mode-vfl9mHoaB.css file served from Youtube.
I'm also open to optional ways of handling embedded videos to avoid this issue.
The code:
#set($showVideo = $request.getParameter("showVideo"))
#set($howItWorksID = $placeholder.getAttributeValueGroup().getAttributeValue('product_howitworks', $sesShoppingCart.getLocale()))
#set($embeddedURL = "https://www.youtube.com/embed/" + $howItWorksID + "?rel=0")
#set($hasVideoID = false)
#if( $howItWorksID && $howItWorksID != "" )
#set( $hasVideoID = true )
#end
<div id="howItWorksModal" class="modal-howItWorks modal fade">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<button type="button" class="close js-modalClose close--howItWorks" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">close</span>
</button>
<div>
<div class="prose howItWorks-embedVideoWrapper">
<div class="iframe-container">
<iframe id="howItWorks-ModalVersion" class="howItWorks js-howItWorks-iframe" width="100%" src="" frameborder="0" allowfullscreen preload></iframe>
</div>
</div>
</div>
</div>
</div>
</div>
jQueryReady(function() {
var videoURL = "$embeddedURL";
// Load destination video and autoplay when modal opens
$("#howItWorksModal").on('shown.bs.modal', function(ev) {
ev.preventDefault();
$("#howItWorks-ModalVersion").attr("src", videoURL + "&autoplay=1");
console.log('clicked on');
});
// Kill video when modal is closed
$('#howItWorksModal').on('hidden.bs.modal', function (e) {
$('.js-howItWorks-iframe').each( function(){
$(this).attr('src', '');
});
});
// Kill mobile video if playing while window is resized
function mobileVideoSource(){
var mobileBlock = $('#BuyNow-mobileBlock'),
howToVid_mobile = $('#howItWorks-MobileVersion');
if (mobileBlock.is(":hidden")) {
// if mobile block is hidden remove it's source
howToVid_mobile.attr('src', '');
} else {
// if mobile block is displayed add a source
howToVid_mobile.attr('src', videoURL);
}
}
sdi.window.on('resize', mobileVideoSource);
})
mobileVideoSource() was being called and removing the src when the video was opening. I did not investigate into why this was happening, however I restructured the script to completely remove the iframe instead of the src and inject a new instance if (for whatever rare edge use case) the screen is resized back down to mobile and the user wants to watch the video again:
function mobileVideoSource() {
var mobileBlock = $('#BuyNow-mobileBlock'),
currentVid = $('#howItWorks-MobileVersion'),
videoContainer = $('.iframe-container')
new_iframe = $('<iframe id="howItWorks-MobileVersion" class="howItWorks" width="560" height="315" src="$embeddedURL" frameborder="0" allowfullscreen></iframe>');
if (mobileBlock.is(":hidden")) {
currentVid.remove();
} else {
videoContainer.append(new_iframe);
}
}

Angular ng-swipe with youtube iframe

I'm trying to build simply slider with images and youtube videos. I want make it works fine on touch devices, so I want to use ng-swipe-* from angular's ngTouch module. Unfortunately swipe doesn't work over youtube's iframe. I tried to set lower z-index: -10;, but then I cannot play the video.
Do you have any idea how to solve this problem?
There is a snippet:
var app = angular.module('app', ['ngTouch']);
app.controller('ctrl', function($scope) {
$scope.msg = function(msg) {
alert(msg);
}
});
.ok {
width: 300px;
height: 100px;
background: green;
}
<script src="https://code.angularjs.org/1.4.8/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-touch.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl" ng-swipe-right="msg('right')" ng-swipe-left="msg('left')">
<div class="ok">swipe works here</div>
<div>
<iframe width="300" height="200" src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
(the best way to test it, is to run it in Chrome developer console and emulate on touch device)
Here's a pretty hacky workaround: using two overlay divs, set to the right and the left of the player allows the user to play and pause, and setting the height to 80% allows them to use the menu on the bottom. This is not perfect, but it kind of works!
Note 1: It's kind of buggy if you play it here, so I'm adding a codepen: http://codepen.io/anon/pen/LGjwYZ
Second version, a little bit more bloated but with more area coverage: http://codepen.io/anon/pen/rxzXxB
Note 2: I used a transparent background on the divs for demonstrational purposes.
var app = angular.module('app', ['ngTouch']);
app.controller('ctrl', function($scope) {
$scope.msg = function(msg) {
alert(msg);
}
});
.ok {
width: 300px;
height: 100px;
background: green;
}
<script src="https://code.angularjs.org/1.4.8/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-touch.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl" ng-swipe-right="msg('right')" ng-swipe-left="msg('left')">
<div class="ok">swipe works here</div>
<div style="position:relative; height:200px; width:300px;">
<iframe style="position:absolute;width:100%;height:100%;z-index:10;" src="https://www.youtube.com/embed/dQw4w9WgXcQ"></iframe>
<div style="background:rgba(0,0,0,0.3);height:80%;width:40%;left:0;position:absolute;z-index:20;"></div>
<div style="background:rgba(0,0,0,0.3);height:80%;width:40%;right:0;position:absolute;z-index:20;"></div>
</div>
</div>
</div>
The issue is that you don't have control of events within the iframe, so can't tell when the user swipes over that area. The work around I suggest is to replace the iframe with a image placeholder while not watching. In order to do this use YouTube's Iframe API to keep track of video events. When the video goes from play to pause we will hide the video and show the image. Here is a demo.
HTML
<div ng-app="app">
<div ng-controller="ctrl" ng-swipe-right="msg($event, 'right')" ng-swipe-left="msg($event, 'left')">
<div id="player"></div>
<img id="player-cover" src="http://img.youtube.com/vi/M7lc1UVf-VE/hqdefault.jpg" />
</div>
</div>
JS
On initiation it hides the video. When ever the image is clicked it shows and plays the video. When the video goes from paused to play onPlayerStateChange handles toggling the image and video. Every time the swiping event gets called on the image it also triggers the click event handler for the image. The variable swiping keeps track of if the event was just a click or also a swipe.
var app = angular.module('app', ['ngTouch']);
app.controller('ctrl', function($scope) {
$scope.msg = function(event, msg) {
swiping = true;
alert(msg);
}
});
// keep track of the user swiping. onYouTubeIframeAPIReady needs to occur outside of Angular.
var swiping = false;
// Youtube related.
document.getElementById('player').style.display = 'none';
document.getElementById('player-cover').addEventListener("click", function() {
if (swiping) {
swiping = false;
return;
}
document.getElementById('player').style.display = 'block';
player.playVideo();
});
// This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// This function creates an <iframe> (and YouTube player) after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: { 'onStateChange': onPlayerStateChange }
});
}
function onPlayerStateChange(event) {
if (event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.ENDED) {
document.getElementById('player-cover').style.display = 'block';
document.getElementById('player').style.display = 'none';
} else {
document.getElementById('player-cover').style.display = 'none';
document.getElementById('player').display = 'block';
}
}

Play mp4 video via javascript

I have a responsive site that contains html5 video. I have some javascript that checks if the size of the video elements are below a certain threshold. If so, it removes the controls, places a video play button overlay image on top of the video element then adds a click event to the container holding the video element. When the container is clicked on, it copies the video into a modal dialog box and plays the video.
Here's the quandary:
The webm version has no problems whatsoever.
The mp4 version of the modal view has no problems in Safari.
If the mp4 plays in place (i.e. is large enough to not need a modal window) it plays fine.
The mp4 version of the modal view won't play in Chrome or IE.
However, it will work in Chrome or IE if I have their built-in DOM
inspectors open (e.g. IE's F12 tools).
This can be seen here.
Here's the HTML:
<div class="video modal-trigger col-lg-4 col-md-4 col-sm-4">
<canvas></canvas>
<video preload="auto" controls="controls" poster="img/why-autologel-poster.png">
<source src="media/why-autologel.m4v" type='video/mp4'>
<source src="media/why-autologel.webm" type='video/webm'>
</video>
</div>
<div class="col-lg-8 col-md-8 col-sm-7">
<h2 class="modal-heading">
Why AutoloGel?
</h2>
<p class="modal-copy">
See what AutoloGel offers to your patients.
</p>
</div>
<!-- Modal Window -->
<div class="modal fade" id="modal-window" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel"></h4>
</div>
<div class="modal-body">
<div class="media"></div>
<div class="copy"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Here's the javascript:
$(document).ready(function() {
// Play very small videos in modal box
if ( $(window).width() > 750 ) {
var modalvideo = document.getElementsByTagName('video');
// Hide controls for very small videos
for (var i = 0; i < modalvideo.length; i++) {
if ( $(modalvideo[i]).width() < 470 ) {
$(modalvideo[i]).removeAttr('controls');
if ( $('html').hasClass('IE-9') ) {
$(modalvideo[i]).after('<img class="poster-overlay" src="img/poster-overlay-ie9.png" alt="play video">');
} else {
$(modalvideo[i]).after('<img class="poster-overlay" src="img/poster-overlay.png" alt="play video">');
}
}
}
// Add click event to video container that brings up video in a modal window
$('.modal-trigger').on("click", function() {
if ( $(this).width() < 470 ) {
// Get video, title and any copy text
var media = $(this).html();
var title = $(this).next().children('.modal-heading').text();
var copy = $(this).next().children('.modal-copy').text();
// Insert video, title and copy text into modal window
$('.modal-title').html(title);
$('.modal-body > .media').html(media);
$('.modal-body > .copy').text(copy);
$('#modal-window .poster-overlay').remove('');
$('#modal-window').modal('show');
// Autoplay video after modal window has rendered
$('#modal-window').on('shown.bs.modal', function() {
modalvideo[modalvideo.length - 1].setAttribute('controls', 'controls');
modalvideo[modalvideo.length - 1].play();
});
// Stop play video when modal window is closed
$('#modal-window').on('hide.bs.modal', function() {
modalvideo[modalvideo.length - 1].pause();
});
}
});
}
});
Thanks for your help!
Figured it out.
The problem was in two parts. For Chrome, there’s some quirk with its cache and copied DOM elements. I figured it was working when the developer tools were open because the cache is disabled. Simply applying a random GET variable at the end of the src attribute for the copied video element to flag it as a different file than the one cached solved the problem.
With IE it was (is) a little different. HubSpot uses Amazon S3 as its CDN and when I looked at the header for the video file its content type was set as application/octet-stream which Internet Explorer doesn’t support. AWS allows this to be set when the file is uploaded but HubSpot is doing this behind the scenes with no user ability to set this that I’m aware of. They're working on a fix.
The solution that ended up working:
$(document).ready(function() {
// Play very small videos in modal box
if ( $(window).width() > 750 ) {
var allvideos = $('video');
// Hide controls for very small videos
for (var i = 0; i < allvideos.length; i++) {
if ( $(allvideos[i]).width() < 470 ) {
$(allvideos[i]).removeAttr('controls');
if ( $('html').hasClass('IE-9') ) {
$(allvideos[i]).after('<img class="poster-overlay" src="img/poster-overlay.png" alt="play video">');
} else {
$(allvideos[i]).after('<img class="poster-overlay" src="img/poster-overlay.png" alt="play video">');
}
}
}
// Add click event to video container that brings up video in a modal window
$('.modal-trigger').on('click', function() {
if ( $(this).width() < 470 ) {
// Get video/img, title and any copy text
var media = $(this).html();
var title = $(this).next().children('.modal-heading').text();
var copy = $(this).next().children('.modal-copy').text();
if (! title.length) { title = '<br>'; }
// Insert video, title and copy text into modal window
var modalsrc = [];
var modaltype = [];
$(media).children('source').each(function() {
modalsrc.push( $(this).attr('src') );
modaltype.push( $(this).attr('type') );
});
$('.modal-title').html(title);
$('.modal-body > .media').html(media);
$('.modal-body > .copy').text(copy);
$('#modal-window .poster-overlay').remove('');
// Assign a random version to video src to bypass cache
var modalsources = $('#modal-window source');
var nocachesrc = '';
for (var i = 0; i < modalsources.length; i++) {
nocachesrc = modalsrc[i] + '?rnd=' + Math.random()*Math.random();
modalsources[i].setAttribute('src', nocachesrc);
modalsources[i].setAttribute('type', modaltype[i]);
}
var modalvideo = $('#modal-window video');
modalvideo[0].setAttribute('controls', 'controls');
// Reveal modal window and play video
$('#modal-window').modal('show');
$('#modal-window').on('shown.bs.modal', function() {
modalvideo[0].play();
});
// Stop playing video when modal window is closed
$('#modal-window').on('hide.bs.modal', function() {
modalvideo[0].pause();
});
}
});
}
});
Remove the semicolon from the type attribute of the source nodes, should be: type="video/mp4", other browsers are probably just being forgiving of this.

Categories

Resources