使用 Tampermonkey/javascript 控制 Netflix (HTML5) 播放
Controlling Netflix (HTML5) playback with Tampermonkey/javascript
在 Netflix 网站上观看 Netflix 视频时,我的目标是让用户脚本以编程方式调用播放控件。具体来说,视频的音量、电平、play/pause状态、时间位置。
我已经能够操纵 html5 视频元素本身,但直接控制它不会向用户提供所需的 netflix 控制栏反馈。 (即视频已暂停,但控制栏仍显示为正在播放)。
到目前为止,我的方法是尝试找到代表您在使用普通控件时单击的 "buttons" 的元素,并通过用户脚本触发它们的单击事件。但我似乎无法分离出适当的元素。此外,netflix 使用 javascript compressor/obfuscator 这增加了找到代表控制栏上按钮的适当元素的难度。
在这样的网站上,如何识别接收元素点击事件的元素,然后创建用户脚本以通过 tampermonkey and/or 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 压缩器让我很难理解代码)。
我认为这是我对问题思考过度的一个案例。一旦我退后一步,我意识到我一直在寻找正确的方向,但没有正确触发点击事件。
因此,例如,要获得控制播放和暂停的 "button",您可以使用:document.getElementsByClassName("player-control-button player-play-pause")[0]
。然后在 tampermonkey 中以编程方式单击它,您只需使用以下命令调用单击事件:
document.getElementsByClassName("player-control-button player-play-pause")[0].click();
栏中的音量和其他控件类似。播放位置看起来有点棘手,但我会做更多的挖掘并在我弄清楚后对此答案添加评论。
好吧,好消息是您可以通过检测 HTML5 VIDEO 标签
在某种程度上控制播放
前任:
https://gist.github.com/rdp/93c761b3524529e591e5286073545362 find_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 一样搜索,你会得到 "Whoops, something went wrong... Unexpected Error There was an unexpected error. Please reload the page and try again. Error Code: M7375"
而且我还没有想出解决办法(尽管如果你的搜索只是 "fast forward" 一点,你可以减小视频大小,将播放速率设置为超高,然后把它当它到达我想的所需位置时恢复正常。
所以我们需要找到一种不同的方式来发送搜索命令。显然在某一时刻有一个 netflix.cadmium.objects.videoPlayer()
或 netflix.player
javascript 对象可用于搜索方法,但它们现在似乎不存在。
所以回到你最初的问题,似乎可以模仿控制位置的滑块上的 "click",从而发送一条搜索消息,就像你尝试的那样。
Netflix Party
(chrome 扩展名,还有 chrome 扩展名`http://showgoers.tv/) does something either like it, explained 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;
});
};
我知道这是一个较旧的问题,但我想 post 这个答案是为了未来用户的利益。
您现在可以通过访问他们的播放器 API 来控制 Netflix 的播放,方法是执行以下 Javascript(最初由 Dmitry Paloskin, on 贡献):
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()
或 player.pause()
),或控制音量(通过使用 player.setVolume()
和括号中的值,1 表示 100%,0 表示 0%)。
此方法避免了尝试更改视频元素 currentTime
属性 时 Netflix 崩溃的问题,如上面 rogerdpack 的回复所述。
在 Netflix 网站上观看 Netflix 视频时,我的目标是让用户脚本以编程方式调用播放控件。具体来说,视频的音量、电平、play/pause状态、时间位置。
我已经能够操纵 html5 视频元素本身,但直接控制它不会向用户提供所需的 netflix 控制栏反馈。 (即视频已暂停,但控制栏仍显示为正在播放)。
到目前为止,我的方法是尝试找到代表您在使用普通控件时单击的 "buttons" 的元素,并通过用户脚本触发它们的单击事件。但我似乎无法分离出适当的元素。此外,netflix 使用 javascript compressor/obfuscator 这增加了找到代表控制栏上按钮的适当元素的难度。
在这样的网站上,如何识别接收元素点击事件的元素,然后创建用户脚本以通过 tampermonkey and/or 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 压缩器让我很难理解代码)。
我认为这是我对问题思考过度的一个案例。一旦我退后一步,我意识到我一直在寻找正确的方向,但没有正确触发点击事件。
因此,例如,要获得控制播放和暂停的 "button",您可以使用:document.getElementsByClassName("player-control-button player-play-pause")[0]
。然后在 tampermonkey 中以编程方式单击它,您只需使用以下命令调用单击事件:
document.getElementsByClassName("player-control-button player-play-pause")[0].click();
栏中的音量和其他控件类似。播放位置看起来有点棘手,但我会做更多的挖掘并在我弄清楚后对此答案添加评论。
好吧,好消息是您可以通过检测 HTML5 VIDEO 标签
在某种程度上控制播放前任:
https://gist.github.com/rdp/93c761b3524529e591e5286073545362 find_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 一样搜索,你会得到 "Whoops, something went wrong... Unexpected Error There was an unexpected error. Please reload the page and try again. Error Code: M7375"
而且我还没有想出解决办法(尽管如果你的搜索只是 "fast forward" 一点,你可以减小视频大小,将播放速率设置为超高,然后把它当它到达我想的所需位置时恢复正常。
所以我们需要找到一种不同的方式来发送搜索命令。显然在某一时刻有一个 netflix.cadmium.objects.videoPlayer()
或 netflix.player
javascript 对象可用于搜索方法,但它们现在似乎不存在。
所以回到你最初的问题,似乎可以模仿控制位置的滑块上的 "click",从而发送一条搜索消息,就像你尝试的那样。
Netflix Party
(chrome 扩展名,还有 chrome 扩展名`http://showgoers.tv/) does something either like it, explained 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;
});
};
我知道这是一个较旧的问题,但我想 post 这个答案是为了未来用户的利益。
您现在可以通过访问他们的播放器 API 来控制 Netflix 的播放,方法是执行以下 Javascript(最初由 Dmitry Paloskin, on
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()
或 player.pause()
),或控制音量(通过使用 player.setVolume()
和括号中的值,1 表示 100%,0 表示 0%)。
此方法避免了尝试更改视频元素 currentTime
属性 时 Netflix 崩溃的问题,如上面 rogerdpack 的回复所述。