// ==UserScript== // @name AlwaysBing // @namespace AlwaysBing // @version 1.0.0 // @description Always search with Bing // @description:en Always search with Bing // @description:zh-CN 永远使用 Bing 搜索 // @description:zh-TW 永遠使用 Bing 搜索 // @icon https://cn.bing.com/favicon.ico // @author lingbopro // @homepage https://github.com/lingbopro/AlwaysBing // @license MIT // @match *://*.bing.com/* // @match *://*.baidu.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @grant GM_log // @grant window.location // @noframes // ==/UserScript== (function () { 'use strict'; /* * AlwaysBing * 这是一个开源的用户脚本 * 遵循 MIT 协议 * GitHub 存储库: https://github.com/lingbopro/AlwaysBing * GreasyFork: https://greasyfork.org/zh-CN/scripts/496648 * 贡献代码前,先用 Prettier 格式化啊~ */ //SECTION - 配置 / CONFIG /* * -------------------- * 这里是配置内容。 * 如果你要修改配置,请在这里修改。 * PS: 不要删JSDoc啊 * -------------------- */ /** * 规则列表 * @type {array} */ let rules = [ // TODO: 完善规则 { name: '百度', // 名称 matches: [ // 子规则 { type: 'search', // 类型(用来匹配下方的Bing URL) url: 'baidu.com/s', // URL匹配 query: 'wd', // 包含搜索内容的参数名称 }, { type: 'image', url: 'image.baidu.com/search', query: 'word', }, { type: 'video', url: 'baidu.com/sf/vsearch', query: 'wd', }, ], }, ]; /** * 必应的 URL * @type {object} */ let bing = { search: 'https://bing.com/search?q=', image: 'https://bing.com/images/search?q=', video: 'https://bing.com/videos/search?q=', }; /** * 读取的配置 * @type {object} */ let config = { rules: [ // 每项分别对应规则的对应项 { action: 'redirect', }, ], }; //!SECTION //SECTION - 逻辑 / LOGIC /* * -------------------- * 这里是核心逻辑。 * 如果你要修改配置,就别动这。 * 注释不太多,将就看吧:D * :) * -------------------- */ let modal_open = false; // 防止叠弹窗 /** * 读取配置 */ let readConfig = function () { GM_log(`AlwaysBing: read config`); config = GM_getValue('config', config); // 读取配置 config.rules.forEach((value, index) => { // 将配置写到规则表中 rules[index].action = value.action; }); GM_log(`AlwaysBing: config:\n${JSON.stringify(config)}`); }; /** * 写入配置 */ let writeConfig = function () { GM_log(`AlwaysBing: write config`); rules.forEach((value, index) => { // 将配置从规则表再写回到配置表 config.rules[index].action = value.action; }); GM_setValue('config', config); // 写入配置 }; /** * 上下文菜单回调 * @param {number} index */ let menuCallback = function (index) { GM_log(`AlwaysBing: menu callback: ${index}`); let rule = rules[index]; switch (rule.action) { case 'redirect': rule.action = 'modal'; break; case 'modal': rule.action = 'modal_closeable'; break; case 'modal_closeable': rule.action = 'nothing'; break; case 'nothing': rule.action = 'redirect'; break; default: break; } rules[index] = rule; writeConfig(); refreshMenu(); }; /** * 刷新上下文菜单 */ let refreshMenu = function () { GM_log(`AlwaysBing: refresh menu`); rules.forEach((value, index) => { let text = ''; switch (value.action) { case 'redirect': text = '🔗重定向'; break; case 'modal': text = '💬提示'; break; case 'modal_closeable': text = '💬提示(可关闭)'; break; case 'nothing': text = '❌什么也不做'; break; default: break; } GM_registerMenuCommand( `🔍${value.name}: ${text}`, function () { menuCallback(index); }, { id: 'menu-' + index, autoClose: false, title: `🔍规则: ${value.name}\n▶动作: ${text}`, } ); }); }; /** * 处理和匹配规则 */ let process = function () { GM_log(`AlwaysBing: process`); rules.forEach((value, index) => { // 遍历规则 let currentRule = value; GM_log(`AlwaysBing: process rule ${value.name}`); value.matches.forEach((value, index) => { // 遍历子规则 if (window.location.href.includes(value.url)) { // URL匹配 GM_log(`AlwaysBing: URL matches rule ${currentRule.name}`); let searchParams = new URLSearchParams( window.location.search ); let query = searchParams.get(value.query); // 获取参数 let url = bing[value.type] + query; // 对应的必应URL switch (currentRule.action) { case 'redirect': window.location.href = url; break; case 'modal': showModal(url, false); break; case 'modal_closeable': showModal(url, true); break; case 'nothing': break; default: break; } } }); }); }; /** * 显示提示窗 * @param {string} url 跳转的URL * @param {boolean} closeable 是否可关闭 */ let showModal = function (url, closeable) { if (modal_open) { return; } modal_open = true; GM_log( `AlwaysBing: show modal\n(url: ${url}\n closeable: ${closeable})` ); let modalEl = document.createElement('div'); modalEl.id = 'alwaysbing-modal-wrapper'; // 样式 GM_addStyle(` #alwaysbing-modal-wrapper { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: #00000060; -webkit-user-select: none; user-select: none; z-index: 1145; /* 故意不小心的 */ } #alwaysbing-modal { position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; padding: 10px 8px; width: -moz-fit-content; height: -moz-fit-content; width: fit-content; height: fit-content; max-width: 30%; max-height: 50%; border-radius: 10px; display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: #ffffff; text-align: center; } /* Bing 暗色主题 */ /* 好像没啥用... */ .b_dark .alwaysbing-modal { background-color: #1b1a19; color: #ffffff; } .b_dark .alwaysbing-modal * { color: #ffffff; } #alwaysbing-modal>* { padding: 10px; margin: 15px; } #alwaysbing-modal>.close-btn { text-align: right; align-self: flex-end; width: 20px; height: 20px; cursor: pointer; } #alwaysbing-modal>.img-wrapper { margin: 10px; padding: 10px; } #alwaysbing-modal>.img-wrapper>.img { display: block; width: 60px; height: 60px; text-align: center; } #alwaysbing-modal>.tit { font-size: large; font-weight: bold; } #alwaysbing-modal>.btn { padding: 18px; background-color: #35adfd; color: #ffffff; border-radius: 10px; cursor: pointer; } #alwaysbing-modal>.btn:hover { background-color: #7ec9fc; } `); // HTML modalEl.innerHTML = `