您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
将 Bing 的重定向 url 转换为真实 url
- // ==UserScript==
- // @name Faster Bing
- // @name:en Faster Bing
- // @namespace CoderJiang
- // @version 1.1.4
- // @description 将 Bing 的重定向 url 转换为真实 url
- // @description:en Convert Bing's redirect url to a real url
- // @author CoderJiang
- // @match *://*.bing.com/*
- // @icon https://cdn.coderjiang.com/pic-go/2024/faster-bing-logo-v1.png!pure
- // @license MIT
- // @grant none
- // @note 2024-12-26 v1.1.4
- // - 功能:修复一些动态创建的链接(例如第一条人工智能生成的解答)无法解析的问题,同时解决在 v1.1.2 中无法解析的问题
- // @note 2024-07-19 v1.1.3
- // - 功能:对于 e.so.com/search/eclk 的链接,需要再次解析(示例:https://cn.bing.com/search?q=ui%E8%AE%BE%E8%AE%A1%E7%BD%91%E7%AB%99&first=1&FORM=PERE)
- // @note 2024-07-18 v1.1.2
- // - 修复:修复在 Edge 浏览器中第二次之后搜索无法解析的问题
- // - 功能:提供对 aclick 的中转链接解析支持
- // @note 2024-06-24 v1.1.1
- // - 修复:修复 Base64 解码问题,提升链接解析准确性。
- // - 优化:针对脚本运行两遍的问题,限制脚本在主页面上运行,无需在 iframes 再运行一次。
- // @note 2024-06-24 v1.1.0
- // - 优化:识别并处理站内相对 URL,确保这些 URL 被正确解析并转换为绝对形式。
- // - 优化:添加 LOGO
- // @noframes
- // ==/UserScript==
- (function () {
- 'use strict';
- const Config = {
- /**
- * 日志配置
- * log.enable 是否打印日志
- * log.success.icon 成功的图标
- * log.fail.icon 失败的图标
- * log.success.originalLink.maxLength 原始链接最大长度,如果为-1则不截断
- * log.success.originalLink.frontChars 原始链接前面保留的字符数
- * log.success.realLink.maxLength 真实链接最大长度,如果为-1则不截断
- * log.success.realLink.frontChars 真实链接前面保留的字符数
- * log.fail.originalLink.maxLength 原始链接最大长度,如果为-1则不截断
- * log.fail.originalLink.frontChars 原始链接前面保留的字符数
- * log.fail.realLink.display 失败时不显示真实链接,用这个字符串代替
- */
- log: {
- enable: true,
- success: {
- icon: '✅',
- originalLink: {
- maxLength: 30,
- frontChars: 10,
- },
- realLink: {
- maxLength: 30,
- frontChars: 20,
- }
- },
- fail: {
- icon: '❎',
- originalLink: {
- maxLength: -1,
- frontChars: 20,
- },
- realLink: {
- display: '------',
- }
- }
- }
- }
- const logo = `
- ________) ______
- (, / (, / ) ,
- /___, _ _ _/_ _ __ /---( __ _
- ) / (_(_/_)_(___(/_/ (_) / ____)_(_/ (_(_/_
- (_/ (_/ ( .-/
- (_/`;
- /**
- * 获取url中的参数
- *
- * @param url url
- * @param key 参数名
- * @returns {string} 参数值,如果没有则返回null
- */
- function getUrlParameter(url, key) {
- const parsedUrl = new URL(url);
- const queryParams = parsedUrl.searchParams;
- return queryParams.get(key);
- }
- /**
- * 判断是否是bing的重定向url
- *
- * @param url url
- * @returns {{valid: boolean, key: (string|null)}} 是否是bing的重定向url
- */
- function checkBingRedirectUrl(url) {
- const patterns = [
- // eg: https://www.bing.com/ck/a...
- {pattern: /^https?:\/\/(.*\.)?bing\.com\/(ck\/a|aclick)/, key: 'u'},
- // eg: https://e.so.com/search/eclk
- {pattern: /^https?:\/\/e\.so\.com\/search\/eclk/, key: 'aurl'},
- ];
- for (const {pattern, key} of patterns) {
- if (pattern.test(url)) {
- return {valid: true, key: key};
- }
- }
- return {valid: false, key: void 0};
- }
- /**
- * 判断url是否有效
- * @param urlString url字符串
- * @returns {boolean} 是否是有效的url
- */
- function isValidUrl(urlString) {
- try {
- new URL(urlString);
- return true; // 没有抛出异常,URL有效
- } catch (error) {
- return false; // 抛出异常,URL无效
- }
- }
- /**
- * 将重定向url转换为真实url
- * @param url Bing的重定向url,必须包含 key 指定的链接参数(eg: u)
- * @param key 参数名
- * @returns {string|null} 真实url,转换失败则返回null
- */
- function redirect2RealUrl(url, key) {
- let urlBase64 = getUrlParameter(url, key)
- urlBase64 = urlBase64.replace(/^a1/, '');
- let realUrl = ''
- try {
- // 还原Base64 URL编码中的特殊字符以便解码
- realUrl = atob(urlBase64.replace(/_/g, '/').replace(/-/g, '+'));
- } catch (error) {
- return null;
- }
- // 解码后的 URL 可能包含特殊字符,例如 http%3a%2f%2fpuaai.net
- realUrl = decodeURIComponent(realUrl);
- // 检查 realUrl 是否是有效的相对路径(以 '/' 开头)
- if (realUrl.startsWith('/')) {
- // 获取当前协议和域
- let currentUrl = window.location.origin; // e.g., "https://www.bing.com"
- // 将相对路径追加到当前 URL
- realUrl = currentUrl + realUrl;
- }
- if (!isValidUrl(realUrl)) {
- return null;
- }
- return realUrl;
- }
- /**
- * 找到所有的链接并转换为真实url
- * @returns {{failedUrls: *[], processedUrls: *[]}}
- */
- function convertBingRedirectUrls() {
- const failedUrls = [];
- const processedUrls = [];
- const links = document.querySelectorAll("a");
- for (const link of links) {
- const {realUrl, originalUrl} = convertBingRedirectUrl(link);
- if (realUrl) {
- processedUrls.push({
- realUrl,
- originalUrl
- });
- } else {
- failedUrls.push(originalUrl);
- }
- }
- return {
- processedUrls,
- failedUrls
- };
- }
- /**
- * 将bing的重定向url转换为真实url
- * @param aElement a标签元素
- * @returns {{realUrl: null, originalUrl: null}}
- */
- function convertBingRedirectUrl(aElement) {
- // v1.1.3: 对于 e.so.com/search/eclk 的链接,需要再次解析,因此使用递归解析
- const resolve = (href) => {
- const checkResult = checkBingRedirectUrl(href)
- if (!checkResult.valid) return href
- const realUrl = redirect2RealUrl(href, checkResult.key);
- return realUrl ? resolve(realUrl) : null;
- }
- const originalUrl = aElement.href;
- const checkResult = checkBingRedirectUrl(originalUrl)
- let realUrl = null;
- if (checkResult.valid) {
- realUrl = resolve(originalUrl);
- if (realUrl) {
- aElement.href = realUrl;
- }
- }
- return {realUrl, originalUrl}
- }
- /**
- * 可视化结果
- *
- * @param result 结果
- */
- function log(result) {
- function middleTruncate(str, maxLength, frontChars) {
- if (maxLength < 0) return str;
- if (str.length > maxLength) {
- const backChars = maxLength - frontChars - 3; // 确保总长度不超过maxLength
- return str.substring(0, frontChars) + '...' + str.substring(str.length - backChars);
- } else {
- return str;
- }
- }
- const overview = {
- "Success": result.processedUrls.length,
- "Failed": result.failedUrls.length,
- }
- const details = [];
- const successSample = {
- "Status": Config.log.success.icon,
- "Original": "",
- "Real": "",
- }
- const failedSample = {
- "Status": Config.log.fail.icon,
- "Original": "",
- "Real": Config.log.fail.realLink.display,
- }
- for (const processedUrl of result.processedUrls) {
- const success = {...successSample};
- success.Original = middleTruncate(
- processedUrl.originalUrl,
- Config.log.success.originalLink.maxLength,
- Config.log.success.originalLink.frontChars);
- success.Real = middleTruncate(
- processedUrl.realUrl,
- Config.log.success.realLink.maxLength,
- Config.log.success.realLink.frontChars);
- details.push(success);
- }
- for (const failedUrl of result.failedUrls) {
- const failed = {...failedSample};
- failed.Original = middleTruncate(failedUrl,
- Config.log.fail.originalLink.maxLength,
- Config.log.fail.originalLink.frontChars);
- details.push(failed);
- }
- console.table(overview);
- console.table(details);
- }
- console.log(logo);
- const result = convertBingRedirectUrls();
- if (Config.log.enable) {
- log(result)
- }
- // v1.1.3: 修复一些动态创建的链接无法解析的问题,同时解决在 v1.1.2 中无法解析的问题
- new MutationObserver((mutationsList) => {
- for (const mutation of mutationsList) {
- // 检测到新的 a 标签被添加
- if (mutation.type === 'childList') {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeType === 1) { // 元素节点
- // 如果是 a 标签
- if (node.tagName === 'A') {
- convertBingRedirectUrl(node);
- }
- // 如果子节点中包含 a 标签
- node.querySelectorAll?.('a').forEach((a) => {
- convertBingRedirectUrl(a);
- });
- }
- });
- }
- // 检测到 a 标签的 href 属性被修改
- if (mutation.type === 'attributes' && mutation.attributeName === 'href') {
- const target = mutation.target;
- if (target.tagName === 'A') {
- convertBingRedirectUrl(target);
- }
- }
- }
- }).observe(document.body, {
- childList: true, // 监听子节点的添加或删除
- subtree: true, // 监听所有后代节点
- attributes: true, // 监听属性变化
- attributeFilter: ['href'] // 仅监听 href 属性的变化
- });
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址