Added default bang selector & SearXNG

This commit is contained in:
Joshua Higgins
2025-07-02 23:50:22 -04:00
parent 91a66c25de
commit 5d88ebd457
8 changed files with 5606 additions and 16 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 yarn.lock* 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:alpine
# 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

@@ -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

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

View File

@@ -10,6 +10,24 @@ export const bangs = [
t: "t3", t: "t3",
u: "https://www.t3.chat/new?q={{{s}}}", u: "https://www.t3.chat/new?q={{{s}}}",
}, },
{
c: "AI",
d: "t3.chat",
r: 0,
s: "T3 Chat",
sc: "AI",
t: "ai",
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",
d: "www.01net.com", d: "www.01net.com",
@@ -3178,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";