🏠 Home 

Greasy Fork is available in English.

Bilibili AntiBV

自动在地址栏中将 bv 还原为 av,非重定向,不会导致页面刷新,顺便清除 search string 中所有无用参数


安装此脚本?
作者推荐脚本

您可能也喜欢Bilibili 哔哩哔哩视频点踩


安装此脚本
// ==UserScript==
// @name         Bilibili AntiBV
// @icon         https://www.bilibili.com/favicon.ico
// @namespace    https://moe.best/
// @version      1.9.6
// @description  自动在地址栏中将 bv 还原为 av,非重定向,不会导致页面刷新,顺便清除 search string 中所有无用参数
// @author       神代绮凛
// @include      /^https:\/\/www\.bilibili\.com\/(s\/)?video\/[BbAa][Vv]/
// @require      https://code.bdstatic.com/npm/[email protected]/src/simplequerystring.min.js
// @license      WTFPL
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==
(function () {
'use strict';
let REDIRECT_S_LINK = GM_getValue('redirect_s_link', true);
GM_registerMenuCommand('自动重定向 /s/video/xxx', () => {
REDIRECT_S_LINK = confirm(`自动将 /s/video/xxx 重定向至 /video/xxx
“确定”开启,“取消”关闭
当前:${REDIRECT_S_LINK ? '开启' : '关闭'}`);
GM_setValue('redirect_s_link', REDIRECT_S_LINK);
});
if (REDIRECT_S_LINK && location.pathname.startsWith('/s/video/')) {
location.pathname = location.pathname.replace(/^\/s/, '');
return;
}
const win = typeof unsafeWindow === 'undefined' ? window : unsafeWindow;
const last = arr => arr[arr.length - 1];
const wrapHistory = method => {
const fn = win.history[method];
const e = new Event(method);
return function () {
setTimeout(() => window.dispatchEvent(e));
return fn.apply(this, arguments);
};
};
win.history.pushState = wrapHistory('pushState');
win.history.replaceState = (() => {
const fn = win.history.replaceState;
return function (state, unused, url, isMe) {
if (isMe) return fn.apply(this, [state, unused, url]);
try {
state = { ...history.state, ...state };
const urlObj = new URL(url.startsWith('/') ? `${location.origin}${url}` : url);
urlObj.search = purgeSearchString(urlObj.search);
const bvid = getBvidFromUrl(urlObj.pathname);
if (bvid) urlObj.pathname = location.pathname;
url = urlObj.href.replace(urlObj.origin, '');
} catch (e) {
console.error(e);
}
return fn.apply(this, [state, unused, url]);
};
})();
const getBvidFromUrl = pathname => {
const lastPath = last(pathname.split('/').filter(v => v));
return /^bv/i.test(lastPath) ? lastPath : null;
};
const getUrl = id => `/video/${id}/${purgeSearchString(location.search)}${location.hash}`;
// https://github.com/mrhso/IshisashiWebsite/blob/master/%E4%B9%B1%E5%86%99%E7%A8%8B%E5%BC%8F/BV%20%E5%8F%B7%E8%B7%8B%E6%89%88%E3%80%80%EF%BD%9E%20Who%20done%20it!.js
const bv2av = (() => {
const charset = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';
const bvReg = new RegExp(`^[Bb][Vv]1[${charset}]{9}$`);
const base = BigInt(charset.length);
const table = {};
for (let i = 0; i < charset.length; i++) table[charset[i]] = i;
const xor = 23442827791579n;
const rangeLeft = 1n;
const rangeRight = 2n ** 51n;
/**
* @param {string} bv
*/
return bv => {
if (!bvReg.test(bv)) {
throw new Error(`Unexpected bv: ${bv}`);
}
const chars = bv.split('');
[chars[3], chars[9]] = [chars[9], chars[3]];
[chars[4], chars[7]] = [chars[7], chars[4]];
let r###lt = 0n;
for (let i = 3; i < 12; i++) {
r###lt = r###lt * base + BigInt(table[chars[i]]);
}
if (r###lt < rangeRight || r###lt >= rangeRight * 2n) {
throw new RangeError(`Unexpected av r###lt: ${r###lt}`);
}
r###lt = r###lt % rangeRight ^ xor;
if (r###lt < rangeLeft) {
throw new RangeError(`Unexpected av r###lt: ${r###lt}`);
}
return r###lt;
};
})();
const purgeSearchString = search => {
const { p, t } = simpleQueryString.parse(search);
const r###lt = simpleQueryString.stringify({ p, t });
return r###lt ? `?${r###lt}` : '';
};
const replaceUrl = () => {
const bvid = getBvidFromUrl(location.pathname);
const aid = bv2av(bvid);
if (!aid) return;
const avUrl = getUrl(`av${aid}`);
const BABKey = `BAB-${avUrl}`;
if (sessionStorage.getItem(BABKey)) {
console.warn('[Bilibili AntiBV] abort');
return;
}
sessionStorage.setItem(BABKey, 1);
setTimeout(() => sessionStorage.removeItem(BABKey), 1000);
history.replaceState({ ...history.state, aid, bvid }, '', avUrl, true);
};
const replaceBack = ({ state }) => {
const { aid, bvid } = state;
if (!bvid) return;
history.replaceState(state, '', getUrl(bvid), true);
setTimeout(() => history.replaceState(state, '', getUrl(`av${aid}`), true));
};
window.addEventListener('load', replaceUrl, { once: true });
window.addEventListener('pushState', replaceUrl);
window.addEventListener('popstate', replaceBack);
})();