Netflix UHD

让 Netflix 在任何分辨率的显示器上播放 UHD 内容

安装此脚本
作者推荐脚本

您可能也喜欢Netflix Plus

安装此脚本
  1. // ==UserScript==
  2. // @name Netflix UHD
  3. // @name:zh-CN Netflix UHD
  4. // @name:zh-TW Netflix UHD
  5. // @name:ja Netflix UHD
  6. // @namespace http://tampermonkey.net/
  7. // @version 1.26
  8. // @description Play Netflix UHD content on any screen resolution
  9. // @description:zh-CN 让 Netflix 在任何分辨率的显示器上播放 UHD 内容
  10. // @description:zh-TW 讓 Netflix 在任何解析度的顯示器上播放 UHD 內容
  11. // @description:ja Netflix をあらゆる解像度のディスプレイで UHD コンテンツを再生できるようにする方法です
  12. // @author TGSAN
  13. // @match https://www.netflix.com/*
  14. // @icon https://www.google.com/s2/favicons?sz=64&domain=netflix.com
  15. // @run-at document-start
  16. // @grant unsafeWindow
  17. // @grant GM_registerMenuCommand
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. // 'use strict';
  22.  
  23. const forceDolbyVision = false;
  24. const forceHEVC = false;
  25. const forceUHD = false;
  26. const forceHDCP = false;
  27. const forceALL = false;
  28.  
  29. let useWindowCtx
  30.  
  31. if (self.unsafeWindow) {
  32. console.log("use unsafeWindow mode");
  33. useWindowCtx = self.unsafeWindow;
  34. } else {
  35. console.log("use window mode");
  36. useWindowCtx = self.window;
  37. }
  38.  
  39. // Hook
  40.  
  41. delete useWindowCtx.screen;
  42. useWindowCtx.__defineGetter__('screen', function () {
  43. let s = [];
  44. s.width = 7680;
  45. s.height = 4320;
  46. s.availWidth = 7680;
  47. s.availHeight = 4320;
  48. s.availLeft = 0;
  49. s.availTop = 0;
  50. s.colorDepth = 32;
  51. s.isExtended = false;
  52. s.pixelDepth = 32;
  53. return s;
  54. });
  55. delete useWindowCtx.devicePixelRatio;
  56. useWindowCtx.devicePixelRatio = 4;
  57.  
  58. // useWindowCtx.MSMediaKeysOriginal = useWindowCtx.MSMediaKeys;
  59. // useWindowCtx.MSMediaKeys = {
  60. // isTypeSupportedWithFeatures: function() { return "probably" },
  61. // isTypeSupported: function() { return true },
  62. // };
  63.  
  64. if (useWindowCtx.MSMediaKeys) {
  65. useWindowCtx.MSMediaKeys.isTypeSupportedWithFeaturesOriginal = useWindowCtx.MSMediaKeys.isTypeSupportedWithFeatures;
  66. useWindowCtx.MSMediaKeys.isTypeSupportedWithFeatures = function (keySystem, targetMediaCodec) {
  67. const reg = /,display-res-[x|y]=\d+,display-res-[x|y]=\d+/
  68. targetMediaCodec = targetMediaCodec.replace(reg, "");
  69. if (forceDolbyVision == true && (targetMediaCodec.indexOf("ext-profile=dvh") !== -1)) {
  70. keySystem = keySystem.replace("com.microsoft.playready.hardware", "com.microsoft.playready");
  71. }
  72. if (forceHEVC == true && targetMediaCodec.indexOf("ext-profile=dvh") === -1 && (targetMediaCodec.indexOf("hvc1") !== -1 || targetMediaCodec.indexOf("hev1") !== -1)) {
  73. keySystem = keySystem.replace("com.microsoft.playready.hardware", "com.microsoft.playready");
  74. }
  75. if (forceHDCP == true && targetMediaCodec.indexOf("hdcp=") !== -1) {
  76. targetMediaCodec = targetMediaCodec.replace("hdcp=1,", "");
  77. targetMediaCodec = targetMediaCodec.replace("hdcp=1", "");
  78. targetMediaCodec = targetMediaCodec.replace("hdcp=2,", "");
  79. targetMediaCodec = targetMediaCodec.replace("hdcp=2", "");
  80. }
  81. if (forceUHD == true && targetMediaCodec.indexOf("decode-res-") !== -1) {
  82. targetMediaCodec = targetMediaCodec.replace("decode-res-x=3840,", "");
  83. targetMediaCodec = targetMediaCodec.replace("decode-res-x=3840", "");
  84. targetMediaCodec = targetMediaCodec.replace("decode-res-y=2160,", "");
  85. targetMediaCodec = targetMediaCodec.replace("decode-res-y=2160", "");
  86. }
  87. let r = this.isTypeSupportedWithFeaturesOriginal(keySystem, targetMediaCodec);
  88. // if (r !== '') {
  89. // console.log("Hook MSMediaKeys isTypeSupportedWithFeatures:", keySystem, targetMediaCodec, r !== '');
  90. // } else {
  91. // console.debug("Hook MSMediaKeys isTypeSupportedWithFeatures:", keySystem, targetMediaCodec, r !== '');
  92. // }
  93. if (forceALL) {
  94. return "probably";
  95. }
  96. return r;
  97. }
  98. useWindowCtx.MSMediaKeys.isTypeSupportedOriginal = useWindowCtx.MSMediaKeys.isTypeSupported;
  99. useWindowCtx.MSMediaKeys.isTypeSupported = function (keySystem) {
  100. keySystem = keySystem.replace("com.microsoft.playready.hardware", "com.microsoft.playready");
  101. let r = this.isTypeSupportedOriginal(keySystem);
  102. // if (r !== '') {
  103. // console.log("Hook MSMediaKeys isTypeSupportedWithFeatures:", keySystem, targetMediaCodec, r !== '');
  104. // } else {
  105. // console.debug("Hook MSMediaKeys isTypeSupportedWithFeatures:", keySystem, targetMediaCodec, r !== '');
  106. // }
  107. return r;
  108. }
  109. useWindowCtx.MSMediaKeys.prototype.createSessionOriginal = useWindowCtx.MSMediaKeys.prototype.createSession;
  110. useWindowCtx.MSMediaKeys.prototype.createSession = function (targetMediaCodec, emptyArrayofInitData, int8ArrayCDMdata) {
  111. console.log(targetMediaCodec, emptyArrayofInitData, int8ArrayCDMdata);
  112. const reg = /,display-res-[x|y]=\d+,display-res-[x|y]=\d+/
  113. targetMediaCodec = targetMediaCodec.replace(reg, "");
  114. if (forceHDCP == true && targetMediaCodec.indexOf("hdcp=") !== -1) {
  115. targetMediaCodec = targetMediaCodec.replace("hdcp=1,", "");
  116. targetMediaCodec = targetMediaCodec.replace("hdcp=1", "");
  117. targetMediaCodec = targetMediaCodec.replace("hdcp=2,", "");
  118. targetMediaCodec = targetMediaCodec.replace("hdcp=2", "");
  119. }
  120. if (forceUHD == true && targetMediaCodec.indexOf("decode-res-") !== -1) {
  121. targetMediaCodec = targetMediaCodec.replace("decode-res-x=3840,", "");
  122. targetMediaCodec = targetMediaCodec.replace("decode-res-x=3840", "");
  123. targetMediaCodec = targetMediaCodec.replace("decode-res-y=2160,", "");
  124. targetMediaCodec = targetMediaCodec.replace("decode-res-y=2160", "");
  125. }
  126. return this.createSessionOriginal(targetMediaCodec, emptyArrayofInitData, int8ArrayCDMdata);
  127. }
  128. }
  129.  
  130. if (useWindowCtx.WebKitMediaKeys) {
  131. useWindowCtx.WebKitMediaKeys.isTypeSupportedOriginal = useWindowCtx.WebKitMediaKeys.isTypeSupported;
  132. useWindowCtx.WebKitMediaKeys.isTypeSupported = function (keySystem, type) {
  133. let r = this.isTypeSupportedOriginal(keySystem, type);
  134. console.log("Hook WebKitMediaKeys", keySystem, type, r);
  135. return r;
  136. }
  137. }
  138.  
  139. if (useWindowCtx.navigator.requestMediaKeySystemAccess) {
  140. useWindowCtx.navigator.requestMediaKeySystemAccessOriginal = useWindowCtx.navigator.requestMediaKeySystemAccess;
  141. useWindowCtx.navigator.requestMediaKeySystemAccess = async function (keySystem, options) {
  142. let newKeySystem = keySystem;
  143. if (keySystem.indexOf("playready") !== -1) {
  144. try {
  145. let r = await useWindowCtx.navigator.requestMediaKeySystemAccessOriginal(newKeySystem, options);
  146. return r;
  147. } catch(e) {
  148. console.warn("Fallback PlayReady to SL");
  149. newKeySystem = "com.microsoft.playready";
  150. }
  151. }
  152. for (let oi = 0; options.length > oi; oi++) {
  153. if (options[oi].videoCapabilities != undefined) {
  154. for (let vci = 0; options[oi].videoCapabilities.length > vci; vci++) {
  155. if (options[oi].videoCapabilities[vci].robustness != undefined) {
  156. // options[oi].videoCapabilities[vci].robustness = options[oi].videoCapabilities[vci].robustness.replace("HW_SECURE", "SW_SECURE");
  157. }
  158. }
  159. }
  160. }
  161. let r = await useWindowCtx.navigator.requestMediaKeySystemAccessOriginal(newKeySystem, options);
  162. // console.log(options);
  163. // console.log(r);
  164. return r;
  165. }
  166. }
  167.  
  168. // useWindowCtx.MediaKeys.prototype.getStatusForPolicyOriginal = useWindowCtx.MediaKeys.prototype.getStatusForPolicy;
  169. // useWindowCtx.MediaKeys.prototype.getStatusForPolicy = function(policy) {
  170. // let r = this.getStatusForPolicy(policy);
  171. // console.log(r, policy);
  172. // return r;
  173. // }
  174.  
  175. // WIP: Firefox not support
  176. // if (useWindowCtx.MediaSource) {
  177. // useWindowCtx.MediaSource.isTypeSupportedOriginal = useWindowCtx.MediaSource.isTypeSupported;
  178. // useWindowCtx.MediaSource.isTypeSupported = function (mimeType) {
  179. // let r = this.isTypeSupportedOriginal(mimeType);
  180. // console.log("Hook MSE", mimeType, r);
  181. // return r;
  182. // }
  183. // }
  184.  
  185. if (useWindowCtx.MediaCapabilities.prototype) {
  186. useWindowCtx.MediaCapabilities.prototype.decodingInfoOriginal = useWindowCtx.MediaCapabilities.prototype.decodingInfo;
  187. useWindowCtx.MediaCapabilities.prototype.decodingInfo = function (mediaDecodingConfiguration) {
  188. let r = this.decodingInfoOriginal(mediaDecodingConfiguration);
  189. // console.log("MC", mediaDecodingConfiguration, r);
  190. let p = new Promise((res, rej) => {
  191. r.then(orir => {
  192. // console.log("orir", orir);
  193. orir.powerEfficient = orir.supported;
  194. orir.smooth = orir.supported;
  195. // console.log("orir edited", orir);
  196. res(orir);
  197. }).catch(ex => {
  198. rej(ex);
  199. });
  200. });
  201. return p;
  202. }
  203. }
  204.  
  205. // Ext
  206. let checkHDCPAsync = async function () {
  207. if (self.GM_registerMenuCommand && window.MSMediaKeys) {
  208. // HW
  209. let hwhdcp0 = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; features="hdcp=0"') != '';
  210. let hwhdcp0hevc = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; codecs="hev1,mp4a"; features="hdcp=0"') != '';
  211. let hwhdcp1 = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; features="hdcp=1"') != '';
  212. let hwhdcp1hevc = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; codecs="hev1,mp4a"; features="hdcp=1"') != '';
  213. let hwhdcp2 = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; features="hdcp=2"') != '';
  214. let hwhdcp2hevc = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; codecs="hev1,mp4a"; features="hdcp=2"') != '';
  215. let hwhdcp2hevc2160p = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.hardware", 'video/mp4; codecs="hev1,mp4a"; features="decode-res-x=3840,decode-res-y=2160,decode-bpc=10,hdcp=2"') != '';
  216. // SW
  217. let swhdcp0 = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; features="hdcp=0"') != '';
  218. let swhdcp0hevc = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; codecs="hev1,mp4a"; features="hdcp=0"') != '';
  219. let swhdcp1 = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; features="hdcp=1"') != '';
  220. let swhdcp1hevc = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; codecs="hev1,mp4a"; features="hdcp=1"') != '';
  221. let swhdcp2 = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; features="hdcp=2"') != '';
  222. let swhdcp2hevc = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; codecs="hev1,mp4a"; features="hdcp=2"') != '';
  223. let swhdcp2hevc2160p = window.MSMediaKeys.isTypeSupportedWithFeaturesOriginal("com.microsoft.playready.software", 'video/mp4; codecs="hev1,mp4a"; features="decode-res-x=3840,decode-res-y=2160,decode-bpc=10,hdcp=2"') != '';
  224. let bool2Status = function (booltype) {
  225. return booltype ? "✓" : "✕";
  226. };
  227. GM_registerMenuCommand("PlayReady DRM Info (" + (hwhdcp2hevc2160p ? "UHD Ready" : "Restricted") + ")", function () {
  228. // DHCP0
  229. let content = "PlayReady DRM (without HDCP 2.2):\n";
  230. content += "Hardware: " + bool2Status(hwhdcp0) + " Software: " + bool2Status(swhdcp0) + "\n\n";
  231. // DHCP0 + HEVC
  232. content += "PlayReady DRM (without HDCP 2.2) with HEVC:\n";
  233. content += "Hardware: " + bool2Status(hwhdcp0hevc) + " Software: " + bool2Status(swhdcp0hevc) + "\n\n";
  234. // DHCP1
  235. content += "PlayReady DRM (HDCP 2.2):\n";
  236. content += "Hardware: " + bool2Status(hwhdcp1) + " Software: " + bool2Status(swhdcp1) + "\n\n";
  237. // DHCP1 + HEVC
  238. content += "PlayReady DRM (HDCP 2.2) with HEVC:\n";
  239. content += "Hardware: " + bool2Status(hwhdcp1hevc) + " Software: " + bool2Status(swhdcp1hevc) + "\n\n";
  240. // DHCP2
  241. content += "PlayReady DRM (HDCP 2.2 Type 1):\n";
  242. content += "Hardware: " + bool2Status(hwhdcp2) + " Software: " + bool2Status(swhdcp2) + "\n\n";
  243. // DHCP2 + HEVC
  244. content += "PlayReady DRM (HDCP 2.2 Type 1) with HEVC:\n";
  245. content += "Hardware: " + bool2Status(hwhdcp2hevc) + " Software: " + bool2Status(swhdcp2hevc) + "\n\n";
  246. // DHCP2 + HEVC 2160P
  247. content += "PlayReady DRM (HDCP 2.2 Type 1) with HEVC UHD:\n";
  248. content += "Hardware: " + bool2Status(hwhdcp2hevc2160p) + " Software: " + bool2Status(swhdcp2hevc2160p) + "\n\n";
  249. // Display DRM Info
  250. alert(content);
  251. });
  252. }
  253. };
  254. checkHDCPAsync();
  255.  
  256. let switchPlayerLog = function () {
  257. console.log("switch player log");
  258.  
  259. useWindowCtx.dispatchEvent(new KeyboardEvent('keydown', {
  260. keyCode: 76,
  261. ctrlKey: true,
  262. altKey: true,
  263. shiftKey: true,
  264. }));
  265. }
  266.  
  267. let loadLocalSubtitle = function () {
  268. console.log("load local subtitle");
  269.  
  270. useWindowCtx.dispatchEvent(new KeyboardEvent('keydown', {
  271. keyCode: 84,
  272. ctrlKey: true,
  273. altKey: true,
  274. shiftKey: true,
  275. }));
  276. }
  277.  
  278. let switchPlayerInfo = function () {
  279. console.log("switch player info");
  280.  
  281. useWindowCtx.dispatchEvent(new KeyboardEvent('keydown', {
  282. keyCode: 68,
  283. ctrlKey: true,
  284. altKey: true,
  285. shiftKey: true,
  286. }));
  287. }
  288.  
  289. let switchStreamSelector = function () {
  290. console.log("switch player info");
  291.  
  292. useWindowCtx.dispatchEvent(new KeyboardEvent('keydown', {
  293. keyCode: 83, // S (Old)
  294. ctrlKey: true,
  295. altKey: true,
  296. shiftKey: true,
  297. }));
  298.  
  299. useWindowCtx.dispatchEvent(new KeyboardEvent('keydown', {
  300. keyCode: 66, // B
  301. ctrlKey: true,
  302. altKey: true,
  303. shiftKey: true,
  304. }));
  305. }
  306.  
  307. GM_registerMenuCommand("Player Info", switchPlayerInfo);
  308. GM_registerMenuCommand("Stream Selector", switchStreamSelector);
  309. GM_registerMenuCommand("Player Log", switchPlayerLog);
  310. GM_registerMenuCommand("Load Local Subtitle (.DFXP)", loadLocalSubtitle);
  311. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址