Compare commits

..

7 Commits

12 changed files with 5624 additions and 3813 deletions

35
Dockerfile Normal file
View File

@@ -0,0 +1,35 @@
# Stage 1: Build the Vite application
FROM node:20-alpine as build
WORKDIR /app
# Copy package.json and package-lock.json (if present) to leverage Docker cache
COPY package.json package-lock.json* ./
# Install dependencies
RUN npm install
# Copy the rest of the application code
COPY . .
# Build the Vite application for production
# You might need to adjust 'npm run build' if your build script is different
RUN npm run build
# Stage 2: Serve the built application with Nginx
FROM nginx:latest
# Copy the built Vite application from the build stage to Nginx's web root
COPY --from=build /app/dist /usr/share/nginx/html
# Remove the default Nginx configuration file
RUN rm /etc/nginx/conf.d/default.conf
# Copy a custom Nginx configuration file (see example below)
COPY nginx.conf /etc/nginx/conf.d/nginx.conf
# Expose port 80 for web traffic
EXPOSE 80
# Start Nginx when the container launches
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2025 Theo Browne Copyright (c) 2025 Joshua Higgins
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -3,11 +3,13 @@
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. 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://unduck.abunchofknowitalls.com?q=%s
``` ```
## How is it that much faster? ## 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. 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. I solved this by doing all of the work client side. Once you've went to https://unduck.abunchofknowitalls.com once, the JS is all cache'd and will never need to be downloaded again. Your device does the redirects, not me.
Forked from Theo Browne's [Unduck](https://github.com/T3-Content/unduck)

7
docker-compose.yml Normal file
View File

@@ -0,0 +1,7 @@
services:
unduck:
container_name: unduck
ports:
- "4322:80"
restart: unless-stopped
image: git.abunchofknowitalls.com/joshuafhiggins/unduck:latest

View File

@@ -18,6 +18,12 @@
as="style" as="style"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
/> />
<link
rel="search"
type="application/opensearchdescription+xml"
title="Unduck"
href="/opensearch.xml"
/>
<link <link
rel="stylesheet" rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"

17
nginx.conf Normal file
View File

@@ -0,0 +1,17 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
# Optional: Cache control for assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff|woff2|ttf|svg|eot)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
}
}

5499
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

3789
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

13
public/opensearch.xml Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<ShortName>Unduck</ShortName>
<Description>A better default search engine (with bangs!)</Description>
<Tags>unduck bangs</Tags>
<Url rel="results" type="text/html" method="GET" template="https://unduck.abunchofknowitalls.com/?q={searchTerms}"/>
<Url rel="suggestions" type="application/x-suggestions+json" template="https://unduck.abunchofknowitalls.com/autocompleter?q={searchTerms}"/>
<Url rel="self" type="application/opensearchdescription+xml" method="GET" template="https://unduck.abunchofknowitalls.com/opensearch.xml" />
<Image height="16" width="16" type="image/svg+xml">https://unduck.abunchofknowitalls.com/search.svg</Image>
<InputEncoding>UTF-8</InputEncoding>
<OutputEncoding>UTF-8</OutputEncoding>
<Query role="example" searchTerms="cats !g"/>
</OpenSearchDescription>

View File

@@ -11,13 +11,22 @@ export const bangs = [
u: "https://www.t3.chat/new?q={{{s}}}", u: "https://www.t3.chat/new?q={{{s}}}",
}, },
{ {
c: "Tech", c: "AI",
d: "npmx", d: "t3.chat",
r: 147, r: 0,
s: "npmx", s: "T3 Chat",
sc: "Programming", sc: "AI",
t: "npmx", t: "ai",
u: "https://npmx.dev/search?q={{{s}}}", u: "https://t3.chat/new?model=gemini-2.5-flash&q={{{s}}}",
},
{
c: "SearXNG",
d: "search.abunchofknowitalls.com",
r: 0,
s: "PrivSearch",
sc: "SearXNG",
t: "xng",
u: "https://search.abunchofknowitalls.com/?q={{{s}}}",
}, },
{ {
c: "Tech", c: "Tech",
@@ -3187,15 +3196,6 @@ export const bangs = [
t: "aitopics", t: "aitopics",
u: "https://aitopics.org/search?q={{{s}}}", u: "https://aitopics.org/search?q={{{s}}}",
}, },
{
c: "Research",
d: "www.duckduckgo.com",
r: 8351,
s: "Duck.ai",
sc: "Reference",
t: "ai",
u: "https://www.duckduckgo.com/?q={{{s}}}&ia=chat&bang=true ",
},
{ {
c: "News", c: "News",
d: "america.aljazeera.com", d: "america.aljazeera.com",

View File

@@ -182,6 +182,15 @@ textarea {
color: #fff; color: #fff;
} }
.default-bang {
border-color: #3d3d3d;
background-color: #191919;
color: #fff;
min-width: 100px;
padding: 8px 12px;
border-radius: 4px;
}
.copy-button img { .copy-button img {
filter: invert(1); filter: invert(1);
} }

View File

@@ -12,20 +12,26 @@ function noSearchDefaultPageRender() {
<input <input
type="text" type="text"
class="url-input" class="url-input"
value="https://unduck.link?q=%s" value="https://unduck.abunchofknowitalls.com?q=%s"
readonly readonly
/> />
<button class="copy-button"> <button class="copy-button">
<img src="/clipboard.svg" alt="Copy" /> <img src="/clipboard.svg" alt="Copy" />
</button> </button>
</div> </div>
<div style="display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 1rem; margin-top: 1rem;">
<p>Set Default Bang: </p>
<select name="default-bang" id="default-bang" class="default-bang">
<option value="g">Google</option>
<option value="ai">T3 Chat</option>
<option value="xng">SearXNG</option>
</select>
</div>
</div> </div>
<footer class="footer"> <footer class="footer">
<a href="https://t3.chat" target="_blank">t3.chat</a> <a href="https://joshuafhiggins.github.io" target="_blank">Joshua Higgins</a>
<a href="https://x.com/theo" target="_blank">theo</a> <a href="https://git.abunchofknowitalls.com/joshuafhiggins/unduck" target="_blank">Git</a>
<a href="https://github.com/t3dotgg/unduck" target="_blank">github</a>
</footer> </footer>
</div> </div>
`; `;
@@ -33,6 +39,7 @@ function noSearchDefaultPageRender() {
const copyButton = app.querySelector<HTMLButtonElement>(".copy-button")!; const copyButton = app.querySelector<HTMLButtonElement>(".copy-button")!;
const copyIcon = copyButton.querySelector("img")!; const copyIcon = copyButton.querySelector("img")!;
const urlInput = app.querySelector<HTMLInputElement>(".url-input")!; const urlInput = app.querySelector<HTMLInputElement>(".url-input")!;
const defaultBangSelect = app.querySelector<HTMLSelectElement>(".default-bang")!;
copyButton.addEventListener("click", async () => { copyButton.addEventListener("click", async () => {
await navigator.clipboard.writeText(urlInput.value); await navigator.clipboard.writeText(urlInput.value);
@@ -42,6 +49,11 @@ function noSearchDefaultPageRender() {
copyIcon.src = "/clipboard.svg"; copyIcon.src = "/clipboard.svg";
}, 2000); }, 2000);
}); });
defaultBangSelect.addEventListener("change", () => {
localStorage.setItem("default-bang", defaultBangSelect.value);
console.log("test");
});
} }
const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? "g"; const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? "g";