在 Youtube 站点中获取 Flash 视频状态 - Chrome 扩展

Get flash video state in Youtube site - Chrome extension

正在开发 Chrome 扩展,将脚本注入 Youtube 站点本身,并使用 Youtube 播放器 API 收听播放器事件。

注入的脚本代码:
(您可以 运行 在 Youtube HTML5 视频页面的控制台中查看它是否有效)

var theYTplayer = document.getElementById('movie_player');

theYTplayer.addEventListener('onStateChange', function(){
    console.log('--- player state has been changed');
});

当谈到 HTML5 视频时,一切都很好,但在 Flash 直播中就不行了。
在 Flash 中,由于某些原因,所有 GET 函数 returns 错误,而 SET 函数工作正常。
获取:getPlayerStateisMutedgetVolume
设置:playVideopauseVideomuteunMutesetVolume

这可能是一个错误,所以我在这里报告了它:issue #7043

例如,您可以在 this live streaming video 上进行测试。

如果我做错了什么,请告诉我应该怎么做。
万一是BUG,那就想个办法检测视频有没有播放。
我比较了两个 DOM,当状态发生变化或其他任何事情时,没有添加任何 class,文件最终匹配。
然后我看到在播放视频的时候Chrome在选项卡中添加了新的extra favicon speaker,但是那只是在有声音的情况下,如果视频静音那么图标就不会出现所以这不好。所以你可能有任何其他 ideas/workarounds 如何检测视频是否正在播放或修复我的代码?

编辑!
这是一种可行的解决方法,但它不是正确的答案,您正在寻找的是:


解决方法,
flash 播放器需要一些时间来完成加载并使其元素 (#movie_player) 成为一个对象。
使用 setInterval 检查元素是否为 null ,只有当它不为 null 时才意味着我们可以将它与 GET 函数一起使用,在这种情况下它将使用 getPlayerState 函数,在另一个 setInterval 中使用它来检查状态会给你一个假的 "onStateChange" 监听器,不幸的是,即使播放器已完全加载,添加事件监听器仍然不起作用,但是 GET 函数确实有效,所以我们将使用它们。

在我的例子中,我只需要知道在我的扩展程序中打开 pageAction 弹出窗口时的状态,所以只要在弹出窗口加载时调用 getPlayerState 函数就足够了。

在注入的脚本中:

var theYTplayer = document.getElementById('movie_player'),
    theYTplayerState;

var checkYTplayerReady = setInterval(function(){
    theYTplayer = document.getElementById('movie_player');

    if(theYTplayer != null){
        clearInterval(checkYTplayerReady);

        setTimeout(function(){
            checkYTplayerState();
        },2000);

        theYTplayer.addEventListener('onStateChange', checkYTplayerState);
    }
}, 100);

function checkYTplayerState(event){ 
    theYTplayerState = event;

    if(typeof event === 'undefined'){
        theYTplayerState = theYTplayer.getPlayerState();
    }

    if(theYTplayerState == 1){
        theYTplayerState = 'playing';
    }else{
        theYTplayerState = 'not playing (unstarted/paused/buffering/ended/video cued)';
    }

    return theYTplayerState;
}

从那里您可以使用消息将其发送到内容脚本,然后发送到弹出窗口或将其用于您需要的任何地方。

我发现了我的代码中的问题以及如何使用 on state change 侦听器。

而在 Javascript 中,当您使用 addEventListener 时,您可以设置不带引号的回调函数名称,如下所示:

player.addEventListener('onStateChange', playerStateChange);

但是!
当涉及到 Youtube 播放器 API 时,您必须将函数名称设置为 string,即带引号:

player.addEventListener('onStateChange', 'playerStateChange');

所以...是的,这就是整个问题,虽然它适用于没有引号的 HTML5 播放器,但它不适用于 Flash 播放器。

来自文档:

Adding or removing an event listener

player.addEventListener(event:String, listener:String):Void

Adds a listener function for the specified event. The Events section below identifies the different events that the player might fire. The listener is a string that specifies the function that will execute when the specified event fires.

https://developers.google.com/youtube/iframe_api_reference#Adding_event_listener

在文档中唯一可以清楚地看到它的地方是 "Subscribing to Events" 部分下的 JS API。

Subscribe to events
by adding an event listener to the player reference. For example, to get notified when the player's state changes, add an event listener for onStateChange and include a callback function.

function onYouTubePlayerReady(playerId) {
    ytplayer = document.getElementById("myytplayer");  
    ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
}

function onytplayerStateChange(newState) {
    alert("Player's new state: " + newState);
}

https://developers.google.com/youtube/js_api_reference#SubscribingEvents

这样做之后,您可以在准备就绪后将侦听器添加到播放器,它会正常工作。
要知道播放器何时准备就绪,您需要使用 manifest 文件中的 run_atdocument_start 注入脚本。 然后在您的代码中使用函数名称 onYouTubePlayerReady,如下所示:

var theYTplayer;

function onYouTubePlayerReady(){
    theYTplayer = document.getElementById('movie_player');
    theYTplayer.addEventListener('onStateChange', 'playerStateChange');
}

不要使用 iframe API 函数名 onYouTubeIframeAPIReady 因为它不起作用,只有 JS API 函数名 onYouTubePlayerReady.

虽然我之前发布的方法有效,但这是正确的方法。