Compare commits
10 Commits
6efab00e75
...
991fd13184
Author | SHA1 | Date | |
---|---|---|---|
991fd13184 | |||
3032a81915 | |||
|
cea48a6584 | ||
|
f96ce5706d | ||
|
5cf34e3467 | ||
|
34f64869c0 | ||
|
b9763e2124 | ||
|
001e48129b | ||
|
3165c3dccb | ||
|
0b569d2b86 |
@ -1,13 +1,15 @@
|
||||
# Unduck
|
||||
# Bang
|
||||
|
||||
*This is a fork of [unduck](https://unduck.link) by [Theo](https://github.com/t3dotgg/unduck).*
|
||||
|
||||
DuckDuckGo's bang redirects are too slow. Add the following URL as a custom search engine to your browser. Enables all of DuckDuckGo's bangs to work, but much faster.
|
||||
|
||||
```
|
||||
https://unduck.link?q=%s
|
||||
https://bang.gbrown.org?q=%s
|
||||
```
|
||||
|
||||
## How is it that much faster?
|
||||
|
||||
DuckDuckGo does their redirects server side. Their DNS is...not always great. Result is that it often takes ages.
|
||||
|
||||
I solved this by doing all of the work client side. Once you've went to https://unduck.link once, the JS is all cache'd and will never need to be downloaded again. Your device does the redirects, not me.
|
||||
Theo solved this by doing all of the work client side. Once you've went to https://unduck.link once, the JS is all cache'd and will never need to be downloaded again. Your device does the redirects, not me.
|
||||
|
@ -11,5 +11,14 @@
|
||||
"devDependencies": {
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^6.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"vite-plugin-pwa": "^0.21.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b",
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"esbuild"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
3237
pnpm-lock.yaml
generated
3237
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
29
src/bang.ts
29
src/bang.ts
@ -1,6 +1,15 @@
|
||||
// This file was (mostly) ripped from https://duckduckgo.com/bang.js
|
||||
|
||||
export const bangs = [
|
||||
{
|
||||
c: "Online Services",
|
||||
d: "search.gibbyb.com",
|
||||
r: 0,
|
||||
s: "GibbyB",
|
||||
sc: "Search",
|
||||
t: "sg",
|
||||
u: "https://search.gibbyb.com/?q={{{s}}}",
|
||||
},
|
||||
{
|
||||
c: "AI",
|
||||
d: "www.t3.chat",
|
||||
@ -10,24 +19,6 @@ export const bangs = [
|
||||
t: "t3",
|
||||
u: "https://www.t3.chat/new?q={{{s}}}",
|
||||
},
|
||||
{
|
||||
c: "Tech",
|
||||
d: "www.01net.com",
|
||||
r: 4,
|
||||
s: "01net",
|
||||
sc: "Downloads (apps)",
|
||||
t: "01net",
|
||||
u: "http://www.01net.com/recherche/recherche.php?searchstring={{{s}}}&chaine=home",
|
||||
},
|
||||
{
|
||||
c: "Entertainment",
|
||||
d: "www.bmw2002faq.com",
|
||||
r: 0,
|
||||
s: "BMW 2002 FAQ",
|
||||
sc: "Forum",
|
||||
t: "02faq",
|
||||
u: "https://www.bmw2002faq.com/search/?q={{{s}}}",
|
||||
},
|
||||
{
|
||||
c: "Entertainment",
|
||||
d: "boxofficemojo.com",
|
||||
@ -93872,7 +93863,7 @@ export const bangs = [
|
||||
r: 46,
|
||||
s: "Sourcegraph",
|
||||
sc: "Programming",
|
||||
t: "sg",
|
||||
t: "srcg",
|
||||
u: "https://sourcegraph.com/search?q={{{s}}}",
|
||||
},
|
||||
{
|
||||
|
@ -89,6 +89,7 @@ textarea {
|
||||
.content-container {
|
||||
max-width: 36rem;
|
||||
text-align: center;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
/* Update url-input width to be 100% since container will control max width */
|
||||
@ -98,6 +99,7 @@ textarea {
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
background: #f5f5f5;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
|
26
src/main.ts
26
src/main.ts
@ -1,20 +1,17 @@
|
||||
import { bangs } from "./bang";
|
||||
import "./global.css";
|
||||
|
||||
const defaultBang = bangs.find((b) => b.t === "g");
|
||||
|
||||
function noSearchDefaultPageRender() {
|
||||
const app = document.querySelector<HTMLDivElement>("#app")!;
|
||||
app.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh;">
|
||||
<div class="content-container">
|
||||
<h1>Unduck</h1>
|
||||
<p>DuckDuckGo's bang redirects are too slow. Add the following URL as a custom search engine to your browser. Enables <a href="https://duckduckgo.com/bang.html" target="_blank">all of DuckDuckGo's bangs.</a></p>
|
||||
<h1>Bang</h1>
|
||||
<div class="url-container">
|
||||
<input
|
||||
type="text"
|
||||
class="url-input"
|
||||
value="https://unduck.link?q=%s"
|
||||
value="bang.gbrown.org?q=%s"
|
||||
readonly
|
||||
/>
|
||||
<button class="copy-button">
|
||||
@ -22,13 +19,6 @@ function noSearchDefaultPageRender() {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<a href="https://t3.chat" target="_blank">t3.chat</a>
|
||||
•
|
||||
<a href="https://x.com/theo" target="_blank">theo</a>
|
||||
•
|
||||
<a href="https://github.com/t3dotgg/unduck" target="_blank">github</a>
|
||||
</footer>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -37,7 +27,7 @@ function noSearchDefaultPageRender() {
|
||||
const urlInput = app.querySelector<HTMLInputElement>(".url-input")!;
|
||||
|
||||
copyButton.addEventListener("click", async () => {
|
||||
await navigator.clipboard.writeText(urlInput.value);
|
||||
await navigator.clipboard.writeText("https://" + urlInput.value);
|
||||
copyIcon.src = "/clipboard-check.svg";
|
||||
|
||||
setTimeout(() => {
|
||||
@ -46,6 +36,9 @@ function noSearchDefaultPageRender() {
|
||||
});
|
||||
}
|
||||
|
||||
const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? "sg";
|
||||
const defaultBang = bangs.find((b) => b.t === LS_DEFAULT_BANG);
|
||||
|
||||
function getBangredirectUrl() {
|
||||
const url = new URL(window.location.href);
|
||||
const query = url.searchParams.get("q")?.trim() ?? "";
|
||||
@ -54,19 +47,20 @@ function getBangredirectUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
const match = query.match(/!([a-z0-9]+)/i);
|
||||
const match = query.match(/!(\S+)/i);
|
||||
|
||||
const bangCandidate = match?.[1]?.toLowerCase();
|
||||
const selectedBang = bangs.find((b) => b.t === bangCandidate) ?? defaultBang;
|
||||
|
||||
// Remove the first bang from the query
|
||||
const cleanQuery = query.replace(/![a-z0-9]+\s*/i, "").trim();
|
||||
const cleanQuery = query.replace(/!\S+\s*/i, "").trim();
|
||||
|
||||
// Format of the url is:
|
||||
// https://www.google.com/search?q={{{s}}}
|
||||
const searchUrl = selectedBang?.u.replace(
|
||||
"{{{s}}}",
|
||||
encodeURIComponent(cleanQuery)
|
||||
// Replace %2F with / to fix formats like "!ghr+t3dotgg/unduck"
|
||||
encodeURIComponent(cleanQuery).replace(/%2F/g, "/")
|
||||
);
|
||||
if (!searchUrl) return null;
|
||||
|
||||
|
10
vite.config.ts
Normal file
10
vite.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
VitePWA({
|
||||
registerType: "autoUpdate",
|
||||
}),
|
||||
],
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user