// ==UserScript== // @name 【哔哩哔哩】屏蔽视频PCDN地址 // @namespace http://tampermonkey.net/ // @version 0.1.2 // @description 从官方CDN加载视频 // @author AkagiYui // @license MIT // @icon https://static.hdslb.com/images/favicon.ico // @match https://www.bilibili.com/video/* // @match https://www.bilibili.com/list/* // @match https://www.bilibili.com/bangumi/play/* // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @downloadURL none // ==/UserScript== /******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; (function () { "use strict"; // 获取配置 function getConfig(key) { return GM_getValue(key, booleanConfigs[key].defaultValue); } // 配置注册 var menuIds = []; function registerMenuCommand() { menuIds.forEach(function (id) { GM_unregisterMenuCommand(id); }); menuIds = []; Object.entries(booleanConfigs).forEach(function (_a) { var key = _a[0], config = _a[1]; var commandName = getConfig(key) ? "✅" : "❌"; commandName += " ".concat(config.title); var id = GM_registerMenuCommand(commandName, function () { var newValue = !getConfig(key); var valueToSet = config.callback ? config.callback(newValue) : newValue; GM_setValue(key, valueToSet); registerMenuCommand(); }); menuIds.push(id); }); } // 配置项 var booleanConfigs = { blockPlayError: { title: "屏蔽“播放遇到问题?”提示", defaultValue: false, }, }; registerMenuCommand(); var pageWindow = unsafeWindow; var filterBackupUrls = function (mediaArray) { mediaArray.forEach(function (media) { var filteredUrls = media.backupUrl.filter(function (url) { return !url.includes("mcdn.bilivideo.cn"); }); if (filteredUrls.length > 0) { media.backupUrl = filteredUrls; media.backup_url = filteredUrls; media.baseUrl = filteredUrls[0]; media.base_url = filteredUrls[0]; } else { console.log("\u6CA1\u6709\u53EF\u7528\u7684\u975Epcdn url"); } }); }; var replaceUrl = function (data) { var dash = data; var video = dash.video; var audio = dash.audio; filterBackupUrls(video); filterBackupUrls(audio); return dash; }; // 普通BV号视频页面,修改播放器初始化参数 var originalConnectPlayerFunction = pageWindow.connectPlayer; Object.defineProperty(pageWindow, "connectPlayer", { get: function () { return originalConnectPlayerFunction; }, set: function (value) { originalConnectPlayerFunction = value; pageWindow.__playinfo__.data.dash = replaceUrl(pageWindow.__playinfo__.data.dash); }, }); // 播放列表页面 var originalXHR = pageWindow.XMLHttpRequest; // 方法一,重写XMLHttpRequest构造函数,会发生错误 // function ModifiedXHR() { // const xhrInstance = new originalXHR() // const originalOpen = xhrInstance.open // xhrInstance.open = function (_: any, url: string) { // if (url.includes('api.bilibili.com/x/player/wbi/playurl')) { // this.addEventListener('readystatechange', function () { // if (this.readyState === 4 && this.status === 200) { // let responseJson = JSON.parse(this.responseText) // responseJson.data.dash = replaceUrl(responseJson.data.dash) // let modifiedResponse = JSON.stringify(responseJson) // Object.defineProperty(this, 'responseText', { value: modifiedResponse }) // } // }) // } // return originalOpen.apply(this, arguments) // } // return xhrInstance // } // pageWindow.XMLHttpRequest = ModifiedXHR as unknown as typeof XMLHttpRequest // 方法二,修改responseText的getter var xhrOpen = originalXHR.prototype.open; originalXHR.prototype.open = function (_, url) { var xhr = this; if (url.includes("api.bilibili.com/x/player/wbi/playurl")) { var getter_1 = Object.getOwnPropertyDescriptor(originalXHR.prototype, "responseText").get; Object.defineProperty(xhr, "responseText", { get: function () { var response = getter_1.call(xhr); var responseJson = JSON.parse(response); responseJson.data.dash = replaceUrl(responseJson.data.dash); var modifiedResponse = JSON.stringify(responseJson); return modifiedResponse; }, }); } return xhrOpen.apply(xhr, arguments); }; // 屏蔽“播放遇到问题?”提示 if (getConfig("blockPlayError")) { var originalDefineProperty_1 = pageWindow.Object.defineProperty; pageWindow.Object.defineProperty = function (target, propertyKey, descriptor) { if (propertyKey === "videoHasBuffered") { originalDefineProperty_1(target, "showLoadTimeoutFeedback", { get: function () { return function () { }; }, set: function () { pageWindow.Object.defineProperty = originalDefineProperty_1; }, }); } return originalDefineProperty_1(target, propertyKey, descriptor); }; } })(); /******/ })() ;