Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control YouTube player from a Chrome extension

I am developing a Google Chrome extension that needs to take over all the controls of a YouTube video (play, pause, next, previous, change the volume, start video at X seconds, etc). I tried the following approaches:

First approach: with content_scripts

My manifest.json contains the following:

"content_scripts": [
    {
        "matches": ["https://www.youtube.com/*"],
        "js": ["scripts/jquery.js", "scripts/in_page.js"]
    }
],

I'm loading the scripts for every YouTube link, and not only /watch* because now YouTube navigation is fully using AJAX, therefore the page is not entirely refreshed, and if I was on a search page and then clicked on a video, the extension wouldn't have loaded my content_scripts.

How I took over the controls

I successfully managed to trigger simple click events on the YouTube player, such as Play, Pause, Previous video, Next video.

For instance, this works to pause the video:

$("#player-api .html5-video-controls .ytp-button-pause").trigger("click");

But it seems that I can't trigger events such as clicking on the progress bar to play from a specific moment of the video or restart the video.

I tried this piece of code without success (using jQuery's $.Event):

var click = $.Event("click");
click.clientX = 0; // Beginning of the video
click.clientY = 0; // I also tried several other coordinates
$("#player-api .html5-video-controls .html5-progress-bar").trigger(click);

(And I also tried clicking on every child of the .html5-progress-bar, but nothing worked.)

Second approach: with an injected script

As I seemed to have encountered a dead-end with my first approach, I then tried something else: injecting a script directly inside the page.

My manifest.json contains the following:

"content_scripts": [
    {
        "matches": ["https://www.youtube.com/*"],
        "js": ["scripts/jquery.js", "scripts/isolated.js"]
    }
],

"web_accessible_resources": [
    "scripts/injected.js"
],

Contents of isolated.js

var s = document.createElement("script");
s.src = chrome.extension.getURL("scripts/injected.js");
s.onload = function() {
    this.parentNode.removeChild(this);
};
(document.head || document.documentElement).appendChild(s);

Contents of injected.js

Well, this is where I encountered my second dead-end. I may have overlooked some things, but I searched in every object inside the page, I found yt, ytplayer, player, and others. But none of them seem to have proper functions to trigger changes on the player such as play/pause/next, etc.

I then downloaded the html5player.js from YouTube (available here) and beautified it to take a peek at what was under the hood. I found some interesting function names such as playVideoAt, playVideo, pauseVideo around the lines 20235-20315 (once beautified).

That would be exactly the functions I would want to call/invoke, but I don't know where they are, and how to call them.

I also know that YouTube has a JavaScript API to control the player, but it's only for embedded players (iframes), so it's not useful in my case.

like image 768
Yoone Avatar asked Jun 29 '15 12:06

Yoone


People also ask

How do I control YouTube speed?

Go to a video. Hover over the player and click Settings . Click Speed. Select the speed at which you'd like the video to play.

How do you play custom speed on YouTube?

As you're watching a video, tap the three-dot hamburger menu in the top-right corner. This will bring up the video settings, much like the gear icon does on desktop. Select Playback speed. You'll see the familiar preset speeds ascending by 0.25 increments from 0.25 to 2.0.


1 Answers

It sounds like you're using YouTube's HTML5 video player. In that case you can just interface with the <video> DOM element. It happens to be the only <video> element on the page, so just do:

$('video').play()
$('video').pause()
$('video').currentTime = 100

The interface is here.

As for previous and next videos, you're almost certainly right that the easiest thing to do is:

$('.ytp-button-next').click()
$('.ytp-button-prev').click()

Since that obviously isn't a published API you have no guarantee those class names will stay the same in future.

like image 72
Sam Avatar answered Sep 29 '22 13:09

Sam