您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds DuckDuckGo !bangs to Google search
// ==UserScript== // @name Duck Google // @namespace garcialnk.com // @license MIT // @version 1.0.1 // @description Adds DuckDuckGo !bangs to Google search // @author GarciaLnk // @match *://www.google.com/search* // @match *://google.com/search* // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @run-at document-start // @sandbox DOM // @tag utilities // @connect duckduckgo.com // ==/UserScript== /* jshint esversion: 11 */ (function () { "use strict"; /** * DuckDuckGo bang object * @typedef {Object} Bang * @property {string} s - The search engine name * @property {string} t - The bang command * @property {string} u - The search URL with {{{s}}} as the search query */ const CUSTOM_BANGS = [ { s: "T3 Chat", t: "t3", u: "https://www.t3.chat/new?q={{{s}}}", }, ]; const BANG_CACHE_KEY = "bangs-cache"; const BANG_CACHE_EXPIRY_KEY = "bangs-cache-expiry"; const CACHE_EXPIRY_MS = 1000 * 60 * 60 * 24 * 7; // 7 days /** * Fetches the DuckDuckGo bangs from the cache or the server * @returns {Promise<Bang[]>} The list of bangs */ function getBangs() { return new Promise((resolve) => { const cachedBangs = GM_getValue(BANG_CACHE_KEY); const cacheExpiry = GM_getValue(BANG_CACHE_EXPIRY_KEY, 0); if (cachedBangs && Date.now() < cacheExpiry) { resolve([...CUSTOM_BANGS, ...cachedBangs]); return; } GM_xmlhttpRequest({ method: "GET", url: "https://duckduckgo.com/bang.js", onload: function (response) { try { const bangs = JSON.parse(response.responseText); GM_setValue(BANG_CACHE_KEY, bangs); GM_setValue(BANG_CACHE_EXPIRY_KEY, Date.now() + CACHE_EXPIRY_MS); resolve([...CUSTOM_BANGS, ...bangs]); } catch (e) { console.error("Error parsing bangs:", e); resolve(CUSTOM_BANGS); } }, onerror: function () { console.error("Failed to fetch bangs"); resolve(CUSTOM_BANGS); }, }); }); } /** * Parses the bang from the query * @param {string} query The search query * @returns {{bang: string, cleanQuery: string} | null} The bang and the clean query */ function parseBang(query) { // regex to match !bang at start or end of query const match = query.match(/^!(\S+)\s+(.+)$|^(.+)\s+!(\S+)$/i); if (match) { if (match[1]) { // !bang query return { bang: match[1].toLowerCase(), cleanQuery: match[2].trim(), }; } else { // query !bang return { bang: match[4].toLowerCase(), cleanQuery: match[3].trim(), }; } } return null; } /** * Redirects to the search engine URL * @param {Bang[]} bangs The list of bangs * @returns {void} */ function redirectToBang(bangs) { const url = new URL(window.location.href); const query = url.searchParams.get("q")?.trim() ?? ""; if (!query) return; const bangData = parseBang(query); if (!bangData) return; const selectedBang = bangs.find((b) => b.t === bangData.bang); if (!selectedBang) return; // Format of the url is: // https://www.google.com/search?q={{{s}}} const searchUrl = selectedBang.u.replace( "{{{s}}}", // Replace %2F with / to fix formats like "!ghr+t3dotgg/unduck" encodeURIComponent(bangData.cleanQuery).replace(/%2F/g, "/"), ); if (searchUrl) { window.location.replace(searchUrl); } } /** * Initializes the script * @returns {void} */ async function init() { const bangs = await getBangs(); redirectToBang(bangs); } init(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址