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

HerrimanCoder picture HerrimanCoder · Feb 1, 2017 · Viewed 15.6k times · Source

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!)

Answer

pyb picture pyb · Feb 5, 2017

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.