// ==UserScript==
// @name Netflix Plus
// @name:ja Netflix Plus
// @name:zh-CN Netflix Plus
// @name:zh-TW Netflix Plus
// @namespace http://tampermonkey.net/
// @version 1.15
// @description Enable best audio and video and more features on Netflix
// @description:ja Netflixで最高の音質と画質、そしてもっと多くの機能を体験しましょう
// @description:zh-CN 在 Netflix 上开启最佳音视频质量和更多功能
// @description:zh-TW 在 Netflix 上啓用最佳影音品質和更多功能
// @author TGSAN
// @match https://www.netflix.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=netflix.com
// @run-at document-start
// @grant unsafeWindow
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// ==/UserScript==
(async () => {
"use strict";
let windowCtx = self.window;
if (self.unsafeWindow) {
console.log("[Netflix Plus] use unsafeWindow mode");
windowCtx = self.unsafeWindow;
} else {
console.log("[Netflix Plus] use window mode (your userscript extensions not support unsafeWindow)");
}
const Event = class {
constructor(script, target) {
this.script = script;
this.target = target;
this._cancel = false;
this._replace = null;
this._stop = false;
}
preventDefault() {
this._cancel = true;
}
stopPropagation() {
this._stop = true;
}
replacePayload(payload) {
this._replace = payload;
}
};
let callbacks = [];
windowCtx.addBeforeScriptExecuteListener = (f) => {
if (typeof f !== "function") {
throw new Error("Event handler must be a function.");
}
callbacks.push(f);
};
windowCtx.removeBeforeScriptExecuteListener = (f) => {
let i = callbacks.length;
while (i--) {
if (callbacks[i] === f) {
callbacks.splice(i, 1);
}
}
};
const dispatch = (script, target) => {
if (script.tagName !== "SCRIPT") {
return;
}
const e = new Event(script, target);
if (typeof windowCtx.onbeforescriptexecute === "function") {
try {
windowCtx.onbeforescriptexecute(e);
} catch (err) {
console.error(err);
}
}
for (const func of callbacks) {
if (e._stop) {
break;
}
try {
func(e);
} catch (err) {
console.error(err);
}
}
if (e._cancel) {
script.textContent = "";
script.remove();
} else if (typeof e._replace === "string") {
script.textContent = e._replace;
}
};
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
for (const n of m.addedNodes) {
dispatch(n, m.target);
}
}
});
observer.observe(document, {
childList: true,
subtree: true,
});
const menuItems = [
["setMaxBitrate", "Automatically select best bitrate available"],
["useallSub", "Show all audio-tracks and subs"],
["closeimsc", "Use SUP subtitle replace IMSC subtitle"],
["useDDPandHA", "Enable Dolby and HE-AAC 5.1 Audio"],
["useFHDAndAVCH", "Focus 1080P and High-AVC"],
];
let menuCommandList = [];
windowCtx.globalOptions = {
useFHDAndAVCH: !checkAdvancedDrm(),
useDDPandHA: true,
setMaxBitrate: true,
useallSub: true,
get ["useddplus"]() {
return windowCtx.globalOptions.useDDPandHA;
},
useAVC: false,
get ["useFHD"]() {
return windowCtx.globalOptions.useFHDAndAVCH;
},
usedef: false,
get ["useHA"]() {
return windowCtx.globalOptions.useDDPandHA;
},
get ["useAVCH"]() {
return windowCtx.globalOptions.useFHDAndAVCH;
},
usevp9: false,
useav1: false,
useprk: true,
usehevc: false,
usef4k: true,
usef12k: false,
closeimsc: true
};
windowCtx.onbeforescriptexecute = function (e) {
let scripts = document.getElementsByTagName("script");
if (scripts.length === 0) return;
for (let i = 0; scripts.length > i; i++) {
let dom = scripts[i];
if (dom.src.includes("cadmium-playercore")) {
let playercore = document.createElement('script');
playercore.src = "https://static-os.kumo.moe/js/netflix/cadmium-playercore.js";
playercore.crossOrigin = dom.crossOrigin;
playercore.async = dom.async;
playercore.id = dom.id;
document.head.appendChild(playercore);
dom.remove();
windowCtx.onbeforescriptexecute = null;
break;
}
}
};
async function checkAdvancedDrm() {
let supported = false;
if (windowCtx.MSMediaKeys) {
supported = true;
}
if (windowCtx.WebKitMediaKeys) {
supported = true;
}
// Check L1
let options = [
{
"videoCapabilities": [
{
"contentType": "video/mp4;codecs=avc1.42E01E",
"robustness": "HW_SECURE_ALL"
}
]
}
];
try {
await navigator.requestMediaKeySystemAccess("com.widevine.alpha.experiment", options);
supported = true;
} catch {}
console.log("Supported advanced DRM: " + supported);
return supported;
}
function checkSelected(type) {
let selected = GM_getValue("NETFLIX_PLUS_" + type);
if (typeof selected == "boolean") {
return selected;
} else {
return windowCtx.globalOptions[type];
}
}
function registerSelectableVideoProcessingMenuCommand(name, type) {
let selected = checkSelected(type);
windowCtx.globalOptions[type] = selected;
return GM_registerMenuCommand((checkSelected(type) ? "✅" : "🔲") + " " + name, function() {
GM_setValue("NETFLIX_PLUS_" + type, !selected);
windowCtx.globalOptions[type] = !selected;
updateMenuCommand();
});
}
async function updateMenuCommand() {
for (let command of menuCommandList) {
await GM_unregisterMenuCommand(command);
}
menuCommandList = [];
for (let menuItem of menuItems) {
menuCommandList.push(await registerSelectableVideoProcessingMenuCommand(menuItem[1], menuItem[0]));
}
}
updateMenuCommand();
})();