Detecting Youtube Seek Event - javascript

I'm writing a Chrome extension which controls background music (Pandora, Google Music, etc) in response to Youtube events.
I'm able to detect when the video is started, paused, or stopped by adding an event listener to the player. However, the video switches states from playing to paused when seeking. This causes the background music to respond (unpauses) when the user is skipping in the video.
Is there any way to catch this click-and-drag seek event from within Javascript? A workaround (which might be the correct behavior) is to only unpause background music when the video ends--not just pauses--but I was curious if anybody had tackled something like this before.

Seeking is normally a quite a short event, so make the music only start up again after a few seconds have elapsed after the player is paused.

Related

Content script for pausing youtube videos

I am currently working on a google chrome extension that features a content script for altering youtube pages. I have done some work with altering the DOM already and all of that works, however, I have been looking for solutions to have the youtube video pause when the page loads.
I initially thought perhaps I could simulate a keystroke as the spacebar pauses youtube videos. I also tried using javascript to pause the video but I don't think it works with Youtube's custom video player.
Don't feel obligated to write any code for this but if someone could point me in the right direction I would be very grateful.
On the main page of a video, the HTML5 video element playing the video has a specific class, so you can target that; and as an HTML5 video element, it has the play() and pause() methods already.
document.querySelectorAll('.html5-main-video').forEach(vid => vid.pause());
That will pause all HTML5 main videos on the page. Helpfully enough, that's the same class used by the little autoplaying video on some channel pages, so it should work for those as well :)
(Don't worry about Flash videos; YouTube hasn't supported those for years now.)

YouTube JavaScript player starts to play the video when seekTo is called

Accordring to the YouTube IFrame Player API the seekTo method should start to play the video unless the player state is "paused". That would be OK if there was any way to put the player in this state. Here is a fiddle that calls pauseVideo to put the player in the "paused" state. Then it calls seekTo. The video starts playing.
Do I read the docs wrong in any way? Or is this a bug in the YouTube player?
http://jsfiddle.net/lborgman/r46ofyz0/6/
With youtube it seems paused means that you have requested the video to pause, unlike HTML5 video where paused simply means "not playing"
You can check the state with instance.getPlayerState(). Anything except 2 (paused) should trigger playing. In this case it seems to be video cued (5).
I created an issue for what I think is the real problem (pauseVideo doesn't do anything), using a fork of your jsfiddle. It may not be considered to be a bug though. We'll see.

How to interact with Netflix Cadmium video player on the client?

I have a Netflix account and I have peeked under the hood at its video player running inside Google Chrome. Netflix calls its video player "Cadmium" and the javascript exposes all the functions and event handlers you might expect, such as play, stop, pause, mute, etc. I'm building a little Chrome extension that would enable me to call these Cadmium player function, but the hard part for me is figuring out how to create an instance of the player so I can start calling. The javascript is large, complex, and somewhat obscure. Once I can create an instance of that player, I'm thinking that making calls into the functions will be easy.
Here is a relevant chunk of js:
muteOn: function() {
this.savedVolume = this.getVolume(),
this.updateVolumeDisplay(0),
this.scrubber.updatePercent(0),
this.muted = !0,
this.videoPlayer.setMuted(this.muted)
}
In Chrome dev tools I can set a breakpoint inside that block, and execution hits the breakpoint when I click the Mute button on the netflix video player. The Netflix js is (unsurprisingly) heavily obfuscated via method renaming. I tried stepping through the code in the debugger and ended down a hundred rabbit holes, never able to find my way to the top of the stack, so that I could make that same call (at top of stack) to simulate the user clicking the mute button. I also tried the approach of programmatically clicking the mute button on the UI player, which would meet my needs equally well, but they have serious defensive mechanisms in there, spinning me like a top.
Since there are over 100K lines of javascript, and I'm uncertain which chunks exactly would be relevant for this post, I would like to suggest that you load Netflix in Chrome, open dev tools, play a movie, and inspect the pause or mute button. Interacting with those video player controls takes you into the maze of javascript which I'm trying to see how I can tap into to control aspects of the player programmatically (just from dev tools is fine for now). Another important thing I need to figure out is how to query the video player to determine the current elapsed time of the playing video.
Any ideas how I can crack this nut? (Thanks in advance!)
Using Chrome, I get playback using HTML 5 video.
Once you get a hold on the <video> tag element, you can use the HTML 5 video API:
Get the <video> element
var video = document.evaluate('//*[#id="70143639"]/video',document).iterateNext()
70143639 is the id of the video, as in https://www.netflix.com/watch/70143639
Remaining time (HH:mm)
document.evaluate('//*[#id="netflix-player"]/div[4]/section[1]/label', document).iterateNext().innerHTML
Elapsed time (seconds)
video.currentTime
Elapsed time updates
video.addEventListener("timeupdate",
function(e) {
console.debug("Seconds elapsed: ", e.timeStamp/1000/60);
}
);
Note that I don't get the same results as with video.currentTime, you may need to use an offset based on the difference. Also it may be something explained in the spec: https://www.w3.org/TR/html5/embedded-content-0.html
Play
video.play();
Pause
video.pause();
Go back and forth in time
Courtesy of rebelliard:
netflix.cadmium.UiEvents.events.resize[1].scope.events.drage‌​nd[1].handler(null, {value: 600, pointerEventData: {playing: false}}); where 600 is the number of seconds to seek.
Note that I ran into "Whoops, something went wrong..." using this:
video.currentTime += 60;
Even with pause and play calls. This is what this demo page does, you nay need to read the full spec on seeking.
Mute and get muted status
video.muted = true
Like video.currentTime, this is a writeable property.

Disable iOS video controls for youtube video

My goal is to present clients with a video from youtube (iframe api) that cannot be skipped or seeked forward. On all platforms but iOS this is simple. But I'm having problems with Apple's fullscreen player.
Once playback on a video has started, you are transported to Apple's iOS video player, with it's standard controls. What I have been unable to find is if you can hide/disable these controls in the fullscreen layout.
Alternatively, if I can capture events from the iOS player and merely detect when a user is trying to skip would work as well. I've attached events in accordance with the HTMLMediaElement specs, but none of them fire. Nor do any of youtube's events fire.
I am tracking the console through Safari from the iOS simulator, which could be a problem on it's own.
Any help would be appreciated. I've gone through every SO post on the subject.
While I was unable to find anyway to hide the iOS default viewer (I believe it's impossible), I was able to get the youtube events to fire. With keeping an interval, and checking that against the video's time each time an event is fired, I can figure out if a user has skipped.

HTML5 - Check if autoplay is allowed

My website plays background music with autoplay. I made it use my custom controls for play and pause. Now, I'd like to set the initial state according to what is going on. If the music is about to play for real, it should show pause icon, otherwise (e.g. on mobile) play icon.
I would use audio.paused boolean value, but it's always false before the audio is loaded.
I would use audio.autoplay value, but it's always true for me, even on devices that don't support it.
Is there any clean way to know whether the audio will be played? I would like to keep it in sync with autoplay attribute, so if I decided to remove it, the state should always show play icon in the beginning.
Just playing or even buffering songs isn't especially fair, when there is the slightest chance people can be on the site for other reasons, like for example to check for updates, to share the link. people can be on the page with a mobile network, with limited bandwidth and downloads of those sizes shouldn't ever start sneaky behind their back.
edit: a few additional references
Here is an overview over the reasons not to have music on autoplay
And contrary, a website I personally like a lot with a great use of background music on autoplay
But if you are already building your own player and want that to be a feature of the page, setting that player to autoplay would not only devalue your own work, totally break your design. Instead you could just trust that people who want to hear the music will identify your audio player and use it.
To fully implement your custom player GUI you may want to listen for all audio events on the player element and update your view accordingly. The event you are looking for is "canplaythrough" but you probably want to react to at least most of the other events too. Those events are:
playing
waiting
seeking
seeked
ended
loadedmetadata
loadeddata
canplay
canplaythrough
timeupdate
play
pause
ratechange
volumechange
suspend
emptied
stalled
You currently may do something along the lines of
view.showPlayButton();
player.play();
but that breaks as soon as you at some point want to toggle your player in some other way or something else happens, like it gets stalled, so better listen to the event and update your GUI in one place, and control the playback (like start / stop the player) in another.

Categories