使用 Tampermonkey/javascript 控制 Netflix (HTML5) 播放

Posted

技术标签:

【中文标题】使用 Tampermonkey/javascript 控制 Netflix (HTML5) 播放【英文标题】:Controlling Netflix (HTML5) playback with Tampermonkey/javascript 【发布时间】:2015-03-11 18:02:33 【问题描述】:

在 Netflix 网站上观看 Netflix 视频时,我的目标是让用户脚本以编程方式调用播放控件。具体来说就是视频的音量、级别、播放/暂停状态、时间位置。

我已经能够操作 html5 视频元素本身,但直接控制它不会向用户提供所需的 netflix 控制栏反馈。 (即视频已暂停,但控制栏仍显示为正在播放)。

到目前为止,我的方法是尝试找到代表您在使用普通控件时单击的“按钮”的元素,并通过用户脚本触发它们的单击事件。但我似乎无法隔离正确的元素。此外,netflix 正在使用 javascript 压缩器/混淆器,这增加了在控制栏上找到代表按钮的适当元素的难度。

在这样的网站上,如何识别正在接收元素点击事件的元素,然后创建用户脚本以通过 tampermonkey 和/或greasemonkey 调用它?

在下面的示例代码中,我在视图上添加了一个按钮用于测试目的。

// ==UserScript==
// @name       Jump a minute ahead in netflix
// @version    0.1
// @description  A Test by trying to jump a minute or so ahead into a netflix movie
// @match        *://www.netflix.com/*
// @grant       GM_addStyle
// @require http://code.jquery.com/jquery-latest.js
// ==/UserScript==

var zNode       = document.createElement ('div');
zNode.innerHTML = '<button id="myButton" type="button">Try It</button>';
zNode.setAttribute ('id', 'myContainer');
document.body.appendChild (zNode);

//--- Activate the newly added button.
document.getElementById ("myButton").addEventListener (
    "click", ButtonClickAction, false
);

function ButtonClickAction (zEvent) 
    /*--- For our dummy action, we'll just add a line of text to the top of the screen.*/
    var zNode       = document.createElement ('p');
    var video = $("video:first-of-type");
    var playerSlider = document.getElementsByClassName("player-slider")[0];

    console.log(netflix);
    console.log(playerSlider);
    console.log(netflix.player);
    console.log(netflix.cadmium);
    console.log(netflix.cadmium.ui);
    console.log(netflix.cadmium.ui.playback);

    //video.get(0).pause();
    //video.get(0).currentTime = 2000.0;
    console.log(video.get(0).currentTime);
    console.log(netflix.cadmium.ui.volume);
    zNode.innerHTML = 'The button was clicked.';
    document.getElementById ("myContainer").appendChild (zNode);


//--- Style our newly added elements using CSS.
GM_addStyle ( multilineStr ( function () /*!
    #myContainer 
        position:               absolute;
        top:                    0;
        left:                   0;
        font-size:              20px;
        background:             orange;
        border:                 3px outset black;
        margin:                 5px;
        opacity:                0.9;
        z-index:                222;
        padding:                5px 20px;
    
    #myButton 
        cursor:                 pointer;
    
    #myContainer p 
        color:                  red;
        background:             white;
    
*/ ) );

function multilineStr (dummyFunc) 
    var str = dummyFunc.toString ();
    str     = str.replace (/^[^\/]+\/\*!?/, '') // Strip function ()  /*!
    .replace (/\s*\*\/\s*\\s*$/, '')   // Strip */ 
    .replace (/\/\/.+$/gm, '') // Double-slash comments wreck CSS. Strip them.
    ;
    return str;

console.log 语句显示了我目前发现的一些内容。但是我还没有弄清楚如何从它们中调用函数,或者它们中的哪些可能具有我正在寻找的东西(我认为主要是由于 javascript 压缩器使我难以遵循代码)。

【问题讨论】:

silverlight播放器控制见***.com/q/6086205/32453 截至 2017 年 9 月。这是唯一有效的答案。 ***.com/questions/42105028/… 【参考方案1】:

我认为这是我对这个问题思考得太深的一个例子。一旦我退后一步,我意识到我一直在寻找正确的方向,但没有正确触发点击事件。

因此,例如,要获得控制播放和暂停的“按钮”,您可以使用:document.getElementsByClassName("player-control-button player-play-pause")[0]。然后要在 tampermonkey 中以编程方式单击它,您只需使用以下命令调用 click 事件:

document.getElementsByClassName("player-control-button player-play-pause")[0].click();

栏中的音量和其他控件类似。播放位置看起来有点棘手,但我会做更多的挖掘并在我弄清楚后添加对此答案的评论。

【讨论】:

我将此标记为答案,因为它确实解决了原始问题。但是,我发现在 netflix 中操作视频播放的更好方法是引用 videoPlayer 对象本身。例如:var vp = netflix.cadmium.objects.videoPlayer(); vp.seek(60500); 您还可以使用此对象获得暂停、成交量、获取位置和持续时间等功能。 你用这个做了什么吗? @ChadMichael 看来netflix.cadmium 对象最近已被删除,不幸的是[?]【参考方案2】:

我知道这是一个较老的问题,但我想发布此答案以供未来用户使用。

您现在可以通过访问他们的播放器 API 来控制 Netflix 的播放,方法是执行以下 Javascript(最初由 Dmitry Paloskin 提供,this topic):

const videoPlayer = netflix.appContext.state.playerApp.getAPI().videoPlayer;

// Getting player id
const playerSessionId = videoPlayer.getAllPlayerSessionIds()[0];

const player = videoPlayer.getVideoPlayerBySessionId(playerSessionId);

然后,您可以使用 API 在 Netflix 播放器上执行各种命令,例如搜索(使用 player.seek() 括号中的毫秒数)、播放或暂停视频(使用 player.play() 或 @ 987654326@),或者控制音量(使用player.setVolume(),括号中的值,1代表100%,0代表0%)。

此方法避免了 Netflix 在尝试更改视频元素的 currentTime 属性时崩溃的问题,如上面来自 rogerdpack 的回复中所述。

【讨论】:

document.querySelector('video') 怎么样 不幸的是,截至 2021 年 12 月,仅使用 document.querySelector('video') 然后设置 currentTime 属性时,Netflix 仍然崩溃。这就是为什么视频搜索需要 Dmitry Paloskin 的解决方案。但是,您可以使用 document.querySelector('video') 更改某些视频元素属性,而不会导致 Netflix 崩溃,例如 muted 属性。感谢您的反馈,@AaronJ。【参考方案3】:

好消息是,您可以通过检测 HTML5 VIDEO 标签在一定程度上控制播放

前任:

https://gist.github.com/rdp/93c761b3524529e591e5286073545362find_html5_video.js

https://github.com/igrigorik/videospeed

然后像任何普通的HTMLMediaElement 对象(静音、暂停等)一样对其调用方法。

 video_element.paused = true // pause playback
 video_element.currentTime // get current timestamp

如果您在大多数网站(亚马逊即时视频、youtube)上使用此技巧,您可以使用video_element.currentTime = 3 进行搜索,它就可以正常工作。

但是,如果您使用 netflix 进行搜索,则会收到“糟糕,出了点问题... Unexpected Error 出现意外错误。请重新加载页面并重试。错误代码:M7375”

我还没有找到解决方法(尽管如果您的搜索只是“快进”一点,您可以减小视频大小,将播放速率设置为超高,然后将其降低到当它到达我想的所需位置时正常)。

所以我们需要找到一种不同的方式来发送 seek 命令。显然,曾经有一个 netflix.cadmium.objects.videoPlayer()netflix.player javascript 对象可用于 seek 方法,但它们现在似乎不存在。

回到你原来的问题,它似乎可以模仿控制位置的滑块上的“点击”,从而发送一条搜索消息,就像你尝试的那样。

Netflix Party(chrome 扩展,还有 chrome 扩展 `http://showgoers.tv/)做类似的事情,解释here。

一个令人心酸的部分似乎是

var showControls = function() 
  uiEventsHappening += 1;
  var scrubber = $('#scrubber-component');
  var eventOptions = 
    'bubbles': true,
    'button': 0,
    'currentTarget': scrubber[0]
  ;
  scrubber[0].dispatchEvent(new MouseEvent('mousemove', eventOptions));
  return delay(10)().then(function() 
    uiEventsHappening -= 1;
  );
;

var seek = function(milliseconds) 
  uiEventsHappening += 1;
  var eventOptions, scrubber;
  return showControls().then(function() 
    // compute the parameters for the mouse events
    scrubber = $('#scrubber-component');
    var factor = milliseconds / getDuration();
    var mouseX = scrubber.offset().left + Math.round(scrubber.width() * factor); // relative to the document
    var mouseY = scrubber.offset().top + scrubber.height() / 2;                  // relative to the document
    eventOptions = 
      'bubbles': true,
      'button': 0,
      'screenX': mouseX - $(window).scrollLeft(),
      'screenY': mouseY - $(window).scrollTop(),
      'clientX': mouseX - $(window).scrollLeft(),
      'clientY': mouseY - $(window).scrollTop(),
      'offsetX': mouseX - scrubber.offset().left,
      'offsetY': mouseY - scrubber.offset().top,
      'pageX': mouseX,
      'pageY': mouseY,
      'currentTarget': scrubber[0]
    ;

    // make the "trickplay preview" show up
    scrubber[0].dispatchEvent(new MouseEvent('mouseover', eventOptions));
  ).then(delay(10)).then(function() 
    // simulate a click on the scrubber
    scrubber[0].dispatchEvent(new MouseEvent('mousedown', eventOptions));
    scrubber[0].dispatchEvent(new MouseEvent('mouseup', eventOptions));
    scrubber[0].dispatchEvent(new MouseEvent('mouseout', eventOptions));
  ).then(delay(1)).then(hideControls).then(function() 
    uiEventsHappening -= 1;
  );
;

【讨论】:

以上是关于使用 Tampermonkey/javascript 控制 Netflix (HTML5) 播放的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)