I've been struggling for a while to include a Plyr library (read & customise audio src) and I need to embed it via requireJS (important). all the other libraries work except this one, I wonder what's wrong!
Error: (console)
Uncaught TypeError: Plyr is not a constructor
Here is an example working without RequireJS, maybe it cool help.
JsFiddle
My JsFiddle example :
html:
<audio crossorigin playsinline>
<source src="https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3" type="audio/mp3">
<source src="https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg" type="audio/ogg">
</audio>
Js:
requirejs.config({
paths: {
jquery: 'https://code.jquery.com/jquery-3.6.3.min',
plyr: 'https://cdn.plyr.io/3.7.3/plyr'
},
shim: {
"plyr": {
deps: ["jquery"]
}
}
});
require(['jquery','plyr'], function($, Plyr) {
'use strict';
const player = new Plyr("audio", {});
window.player = player;
});
Related
I am trying to find a way to reproduce the effect of having all my sound files in my A-frame vr project autoplay once the scene loads, but with an on-window-click function so that they are able to work on browsers that do not allow autoplay / require user interaction
i'm sure the solution is pretty simple but I have tried for quite a few hours and can't seem to find a solution online including stack anywhere. when I try to follow tutorials such as this, I can't get them to work:
Play sound on click in A-Frame
Autoplaying videosphere from A-frame is not working on any browser(Safari/Chrome)
in my html i have something like this (but with about 10 sound files and 10 models in total):
<a-assets>
<a-asset-item id="logo" src="code/to/gltf"></a-asset-item>
<a-asset-item id="logo" src="code/to/gltf"></a-asset-item>
<audio id="track" src="code/to/audio" crossOrigin="anonymous"></audio>
<audio id="track" src="code/to/audio" crossOrigin="anonymous"></audio>
</a-assets>
<a-entity
gltf-model="#logo"
play-audio
sound="
src: #track;
loop: true;
volume: 0.05;
distanceModel: inverse;
refDistance: 1000"
position="0 1.5 -2.5"
rotation="90 0 0"
scale="0.4 0.4 0.4"
foo>
</a-entity>
<a-entity
gltf-model="#bink"
navigate-on-click="url: bink.html"
play-audio
sound="
src: #binkaudio;
loop: true;
volume: 1;
distanceModel: inverse;
refDistance: 10"
position="-2.93 1.5 6"
rotation="90 149 0"
scale="0.4 0.4 0.4"
foo
></a-entity>
then in a separate js file linked into the html I have this
AFRAME.registerComponent('play-audio', {
init: function () {
this.onClick = this.onClick.bind(this);
},
play: function () {
window.addEventListener('click', this.onClick);
},
// pause: function () {
// window.removeEventListener('click', this.onClick);
// },
onClick: function (evt) {
var sceneEl = document.querySelector('a-scene')
var entity = sceneEl.querySelectorAll('[sounds]');
entity.components.sound.playSound();
}
});
EDIT
I keep recieveing this error message
Uncaught TypeError: Cannot read property 'sound' of undefined
at i.onClick (audiohandler.js:109)
at HTMLElement.emit (a-node.js:263)
at i.twoWayEmit (cursor.js:415)
at i.onCursorUp (cursor.js:271)
at HTMLCanvasElement.<anonymous> (bind.js:12)
EDIT
this was the final solution thank you !!!
AFRAME.registerComponent('play-audio', {
init: function () {
this.onClick = this.onClick.bind(this);
},
play: function () {
window.addEventListener('click', this.onClick);
},
pause: function () {
window.removeEventListener('click', this.onClick);
},
onClick: function (evt) {
let entity = document.querySelectorAll('[sound]');
for (let item of entity) {
item.components.sound.playSound();
}
}
});
If you want to grab all nodes that have the sound component, then you need to change your selector from sounds to sound - document.querySelectorAll('[sound]').
Also querySelectorAll will return a list of elements, so You have to iterate through them:
for (let item of list) {
item.components.sound.playSound()
}
This is fantastic and something I've been trying to figure out for a while. How could we adapt this component so that you had to click on once of the sound entities to start it (instead of clicking anywhere in the scene?)
I want one or more videos to play/pause depending on whether or not they're in the viewport.
I understand this can be achieved with jQuery (and plugins), so I've tried using the isInViewport plugin along with the following code, but I receive the error shown below.
HTML
<script src="scripts/jquery.js"></script>
<script src="scripts/isInViewport.js"></script>
[...]
<video id="video1" src="file.mp4" width="50%"></video>
[...]
<script src="scripts/script.js"></script>
JS
var $video = document.getElementsByTagName("video1");
if ($video.is(":in-viewport")) {
$video.play();
} else {
$video.pause();
};
Console
TypeError: $video.is is not a function
try
$('video').each(function() {
if ($(this).is(":in-viewport")) {
$(this)[0].play();
} else {
$(this)[0].pause();
}
}
);
I'm new with AngularJS. I must create customs controls for a video player (HTML5 <video>).
Basically, I would use getElementById('myvideotag'), listen clicks on the video for play/pause.
How I can do this with AngularJS ? Binding the click with ng-click="videoPlayPause()" but then, how I play or pause the video. How I use the classic methods of <video> ?
I guess it's really simple... I didn't get all the AngularJS concepts yet !
Thank you :)
Oh, the code... in the view:
<video autoplay="autoplay" preload="auto" ng-click="video()">
<source src="{{ current.url }}" type="video/mp4" />
</video>
In the right controller:
$scope.video = function() {
this.pause(); // ???
}
For full control, like behaviour and look&feel, I'm using videoJS in angular.
I have a ui-video directive that wraps the video HTML5 element. This is necessary to overcome a problem of integration with AngularJS:
m.directive('uiVideo', function () {
var vp; // video player object to overcome one of the angularjs issues in #1352 (https://github.com/angular/angular.js/issues/1352). when the videojs player is removed from the dom, the player object is not destroyed and can't be reused.
var videoId = Math.floor((Math.random() * 1000) + 100); // in random we trust. you can use a hash of the video uri
return {
template: '<div class="video">' +
'<video ng-src="{{ properties.src }}" id="video-' + videoId + '" class="video-js vjs-default-skin" controls preload="auto" >' +
//'<source type="video/mp4"> '+ /* seems not yet supported in angular */
'Your browser does not support the video tag. ' +
'</video></div>',
link: function (scope, element, attrs) {
scope.properties = 'whatever url';
if (vp) vp.dispose();
vp = videojs('video-' + videoId, {width: 640, height: 480 });
}
};
});
How about this:
In your HTML, set ng-click="video($event)" (don't forget the $event argument), which calls the following function:
$scope.video = function(e) {
var videoElements = angular.element(e.srcElement);
videoElements[0].pause();
}
I believe this is the simplest method.
Documentation for angular.element
Also, this might help you get used to Angular: How do I “think in AngularJS/EmberJS(or other client MVC framework)” if I have a jQuery background?
You could also take a look to my project Videogular.
https://github.com/2fdevs/videogular
It's a video player written in AngularJS, so you will have all the benefits of bindings and scope variables. Also you could write your own themes and plugins.
I also used videojs
bower install videojs --save
I wanted to use my directive in a ng-repeat and with a scope object, so... here's my version of it with props to Eduard above. I didn't seem to have a problem with the video player disposal, but the source tag issue referenced was an actual problem.
I also decided to write this up as an answer, so that I could give an example of how one might want to handle the videojs events.
IMPORTANT! Please note I am using Angular.js with Jinja2 templates, so I had to change my Angular HTML interpolation markers to {[ ]} from {{ }} in case anyone notices that as weird. I'll include that code too, so it's not weird for anyone.
Interpolation tweak
app.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('{[');
$interpolateProvider.endSymbol(']}');
}]);
Directive
angular.module('myModule').directive('uiVideo', function () {
// Function for logging videojs events, possibly to server
function playLog(player, videoId, action, logToDb) {
action = action || 'view';
var time = player.currentTime().toFixed(3);
if (logToDb) {
// Implement your own server logging here
}
// Paused
if (player.paused()) {
console.log('playLog: ', action + " at " + time + " " + videoId);
// Playing
} else {
console.log('playLog: ', action + ", while playing at " + time + " " + videoId);
if (action === 'play') {
var wrapFn = function () {
playLog(player, videoId, action, logToDb);
};
setTimeout(wrapFn, 1000);
}
}
}
return {
template: [
'<div class="video">',
'<video id="video-{[ video.id ]}" class="video-js vjs-default-skin img-responsive" controls preload="none"',
' ng-src="{[ video.mp4 ]}"',
' poster="{[ video.jpg ]}"',
' width="240" height="120">',
'</video>',
'</div>'
].join(''),
scope: {
video: '=video',
logToDb: '=logToDb'
},
link: function (scope, element, attrs) {
scope.logToDb = scope.logToDb || false;
var videoEl = element[0].children[0].children[0];
var vp = videojs(videoEl, {},
function(){
this.on("firstplay", function(){
playLog(vp, scope.video.id, 'firstplay', scope.logToDb);
});
this.on("play", function(){
playLog(vp, scope.video.id, 'play', scope.logToDb);
});
this.on("pause", function(){
playLog(vp, scope.video.id, 'pause', scope.logToDb);
});
this.on("seeking", function(){
playLog(vp, scope.video.id, 'seeking', scope.logToDb);
});
this.on("seeked", function(){
playLog(vp, scope.video.id, 'seeked', scope.logToDb);
});
this.on("ended", function(){
playLog(vp, scope.video.id, 'ended', scope.logToDb);
});
}
);
}
};
});
Directive HTML usage
<div ng-repeat="row in videos">
<ui-video video="row"></ui-video>
</div>
tried a few things and can't get this working. I have an inline video element that I'm loading into a colorbox, then applying mediaelementjs to it. I'm firing mediaelement on the colorbox onOpen event.
Problem is that the movie keeps playing when I close colorbox. I can't access that player outside the success function, like in onCleanup or onClose.
Here's the html where the video sits:
<div class="hidden">
<div id="trailer-wrap">
<video id="trailer" src="...video source..." type="video/mp4" controls="controls" width="720" height="480" preload="none">
<object width="720" height="405" type="application/x-shockwave-flash" data="path/to/flashmediaelement.swf">
<param name="movie" value="path/to/flashmediaelement.swf" />
<param name="flashvars" value="controls=true&file=...video source..." />
<img src="poster.jpg" alt="No video playback capabilities" />
</object>
</video>
</div>
</div>
and here's the script below it:
$(".cbox-trigger").colorbox({
inline:true,
innerWidth:"720px",
innerHeight:"480px",
scrolling:false,
onOpen: function(){
var player = new MediaElementPlayer('#trailer', {
success: function (mediaElement, domObject) {
// call the play method
mediaElement.play();
}
});
$.fn.colorbox.resize();
},
onCleanup: function(){
[how to access player object here?].pause();
}
});
For this, you may need to define player variable outside of colorbox block, then use this variable in the onCleanup callback
var player = null;
$(".cbox-trigger").colorbox({
inline:true,
innerWidth:"720px",
innerHeight:"480px",
scrolling:false,
onOpen: function(){
player = new MediaElementPlayer('#trailer', {
success: function (mediaElement, domObject) {
// call the play method
mediaElement.play();
}
});
$.fn.colorbox.resize();
},
onCleanup: function(){
player.pause();
}
});
From what I've read, this is how I should setup the YouTube API:
<!DOCTYPE html>
<html lang="en">
<head>
<meta content='text/html;charset=UTF-8' http-equiv='content-type' />
<title>Youtube Player</title>
<script src="jquery.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
function onYouTubePlayerReady(id) {
console.log("onYouTubePlayerReady() Fired!");
var player = $("#youtube_player").get(0);
}
var params = { allowScriptAccess: "always" };
var atts = { id: "youtube_player" };
swfobject.embedSWF("http://www.youtube.com/apiplayer?enablejsapi=1",
"youtube", "425", "356", "8", null, null, params, atts);
</script>
</head>
<body>
<div id="youtube"></div>
</body>
</html>
However, 'onYouTubePlayerReady()' doesn't fire at all, and if I manually get a reference to the player, a lot of methods are undefined; for example, cueVideoById() works, but playVideo() doesn't.
How can I fix this problem?
You need to be on a web server with your test script, as stated in the documentation:
Note: To test any of these calls, you must have your file running on a webserver, as the Flash player restricts calls between local files and the internet.
this function:
function onYouTubePlayerReady(playerid) {
console.log('readyIn');
};
don't have to be directly in head in separate script tag.
Only rule you have to keep is: don't put this function inside domready event - it has to be defined sooner.
For example in mootools I use it like this:
function onYouTubePlayerReady(playerid) {
echo('readyIn');
};
document.addEvent('domready', function() {
...
});
I have the answer, separate out this portion of the script and put it in the head in its own script tag. OMG, finally
<script type="text/javascript" language="javascript">
function onYouTubePlayerReady(playerid) {
ytp = document.getElementById('ytplayer');
ytp.mute();
};
</script>
I consider this the best way of adding a youtube video to your website with javascript. It gives you a very clear way of dealing with events. It works on a local machine, and as far as I know it works on apple devices. You can use all the events and function described in the javascript documentation for the youtube api.
<div id="player"></div>
<script>
//Load player api asynchronously.
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var done = false;
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'JW5meKfy3fY',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(evt) {
evt.target.playVideo();
}
function onPlayerStateChange(evt) {
if (evt.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
source: http://apiblog.youtube.com/2011/01/introducing-javascript-player-api-for.html
<!DOCTYPE html>
had to lead the page in order for the html5 stuff to function for me in FF4
If you're embedding youtube videos like so:
<iframe src="http://www.youtube.com/embed/VIDEO_ID?jsapi=1" width="1280" height="720" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
then you should place
<script src="http://www.youtube.com/player_api"></script>
after the </iframe>. At least that's how I got it to work.
Additionally, if you're dynamically changing the [src] attribute of the iframe via jQuery or whatever to load a new video then you need to call onYouTubePlayerAPIReady() after it has loaded.
I prefer to change the [src] attribute and then:
setTimeout(onYouTubePlayerAPIReady, 500);
Just had the same issue, but for another reason. It worked in Chrome but not Firefox, and the reason was that I had a http header "Content-type: text/xml" instead of "Content-type: text/html". Serving as HTML now fires the onYouTubePlayerReady event in Firefox, too.
Just posting this in case someone stumbles on this answer from Google (like I just did when trying to find a solution).