您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在 Netflix 上开启最佳音视频质量和更多功能
当前为
- // ==UserScript==
- // @name Netflix Plus
- // @name:ja Netflix Plus
- // @name:zh-CN Netflix Plus
- // @name:zh-TW Netflix Plus
- // @namespace http://tampermonkey.net/
- // @version 2.4
- // @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)");
- }
- // Register Netflix Plus Functions
- windowCtx._videoElementNetflixPlus;
- Object.defineProperty(windowCtx, "videoElementNetflixPlus", {
- get: function () { return windowCtx._videoElementNetflixPlus; },
- set: function (element) {
- let backup = windowCtx._videoElementNetflixPlus;
- windowCtx._videoElementNetflixPlus = element;
- element.addEventListener('playing', function () {
- if (backup === element) {
- return;
- }
- if (!windowCtx.globalOptions.setMaxBitrate) {
- return;
- }
- let getElementByXPath = function (xpath) {
- return document.evaluate(
- xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
- ).singleNodeValue;
- };
- let selectFun = function () {
- windowCtx.dispatchEvent(new KeyboardEvent('keydown', {
- keyCode: 83, // S (Old)
- ctrlKey: true,
- altKey: true,
- shiftKey: true,
- }));
- windowCtx.dispatchEvent(new KeyboardEvent('keydown', {
- keyCode: 66, // B
- ctrlKey: true,
- altKey: true,
- shiftKey: true,
- }));
- const VIDEO_SELECT = getElementByXPath("//div[text()='Video Bitrate / VMAF']");
- const AUDIO_SELECT = getElementByXPath("//div[text()='Audio Bitrate']");
- const BUTTON = getElementByXPath("//button[text()='Override']");
- if (VIDEO_SELECT && AUDIO_SELECT && BUTTON) {
- [VIDEO_SELECT, AUDIO_SELECT].forEach(function (el) {
- let parent = el.parentElement;
- let selects = parent.querySelectorAll('select');
- selects.forEach(function (select) {
- select.removeAttribute("disabled");
- });
- let options = parent.querySelectorAll('select > option');
- for (var i = 0; i < options.length - 1; i++) {
- options[i].removeAttribute('selected');
- }
- options[options.length - 1].setAttribute('selected', 'selected');
- });
- BUTTON.click();
- backup = element;
- } else {
- setTimeout(selectFun, 100);
- }
- }
- selectFun();
- });
- }
- });
- windowCtx.modifyFilterNetflixPlus = function (ModList, ModConfig, DRMType) {
- let DrmVersion = "playready" === DRMType ? 30 : 0;
- if (windowCtx.globalOptions.useprk) {
- ModList.push("h264mpl30-dash-playready-prk-qc");
- ModList.push("h264mpl31-dash-playready-prk-qc");
- ModList.push("h264mpl40-dash-playready-prk-qc");
- }
- if (DrmVersion == 30) {
- if (windowCtx.globalOptions.useddplus) {
- ModList.push("ddplus-2.0-dash");
- ModList.push("ddplus-5.1-dash");
- ModList.push("ddplus-5.1hq-dash");
- ModList.push("ddplus-atmos-dash");
- // ModList = ModList.filter(item => { if (!new RegExp(/heaac/g).test(JSON.stringify(item))) return item; });
- }
- if (windowCtx.globalOptions.usehevc) {
- ModList = ModList.filter(item => { if (!new RegExp(/main10-L5/g).test(JSON.stringify(item))) return item; });
- }
- if (windowCtx.globalOptions.usef12k) {
- ModList = ModList.filter(item => { if (!new RegExp(/hevc-main10-L.*-dash-cenc-prk-do/g).test(JSON.stringify(item))) return item; });
- }
- if (windowCtx.globalOptions.usef4k) {
- ModList.push("hevc-main10-L30-dash-cenc");
- ModList.push("hevc-main10-L31-dash-cenc");
- ModList.push("hevc-main10-L40-dash-cenc");
- ModList.push("hevc-main10-L41-dash-cenc");
- }
- } else {
- if (windowCtx.globalOptions.useFHD) {
- ModList.push("playready-h264mpl40-dash");
- ModList.push("playready-h264hpl40-dash");
- ModList.push("vp9-profile0-L40-dash-cenc");
- ModList.push("av1-main-L50-dash-cbcs-prk");
- ModList.push("av1-main-L51-dash-cbcs-prk");
- }
- if (windowCtx.globalOptions.useHA) {
- ModList.push("heaac-5.1-dash");
- }
- if (!windowCtx.globalOptions.usedef) {
- if (windowCtx.globalOptions.useav1) {
- ModList.push("av1-main-L20-dash-cbcs-prk");
- ModList.push("av1-main-L21-dash-cbcs-prk");
- ModList = ModList.filter(item => { if (!new RegExp(/h264/g).test(JSON.stringify(item))) return item; });
- ModList = ModList.filter(item => { if (!new RegExp(/vp9-profile/g).test(JSON.stringify(item))) return item; });
- }
- if (windowCtx.globalOptions.usevp9) {
- ModList.push("vp9-profile0-L21-dash-cenc");
- ModList = ModList.filter(item => { if (!new RegExp(/h264/g).test(JSON.stringify(item))) return item; });
- ModList = ModList.filter(item => { if (!new RegExp(/av1-main/g).test(JSON.stringify(item))) return item; });
- }
- if (windowCtx.globalOptions.useAVCH) {
- ModList = ModList.filter(item => { if (!new RegExp(/vp9-profile/g).test(JSON.stringify(item))) return item; });
- ModList = ModList.filter(item => { if (!new RegExp(/h264mp/g).test(JSON.stringify(item))) return item; });
- ModList = ModList.filter(item => { if (!new RegExp(/av1-main/g).test(JSON.stringify(item))) return item; });
- }
- if (windowCtx.globalOptions.useAVC) {
- ModList = ModList.filter(item => { if (!new RegExp(/vp9-profile/g).test(JSON.stringify(item))) return item; });
- ModList = ModList.filter(item => { if (!new RegExp(/h264hp/g).test(JSON.stringify(item))) return item; });
- ModList = ModList.filter(item => { if (!new RegExp(/av1-main/g).test(JSON.stringify(item))) return item; });
- }
- }
- }
- if (windowCtx.globalOptions.useallSub) {
- ModConfig.showAllSubDubTracks = 1
- }
- if (windowCtx.globalOptions.closeimsc) {
- ModList = ModList.filter(item => { if (!new RegExp(/imsc1.1/g).test(JSON.stringify(item))) return item; });
- }
- return [ModList, ModConfig, DRMType];
- };
- // Main Logic
- 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")) {
- // firefox cannot reload src after change src url
- // dom.src = "https://static-os.kumo.moe/js/netflix/cadmium-playercore.js";
- 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;
- dom.replaceWith(playercore);
- 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();
- })();