jQuery video hover optimising dynamic selectors - javascript

I'm working on something where the user hovers over a video to trigger it playing. When they hover over a different video, this new video starts playing and stops the others.
I'm using Vimeo and their Froogaloop library ( not too relevant here, could also be video tags, mainly concerned with the caching of the selectors ).
This code works fine, but I know it's not as optimised as it should be, it uses multiple selectors each time the hover function is called which I don't want to do. Can I improve this code so that it doesn't do this? Or is it Ok to keep calling the jQuery selectors like this in modern browsers now?
Here is a simplified working demo
function hoverVid() {
var frame = $(this).find('iframe');
var player = $f(frame[0]);
player.api('play');
var vids = $('.vid-row iframe').not(frame);
vids.each(function(index) {
var frame = $(this);
var player = $f(frame[0]);
player.api('pause');
});
}
$('.vid-row').hover(hoverVid);
Cheers :]

I improved it a bit - As per #GerardCuadras comment, removed the need for using the .not() filter by simply pausing all the videos, then playing the desired one.
This allowed me to cache the list of iframes. I also optimised the selector to use an #id and .find().
JSBin
var vidz = $('#vidz').find('iframe');
function hoverVid(e){
vidz.each(function( index ){
var frame = $(this);
var player = $f(frame[0]);
player.api('pause');
});
var frame = $(this).find('iframe');
var player = $f(frame[0]);
player.api('play');
}
$('.vid-row').hover(hoverVid);

Related

Tampermonkey play sound when page changes?

Basically, there is a specific website I visit that I keep a userscript auto-refresh set on a timer. This specific page changes content every now and then upon being refreshed. I want a sound to be played whenever the page gets refreshed and any page changes occur.
Here's the code I've currently gathered, but I still need a few things to get it running properly:
// ==UserScript==
// #name Auto-Refresh
// #include https://www.prolific.ac/studies
// ==/UserScript==
//--- https://stackoverflow.com/questions/25484978/i-want-a-simple-greasemonkey-script-to-reload-the-page-every-minute
setTimeout(function(){ location.reload(); }, 20*1000);
var player = document.createElement('audio');
player.src = 'https://notificationsounds.com/soundfiles/a86c450b76fb8c371afead6410d55534/file-sounds-1108-slow-spring-board.mp3';
player.preload = 'auto';
// Play a sound with condition and then player.play()
So basically the rest of the script would be "if page change occurs (after refresh), then play sound." This is where I'm having trouble.
I've been using this thread as a guide: How to monitor a static HTML page for changes with Greasemonkey? Use a hash? But I'm not quite sure which method would work best. Any and all advice would be deeply appreciated. Thanks in advance.
In my experience you want to check for changes in specific elements, not the HTML of the entire page because there are often technical parts of the page that will change (timestamps, counters, random generated IDs, ads). So I have used jQuery to find the pieces which I then check for changes.
I guess you could check for changes in entire parts of page by doing something like this:
var player = document.createElement('audio');
player.src = 'https://notificationsounds.com/soundfiles/a86c450b76fb8c371afead6410d55534/file-sounds-1108-slow-spring-board.mp3';
player.preload = 'auto';
// First you store the content
var initialContent = $('.articles-section').html();
// Then next time you compare that content to the newly retrieved content
var newContent = $('.articles-section').html();
if (newContent !== initialContent) {
player.play();
}
You will have to use some kind of persistent storage, I guess you can use localStorage for that. See HTML5 Web Storage.
This part
var player = document.createElement('audio');
player.src = 'https://notificationsounds.com/soundfiles/a86c450b76fb8c371afead6410d55534/file-sounds-1108-slow-spring-board.mp3';
player.preload = 'auto';
only worked for me when I did
player.play() instead of player.preload = 'auto'

How can I target a specific Vimeo video when I have mulitple videos on the page?

I have several videos embedded from Vimeo and I want to show an overlay with some information when you hover over the video. The overlay blocks the play button, so I want the video to play when you click the overlay. It works just fine with a single video, but I'm having trouble having the play command target the correct video when there are multiple videos. Here's my script:
$(".overlay").click(function() {
$(this).toggleClass("playButton pauseButton");
var parent = $(this).parent();
var iframe = document.getElementById("vimeo");
var player = $f(iframe)
var paused = player.api('paused()');
var playButton = $(parent).children(".playButton");
$(playButton).click( function () {
player.api('play');
});
var pauseButton = $(parent).children(".pauseButton");
$(pauseButton).click( function () {
player.api('pause');
});
});
The issue seems to be with this line
var iframe = document.getElementById("vimeo");
That pulls every video instead of just the one the overlay is associated with. I've tried this:
var iframe = $(this).siblings("#vimeo");
But it doesn't seem to like jquery and I get an error.
Vimeo should probably be a class instead of an id, but I couldn't get it to work with any method other than getElementById.
Can you add classes to each iframe to use for selecting the individual ones?
edited because my first suggestion was bad.

Please help me to use play/stop code so my code should stop and reset not pause [duplicate]

I am playing a small audio clip on click of each link in my navigation
HTML Code:
<audio tabindex="0" id="beep-one" controls preload="auto" >
<source src="audio/Output 1-2.mp3">
<source src="audio/Output 1-2.ogg">
</audio>
JS code:
$('#links a').click(function(e) {
e.preventDefault();
var beepOne = $("#beep-one")[0];
beepOne.play();
});
It's working fine so far.
Issue is when a sound clip is already running and i click on any link nothing happens.
I tried to stop the already playing sound on click of link, but there is no direct event for that in HTML5's Audio API
I tried following code but it's not working
$.each($('audio'), function () {
$(this).stop();
});
Any suggestions please?
Instead of stop() you could try with:
sound.pause();
sound.currentTime = 0;
This should have the desired effect.
first you have to set an id for your audio element
in your js :
var ply = document.getElementById('player');
var oldSrc = ply.src;// just to remember the old source
ply.src = "";// to stop the player you have to replace the source with nothing
I was having same issue. A stop should stop the stream and onplay go to live if it is a radio. All solutions I saw had a disadvantage:
player.currentTime = 0 keeps downloading the stream.
player.src = '' raise error event
My solution:
var player = document.getElementById('radio');
player.pause();
player.src = player.src;
And the HTML
<audio src="http://radio-stream" id="radio" class="hidden" preload="none"></audio>
Here is my way of doing stop() method:
Somewhere in code:
audioCh1: document.createElement("audio");
and then in stop():
this.audioCh1.pause()
this.audioCh1.src = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAVFYAAFRWAAABAAgAZGF0YQAAAAA=';
In this way we don`t produce additional request, the old one is cancelled and our audio element is in clean state (tested in Chrome and FF) :>
This method works:
audio.pause();
audio.currentTime = 0;
But if you don't want to have to write these two lines of code every time you stop an audio you could do one of two things. The second I think is the more appropriate one and I'm not sure why the "gods of javascript standards" have not made this standard.
First method: create a function and pass the audio
function stopAudio(audio) {
audio.pause();
audio.currentTime = 0;
}
//then using it:
stopAudio(audio);
Second method (favoured): extend the Audio class:
Audio.prototype.stop = function() {
this.pause();
this.currentTime = 0;
};
I have this in a javascript file I called "AudioPlus.js" which I include in my html before any script that will be dealing with audio.
Then you can call the stop function on audio objects:
audio.stop();
FINALLY CHROME ISSUE WITH "canplaythrough":
I have not tested this in all browsers but this is a problem I came across in Chrome. If you try to set currentTime on an audio that has a "canplaythrough" event listener attached to it then you will trigger that event again which can lead to undesirable results.
So the solution, similar to all cases when you have attached an event listener that you really want to make sure it is not triggered again, is to remove the event listener after the first call. Something like this:
//note using jquery to attach the event. You can use plain javascript as well of course.
$(audio).on("canplaythrough", function() {
$(this).off("canplaythrough");
// rest of the code ...
});
BONUS:
Note that you can add even more custom methods to the Audio class (or any native javascript class for that matter).
For example if you wanted a "restart" method that restarted the audio it could look something like:
Audio.prototype.restart= function() {
this.pause();
this.currentTime = 0;
this.play();
};
It doesn't work sometimes in chrome,
sound.pause();
sound.currentTime = 0;
just change like that,
sound.currentTime = 0;
sound.pause();
From my own javascript function to toggle Play/Pause - since I'm handling a radio stream, I wanted it to clear the buffer so that the listener does not end up coming out of sync with the radio station.
function playStream() {
var player = document.getElementById('player');
(player.paused == true) ? toggle(0) : toggle(1);
}
function toggle(state) {
var player = document.getElementById('player');
var link = document.getElementById('radio-link');
var src = "http://192.81.248.91:8159/;";
switch(state) {
case 0:
player.src = src;
player.load();
player.play();
link.innerHTML = 'Pause';
player_state = 1;
break;
case 1:
player.pause();
player.currentTime = 0;
player.src = '';
link.innerHTML = 'Play';
player_state = 0;
break;
}
}
Turns out, just clearing the currentTime doesn't cut it under Chrome, needed to clear the source too and load it back in. Hope this helps.
As a side note and because I was recently using the stop method provided in the accepted answer, according to this link:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element. In the link it mentions Firefox, but I encountered this event firing after setting currentTime manually on Chrome. So if you have behavior attached to this event you might end up in an audio loop.
shamangeorge wrote:
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element.
This is indeed what will happen, and pausing will also trigger the pause event, both of which make this technique unsuitable for use as a "stop" method. Moreover, setting the src as suggested by zaki will make the player try to load the current page's URL as a media file (and fail) if autoplay is enabled - setting src to null is not allowed; it will always be treated as a URL. Short of destroying the player object there seems to be no good way of providing a "stop" method, so I would suggest just dropping the dedicated stop button and providing pause and skip back buttons instead - a stop button wouldn't really add any functionality.
This approach is "brute force", but it works assuming using jQuery is "allowed". Surround your "player" <audio></audio> tags with a div (here with an id of "plHolder").
<div id="plHolder">
<audio controls id="player">
...
</audio>
<div>
Then this javascript should work:
function stopAudio() {
var savePlayer = $('#plHolder').html(); // Save player code
$('#player').remove(); // Remove player from DOM
$('#FlHolder').html(savePlayer); // Restore it
}
I was looking for something similar due to making an application that could be used to layer sounds with each other for focus. What I ended up doing was - when selecting a sound, create the audio element with Javascript:
const audio = document.createElement('audio') as HTMLAudioElement;
audio.src = getSoundURL(clickedTrackId);
audio.id = `${clickedTrackId}-audio`;
console.log(audio.id);
audio.volume = 20/100;
audio.load();
audio.play();
Then, append child to document to actually surface the audio element
document.body.appendChild(audio);
Finally, when unselecting audio, you can stop and remove the audio element altogether - this will also stop streaming.
const audio = document.getElementById(`${clickedTrackId}-audio`) as HTMLAudioElement;
audio.pause();
audio.remove();
If you have several audio players on your site and you like to pause all of them:
$('audio').each( function() {
$(this)[0].pause();
});
I believe it would be good to check if the audio is playing state and reset the currentTime property.
if (sound.currentTime !== 0 && (sound.currentTime > 0 && sound.currentTime < sound.duration) {
sound.currentTime = 0;
}
sound.play();
for me that code working fine. (IE10+)
var Wmp = document.getElementById("MediaPlayer");
Wmp.controls.stop();
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"
standby="Loading áudio..." style="width: 100%; height: 170px" id="MediaPlayer">...
Hope this help.
What I like to do is completely remove the control using Angular2 then it's reloaded when the next song has an audio path:
<audio id="audioplayer" *ngIf="song?.audio_path">
Then when I want to unload it in code I do this:
this.song = Object.assign({},this.song,{audio_path: null});
When the next song is assigned, the control gets completely recreated from scratch:
this.song = this.songOnDeck;
The simple way to get around this error is to catch the error.
audioElement.play() returns a promise, so the following code with a .catch() should suffice manage this issue:
function playSound(sound) {
sfx.pause();
sfx.currentTime = 0;
sfx.src = sound;
sfx.play().catch(e => e);
}
Note: You may want to replace the arrow function with an anonymous function for backward compatibility.
In IE 11 I used combined variant:
player.currentTime = 0;
player.pause();
player.currentTime = 0;
Only 2 times repeat prevents IE from continuing loading media stream after pause() and flooding a disk by that.
What's wrong with simply this?
audio.load()
As stated by the spec and on MDN, respectively:
Playback of any previously playing media resource for this element stops.
Calling load() aborts all ongoing operations involving this media element

Playing audio within a loop

First off here is my javascript code:
$(function() {
stepFade('.fadable',700,1);
});
function stepFade(target, speed, opacity) {
var mysound = new Audio("./sounds/kick.mp3");
var $fade = $(target);
($fade).each( function( i ) {
$(this).delay(i*speed).fadeTo(speed, opacity);
mysound.play();
mysound.currentTime = 0;
});
}
My goal here is to play a sound in conjunction with the fade ins that are happening on the website with jquery. I'm having trouble looping the sound in a way so that they are in sync. I've tried resetting the currentTime and that doesn't seem to work for some reason.
Another method would be to use mysound.loop(); however this just plays the sound in a loop without any considerations in the timing of the sounds. Thus this becomes de-synchronized with the animations.
Anyone can first explain why setting the current time doesn't work and what possible solutions exists?
Thanks!

Play selected audio while pausing/resetting others

I have two audio elements that play through a button's click event. I've successfully managed to pause one if another is selected but also need to set the paused element back to 0.0 seconds (i.e pause and reset).
I'm aware that Javascript currently doesn't have a stop() method which led assume that this would be done by setting its currentTime to 0. If so I just haven't been able to figure out the best way to incorporate this method in my code.
Right now I'm pausing all audio elements in the latter half of the conditional using $(".audio").trigger("pause"); which doesn't too efficient performance wise. What would be the best way to pause and reset only the previously played audio file and not every one on the page?
http://jsfiddle.net/txrcxfpy/
use below code . check DEMO
$(function() {
$('.track-button').click(function() {
var reSet = $('.track-button').not($(this)).siblings(".audio").get(0);
reSet.pause();
reSet.currentTime = 0;
var $this = $(this),
trackNum = $this.text(),
currentAudio = $this.siblings(".audio"),
audioIsPaused = currentAudio.get(0).paused;
if (audioIsPaused) {
currentAudio.get(0).play();
} else {
currentAudio.get(0).pause();
}
});
});

Categories