!bangAnywhere

Use DuckDuckGo !bangs (almost) anywhere

// ==UserScript==
// @name        !bangAnywhere
// @namespace   https://github.com/RuiNtD
// @version     1.1.2
// @description Use DuckDuckGo !bangs (almost) anywhere
// @author      RuiNtD
// @match       https://*.google.com/search?*
// @match       https://*.bing.com/search?*
// @match       https://search.brave.com/search?*
// @match       https://*.qwant.com/?*
// @match       https://*.startpage.com/*/search*
// @noframes    
// @homepageURL https://greasyfork.org/scripts/469625
// @icon        https://icons.duckduckgo.com/ip2/duckduckgo.com.ico
// @require     https://cdn.jsdelivr.net/npm/@violentmonkey/url@0
// @resource    bangs https://duckduckgo.com/bang.js
// @license     MIT
// @grant       GM_getResourceText
// ==/UserScript==

(function (url) {
'use strict';

// Only load bangs into memory when needed
let bangs = null;
function preloadBangs() {
  if (bangs) return;
  bangs = JSON.parse(GM_getResourceText("bangs"));
}

// Modified from https://github.com/t3dotgg/unduck
function getBangUrl(query) {
  const match = query.match(/!(\S+)/i);
  const bangTag = match?.[1]?.toLowerCase();
  if (!bangTag) return;
  preloadBangs();
  const bang = bangs.find(b => b.t == bangTag);
  if (!bang) return null;
  const cleanQuery = query.replace(/!\S+\s*/i, "").trim();
  if (!cleanQuery) return `https://${bang.d}`;
  return bang.u.replace("{{{s}}}", encodeURIComponent(cleanQuery));
}
function checkQuery() {
  const url = new URL(window.location.href);
  const params = url.searchParams;
  const qInput = document.querySelector("input#q");
  const query = (params.get("q") || params.get("query") || qInput?.value || "").trim();
  if (!query) return;
  console.log("!bangAnywhere Query:", query);
  const bangUrl = getBangUrl(query);
  console.log("!bangAnywhere Redirect:", bangUrl);
  if (bangUrl) window.location.replace(bangUrl);
}
url.onNavigate(checkQuery);
checkQuery();

})(VM);