Compare commits
19 Commits
8f77173b8b
...
main
Author | SHA1 | Date | |
---|---|---|---|
5032672341 | |||
eec2d36526 | |||
3f3c0d72f8 | |||
f6b6639905 | |||
3781ae935d | |||
ede223d9d5 | |||
dc1fa6d08a | |||
7df4b38d09 | |||
7644c2c810 | |||
b5e740a5c2 | |||
48a526f404 | |||
94a7880db3 | |||
6f336b18d3 | |||
1451ab0ef1 | |||
b35f479def | |||
740ef0f748 | |||
5d6e12c308 | |||
c75f426065 | |||
69239287b2 |
26
.env.example
Normal file
26
.env.example
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# All environment variables must be prefixed with VITE_ to be seen by client.
|
||||||
|
|
||||||
|
# Self-hosted Services URLs. Do not include the trailing slash.
|
||||||
|
VITE_BANG_URL="https://bang."
|
||||||
|
VITE_GITEA_URL="https://git."
|
||||||
|
VITE_SEARXNG_URL="https://search."
|
||||||
|
VITE_OPENWEBUI_URL="https://chat."
|
||||||
|
VITE_NEXTCLOUD_URL="https://apps.cloud."
|
||||||
|
VITE_PLEX_URL="https://plex."
|
||||||
|
VITE_OVERSEERR_URL="https://overseerr."
|
||||||
|
VITE_SONARR_URL="https://sonarr."
|
||||||
|
VITE_RADARR_URL="https://radarr."
|
||||||
|
VITE_LIDARR_URL="https://lidarr."
|
||||||
|
|
||||||
|
# Set default bang here. For example "g" would be Google.
|
||||||
|
# Google is the default if you don't set this.
|
||||||
|
# 's' is for your searxng instance, replacing startpage
|
||||||
|
VITE_DEFAULT_BANG="s"
|
||||||
|
|
||||||
|
# SPECIFIC MODELS FOR OPENWEBUI
|
||||||
|
# Local
|
||||||
|
VITE_LLAMA_MODEL="llama3.1" # !llama
|
||||||
|
VITE_DEEPSEEK_MODEL="deepseek-r1:8b" # !r1
|
||||||
|
# Remote
|
||||||
|
VITE_OPENAI_MODEL="gpt-4o-mini" # !openai
|
||||||
|
VITE_CLAUDE_MODEL="anthropic/claude-3.5-sonnet" # !claude
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -6,6 +6,7 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
public/opensearch.xml
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
@ -22,3 +23,10 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# ENV
|
||||||
|
docker/.env
|
||||||
|
!docker/.env.example
|
||||||
|
.env
|
||||||
|
.env*
|
||||||
|
!.env.example
|
||||||
|
41
README.md
41
README.md
@ -1,14 +1,43 @@
|
|||||||
# Bang
|
# 💣Bang
|
||||||
|
|
||||||
*This is a fork of [unduck](https://unduck.link) by [Theo](https://github.com/t3dotgg/unduck).*
|
*This is a fork of [unduck](https://unduck.link) by [Theo](https://github.com/t3dotgg/unduck).*
|
||||||
|
|
||||||
|
## Why fork?
|
||||||
|
|
||||||
|
This fork allows anyone to easily self host this service & add bangs for their own self-hosted websites. Bang comes pre-configured to work with
|
||||||
|
|
||||||
|
- Searxng *!s*
|
||||||
|
- Gitea *!tea*
|
||||||
|
- OpenWebUI *!ai*
|
||||||
|
- Plex *!plex*
|
||||||
|
- Sonarr *!tv*
|
||||||
|
- Radarr *!mv*
|
||||||
|
- Lidarr *!mp3*
|
||||||
|
- ~Overseerr *!ov*~ *Overseerr doesn't seem to work correctly*
|
||||||
|
|
||||||
|
*Note: We have replaced some of the default bangs from duckduckgo with our own bangs in order to have more simple bangs for the self-hosted websites.*
|
||||||
|
|
||||||
|
All you have to do is fill out the environment variables in the .env.example files located in the root directory & the docker directory & rename them to .env.
|
||||||
|
|
||||||
|
You can also easily add your own bangs by adding a new entry in the bangs.ts file.
|
||||||
|
|
||||||
|
## How to self host
|
||||||
|
|
||||||
|
1. Clone the repo & fill out the .env.example files in the root directory & the docker directory & rename them to .env.
|
||||||
|
- *Note: Our docker compose assumes you plan to select an external network.*
|
||||||
|
2. Run the bash script `host-bang` in the docker directory with the root directory of the project as an argument.
|
||||||
|
- *Note: You can also simply run it from the root or docker directory without an argument.*
|
||||||
|
|
||||||
|
### How to update the website
|
||||||
|
|
||||||
|
1. Run the bash script `update-bang` in the docker directory with the root directory of the project as an argument.
|
||||||
|
- *Note: You can also simply run it from the root or docker directory without an argument.*
|
||||||
|
|
||||||
|
## Theo's words
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
```
|
### How is it that much faster?
|
||||||
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.
|
DuckDuckGo does their redirects server side. Their DNS is...not always great. Result is that it often takes ages.
|
||||||
|
|
||||||
|
3
docker/.env.example
Normal file
3
docker/.env.example
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
PORT=5000
|
||||||
|
DOMAIN=bang.mydomain.com
|
||||||
|
NETWORK=bridge
|
@ -13,6 +13,7 @@ RUN pnpm install
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the project
|
# Build the project
|
||||||
|
RUN pnpm run prebuild
|
||||||
RUN pnpm run build
|
RUN pnpm run build
|
||||||
|
|
||||||
# Stage 2: Serve the app using the same version of Node
|
# Stage 2: Serve the app using the same version of Node
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
bang-web-server:
|
bang-web-server:
|
||||||
build:
|
build:
|
||||||
context: ../ # point to the parent directory where package.json and source code reside
|
context: ../
|
||||||
dockerfile: docker/Dockerfile # specific path to the Dockerfile
|
dockerfile: docker/Dockerfile
|
||||||
container_name: bang
|
container_name: bang
|
||||||
|
hostname: bang.gib
|
||||||
domainname: bang.gbrown.org
|
domainname: bang.gbrown.org
|
||||||
hostname: bang
|
|
||||||
networks:
|
networks:
|
||||||
- node_apps
|
- nginx-bridge
|
||||||
ports:
|
#ports:
|
||||||
- "5000:5000"
|
#- 5000:5000
|
||||||
tty: true
|
tty: true
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ../:/app # mount the parent directory to /app in the container
|
- ../:/app
|
||||||
command: serve -s /app/dist -l 5000
|
command: serve -s /app/dist -l 5000
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
node_apps:
|
nginx-bridge:
|
||||||
external: true
|
external: true
|
||||||
|
51
docker/host-bang
Executable file
51
docker/host-bang
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to check if we're in the correct directory
|
||||||
|
check_directory() {
|
||||||
|
if [ -d "docker" ] && [ -f "package.json" ]; then
|
||||||
|
return 0 # We're in the root directory
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize root_dir
|
||||||
|
root_dir=""
|
||||||
|
|
||||||
|
# Check if argument is provided
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
# Use provided path
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
root_dir="$1"
|
||||||
|
cd "$root_dir" || exit 1
|
||||||
|
else
|
||||||
|
echo "Error: Provided directory does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No argument provided, try to determine location
|
||||||
|
current_dir=$(basename "$(pwd)")
|
||||||
|
|
||||||
|
if [ "$current_dir" = "docker" ]; then
|
||||||
|
cd .. || exit 1
|
||||||
|
elif [ "$current_dir" != "Bang" ]; then
|
||||||
|
echo "Error: Not in the correct directory and no valid path provided"
|
||||||
|
echo "Please either:"
|
||||||
|
echo "1. Run this script from the Bang root directory"
|
||||||
|
echo "2. Run this script from the docker directory"
|
||||||
|
echo "3. Provide the path to the Bang root directory as an argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify we're in the correct directory
|
||||||
|
if ! check_directory; then
|
||||||
|
echo "Error: Not in the correct directory structure"
|
||||||
|
echo "Make sure you're in a directory with 'docker' folder and package.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pnpm install
|
||||||
|
pnpm build
|
||||||
|
cd docker || exit 1
|
||||||
|
sudo docker compose up -d
|
||||||
|
cd ..
|
52
docker/update-bang
Executable file
52
docker/update-bang
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to check if we're in the correct directory
|
||||||
|
check_directory() {
|
||||||
|
if [ -d "docker" ] && [ -f "package.json" ]; then
|
||||||
|
return 0 # We're in the root directory
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize root_dir
|
||||||
|
root_dir=""
|
||||||
|
|
||||||
|
# Check if argument is provided
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
# Use provided path
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
root_dir="$1"
|
||||||
|
cd "$root_dir" || exit 1
|
||||||
|
else
|
||||||
|
echo "Error: Provided directory does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No argument provided, try to determine location
|
||||||
|
current_dir=$(basename "$(pwd)")
|
||||||
|
|
||||||
|
if [ "$current_dir" = "docker" ]; then
|
||||||
|
cd .. || exit 1
|
||||||
|
elif [ "$current_dir" != "Bang" ]; then
|
||||||
|
echo "Error: Not in the correct directory and no valid path provided"
|
||||||
|
echo "Please either:"
|
||||||
|
echo "1. Run this script from the Bang root directory"
|
||||||
|
echo "2. Run this script from the docker directory"
|
||||||
|
echo "3. Provide the path to the Bang root directory as an argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify we're in the correct directory
|
||||||
|
if ! check_directory; then
|
||||||
|
echo "Error: Not in the correct directory structure"
|
||||||
|
echo "Make sure you're in a directory with 'docker' folder and package.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git pull
|
||||||
|
pnpm build
|
||||||
|
cd docker || exit 1
|
||||||
|
sudo docker compose down
|
||||||
|
sudo docker compose up -d
|
||||||
|
cd ..
|
@ -24,6 +24,12 @@
|
|||||||
media="print"
|
media="print"
|
||||||
onload="this.media='all'"
|
onload="this.media='all'"
|
||||||
/>
|
/>
|
||||||
|
<link
|
||||||
|
rel="search"
|
||||||
|
type="application/opensearchdescription+xml"
|
||||||
|
title="Bang!"
|
||||||
|
href="/opensearch.xml"
|
||||||
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Bang!</title>
|
<title>Bang!</title>
|
||||||
<meta
|
<meta
|
||||||
|
14
package.json
14
package.json
@ -1,21 +1,25 @@
|
|||||||
{
|
{
|
||||||
"name": "unduck",
|
"name": "bang",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
"generate-opensearch": "ts-node scripts/generateOpenSearch.ts",
|
||||||
|
"prebuild": "pnpm generate-opensearch",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "~5.7.2",
|
"@types/node": "^22.15.17",
|
||||||
"vite": "^6.1.0"
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "~5.7.3",
|
||||||
|
"vite": "^6.3.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vite-plugin-pwa": "^0.21.1"
|
"vite-plugin-pwa": "^0.21.2"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b",
|
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"esbuild"
|
"esbuild"
|
||||||
|
1904
pnpm-lock.yaml
generated
1904
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
10
public/opensearch.xml
Normal file
10
public/opensearch.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Bang!</ShortName>
|
||||||
|
<Description>A better default search engine with bangs</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<Image width="16" height="16" type="image/svg+xml">https://bang.gbrown.org/bang.svg</Image>
|
||||||
|
<Url type="text/html" method="get" template="https://bang.gbrown.org?q={searchTerms}"/>
|
||||||
|
<Url type="application/opensearchdescription+xml" rel="self" template="https://bang.gbrown.org/opensearch.xml"/>
|
||||||
|
<moz:SearchForm xmlns:moz="http://www.mozilla.org/2006/browser/search/">https://bang.gbrown.org</moz:SearchForm>
|
||||||
|
</OpenSearchDescription>
|
98
scripts/files_to_clipboard
Executable file
98
scripts/files_to_clipboard
Executable file
@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
import pyperclip
|
||||||
|
import questionary
|
||||||
|
|
||||||
|
# List of directories to exclude
|
||||||
|
EXCLUDED_DIRS = {'node_modules', '.next', '.venv', '.git', '__pycache__', '.idea', '.vscode', 'ui'}
|
||||||
|
|
||||||
|
def collect_files(project_path):
|
||||||
|
"""
|
||||||
|
Collects files from the project directory, excluding specified directories and filtering by extensions.
|
||||||
|
Returns a list of file paths relative to the project directory.
|
||||||
|
"""
|
||||||
|
collected_files = []
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(project_path):
|
||||||
|
# Exclude specified directories
|
||||||
|
dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
file_path = Path(root) / file
|
||||||
|
relative_path = file_path.relative_to(project_path)
|
||||||
|
collected_files.append(relative_path)
|
||||||
|
|
||||||
|
return collected_files
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Parse command-line arguments
|
||||||
|
parser = argparse.ArgumentParser(description='Generate Markdown from selected files.')
|
||||||
|
parser.add_argument('path', nargs='?', default='.', help='Path to the project directory')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
project_path = Path(args.path).resolve()
|
||||||
|
if not project_path.is_dir():
|
||||||
|
print(f"Error: '{project_path}' is not a directory.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Collect files from the project directory
|
||||||
|
file_list = collect_files(project_path)
|
||||||
|
|
||||||
|
if not file_list:
|
||||||
|
print("No files found in the project directory with the specified extensions.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Sort file_list for better organization
|
||||||
|
file_list.sort()
|
||||||
|
|
||||||
|
# Interactive file selection using questionary
|
||||||
|
print("\nSelect the files you want to include:")
|
||||||
|
selected_files = questionary.checkbox(
|
||||||
|
"Press space to select files, and Enter when you're done:",
|
||||||
|
choices=[str(f) for f in file_list]
|
||||||
|
).ask()
|
||||||
|
|
||||||
|
if not selected_files:
|
||||||
|
print("No files selected.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Generate markdown
|
||||||
|
markdown_lines = []
|
||||||
|
markdown_lines.append('')
|
||||||
|
|
||||||
|
for selected_file in selected_files:
|
||||||
|
file_path = project_path / selected_file
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
# Determine the language for code block from file extension
|
||||||
|
language = file_path.suffix.lstrip('.')
|
||||||
|
markdown_lines.append(f'{selected_file}')
|
||||||
|
markdown_lines.append(f'```{language}')
|
||||||
|
markdown_lines.append(content)
|
||||||
|
markdown_lines.append('```')
|
||||||
|
markdown_lines.append('')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading file {selected_file}: {e}")
|
||||||
|
|
||||||
|
# Copy markdown content to clipboard
|
||||||
|
markdown_text = '\n'.join(markdown_lines)
|
||||||
|
pyperclip.copy(markdown_text)
|
||||||
|
print("Markdown content has been copied to the clipboard.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Check if required libraries are installed
|
||||||
|
try:
|
||||||
|
import questionary
|
||||||
|
import pyperclip
|
||||||
|
except ImportError as e:
|
||||||
|
missing_module = e.name
|
||||||
|
print(f"Error: Missing required module '{missing_module}'.")
|
||||||
|
print(f"Please install it by running: pip install {missing_module}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
main()
|
33
scripts/generateOpenSearch.ts
Normal file
33
scripts/generateOpenSearch.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import * as fs from 'node:fs';
|
||||||
|
import * as path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
// Get the current file's directory
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// Get the Bang URL from environment or use a default for local development
|
||||||
|
const bangUrl = process.env.VITE_BANG_URL || 'https://bang.gbrown.org';
|
||||||
|
|
||||||
|
// Create the OpenSearch XML content
|
||||||
|
const openSearchXml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Bang!</ShortName>
|
||||||
|
<Description>A better default search engine with bangs</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<Image width="16" height="16" type="image/svg+xml">${bangUrl}/bang.svg</Image>
|
||||||
|
<Url type="text/html" method="get" template="${bangUrl}?q={searchTerms}"/>
|
||||||
|
<Url type="application/opensearchdescription+xml" rel="self" template="${bangUrl}/opensearch.xml"/>
|
||||||
|
<moz:SearchForm xmlns:moz="http://www.mozilla.org/2006/browser/search/">${bangUrl}</moz:SearchForm>
|
||||||
|
</OpenSearchDescription>`;
|
||||||
|
|
||||||
|
// Ensure the public directory exists
|
||||||
|
const publicDir = path.resolve(__dirname, '../public');
|
||||||
|
if (!fs.existsSync(publicDir)) {
|
||||||
|
fs.mkdirSync(publicDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the OpenSearch XML file
|
||||||
|
fs.writeFileSync(path.join(publicDir, 'opensearch.xml'), openSearchXml);
|
||||||
|
|
||||||
|
console.log('OpenSearch XML file generated successfully!');
|
186
src/bang.ts
186
src/bang.ts
@ -1,113 +1,190 @@
|
|||||||
// This file was (mostly) ripped from https://duckduckgo.com/bang.js
|
// This file was (mostly) ripped from https://duckduckgo.com/bang.js
|
||||||
|
|
||||||
|
const SEARXNG_URL = import.meta.env.VITE_SEARXNG_URL as string;
|
||||||
|
const GITEA_URL = import.meta.env.VITE_GITEA_URL as string;
|
||||||
|
const OPENWEBUI_URL = import.meta.env.VITE_OPENWEBUI_URL as string;
|
||||||
|
const PLEX_URL = import.meta.env.VITE_PLEX_URL as string;
|
||||||
|
const OVERSEERR_URL = import.meta.env.VITE_OVERSEERR_URL as string;
|
||||||
|
const SONARR_URL = import.meta.env.VITE_SONARR_URL as string;
|
||||||
|
const RADARR_URL = import.meta.env.VITE_RADARR_URL as string;
|
||||||
|
const LIDARR_URL = import.meta.env.VITE_LIDARR_URL as string;
|
||||||
|
|
||||||
|
const LLAMA_MODEL = import.meta.env.VITE_LLAMA_MODEL.replace(":", "%3A") as string;
|
||||||
|
const DEEPSEEK_MODEL = import.meta.env.VITE_DEEPSEEK_MODEL.replace(":", "%3A") as string;
|
||||||
|
const OPENAI_MODEL = import.meta.env.VITE_OPENAI_MODEL as string;
|
||||||
|
const CLAUDE_MODEL = import.meta.env.VITE_CLAUDE_MODEL.replace("/", "%2F") as string;
|
||||||
|
|
||||||
export const bangs = [
|
export const bangs = [
|
||||||
{
|
{
|
||||||
c: "Online Services",
|
c: "Online Services",
|
||||||
d: "search.gibbyb.com",
|
d: SEARXNG_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "Searxng",
|
||||||
sc: "Search",
|
sc: "Search",
|
||||||
t: "sg",
|
t: "s",
|
||||||
u: "https://search.gibbyb.com/?q={{{s}}}",
|
u: `${SEARXNG_URL}/?q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "Tech",
|
c: "Tech",
|
||||||
d: "git.gibbyb.com",
|
d: GITEA_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "Gitea",
|
s: "Gitea",
|
||||||
sc: "Cryptocurrency",
|
sc: "Cryptocurrency",
|
||||||
t: "tea",
|
t: "tea",
|
||||||
u: "https://git.gibbyb.com/?repo-search-query={{{s}}}",
|
u: `${GITEA_URL}/?repo-search-query={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: PLEX_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Plex",
|
||||||
|
sc: "Movies",
|
||||||
|
t: "plex",
|
||||||
|
u: `${PLEX_URL}/web/index.html#!/search?pivot=top&query={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: OVERSEERR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Overseerr",
|
||||||
|
sc: "Movies",
|
||||||
|
t: "ov",
|
||||||
|
u: `${OVERSEERR_URL}/search?query={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: LIDARR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Lidarr",
|
||||||
|
sc: "Music",
|
||||||
|
t: "mp3",
|
||||||
|
u: `${LIDARR_URL}/add/new?term={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: SONARR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Sonarr",
|
||||||
|
sc: "TV",
|
||||||
|
t: "tv",
|
||||||
|
u: `${SONARR_URL}/add/new?term={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "Entertainment",
|
||||||
|
d: RADARR_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "Radarr",
|
||||||
|
sc: "Movies",
|
||||||
|
t: "mv",
|
||||||
|
u: `${RADARR_URL}/add/new?term={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "ai",
|
t: "ai",
|
||||||
u: "https://chat.gibbyb.com/?q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "claude",
|
t: "c",
|
||||||
u: "https://chat.gibbyb.com/?models=anthropic%2Fclaude-3.5-sonnet&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "llama",
|
t: "llama",
|
||||||
u: "https://chat.gibbyb.com/?models=llama3.1&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=${LLAMA_MODEL}&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
|
||||||
t: "r17b",
|
|
||||||
u: "https://chat.gibbyb.com/?models=deepseek-r1%3A7b&q={{{s}}}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
c: "AI",
|
|
||||||
d: "chat.gibbyb.com",
|
|
||||||
r: 0,
|
|
||||||
s: "GibbyB",
|
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "r1",
|
t: "r1",
|
||||||
u: "https://chat.gibbyb.com/?models=deepseek-r1%3A8b&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=${DEEPSEEK_MODEL}&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "r132b",
|
t: "r1-7b",
|
||||||
u: "https://chat.gibbyb.com/?models=deepseek-r1%3A32b&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=deepseek-r1%3A7b&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "r1-32b",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=deepseek-r1%3A32b&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "claude",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=${CLAUDE_MODEL}&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
|
sc: "AI",
|
||||||
|
t: "openai",
|
||||||
|
u: `${OPENWEBUI_URL}/?models=${OPENAI_MODEL}&q={{{s}}}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
c: "AI",
|
||||||
|
d: OPENWEBUI_URL,
|
||||||
|
r: 0,
|
||||||
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "o3-mini",
|
t: "o3-mini",
|
||||||
u: "https://chat.gibbyb.com/?models=o3-mini&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=o3-mini&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "o1",
|
t: "o1",
|
||||||
u: "https://chat.gibbyb.com/?models=o1&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=o1&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "4o-mini",
|
t: "4o-mini",
|
||||||
u: "https://chat.gibbyb.com/?models=gpt-4o-mini&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=gpt-4o-mini&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
d: "chat.gibbyb.com",
|
d: OPENWEBUI_URL,
|
||||||
r: 0,
|
r: 0,
|
||||||
s: "GibbyB",
|
s: "OpenWebUI",
|
||||||
sc: "AI",
|
sc: "AI",
|
||||||
t: "4o",
|
t: "4o",
|
||||||
u: "https://chat.gibbyb.com/?models=gpt-4o&q={{{s}}}",
|
u: `${OPENWEBUI_URL}/?models=gpt-4o&q={{{s}}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "AI",
|
c: "AI",
|
||||||
@ -71396,7 +71473,7 @@ export const bangs = [
|
|||||||
r: 10,
|
r: 10,
|
||||||
s: "Myvideo",
|
s: "Myvideo",
|
||||||
sc: "Video",
|
sc: "Video",
|
||||||
t: "mv",
|
t: "myvideo",
|
||||||
u: "http://www.myvideo.de/Videos_A-Z?searchWord={{{s}}}",
|
u: "http://www.myvideo.de/Videos_A-Z?searchWord={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -73509,8 +73586,8 @@ export const bangs = [
|
|||||||
r: 0,
|
r: 0,
|
||||||
s: "Nextcloud App Store",
|
s: "Nextcloud App Store",
|
||||||
sc: "Sysadmin",
|
sc: "Sysadmin",
|
||||||
t: "nextcloudapp",
|
t: "cloudapp",
|
||||||
u: "https://apps.nextcloud.com/?search={{{s}}}",
|
u: "https://apps.nextcloud.com/search/?q={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
c: "Entertainment",
|
c: "Entertainment",
|
||||||
@ -78835,7 +78912,7 @@ export const bangs = [
|
|||||||
r: 0,
|
r: 0,
|
||||||
s: "StackOverflow",
|
s: "StackOverflow",
|
||||||
sc: "Programming",
|
sc: "Programming",
|
||||||
t: "ov",
|
t: "ovfl",
|
||||||
u: "http://stackoverflow.com/search?q={{{s}}}",
|
u: "http://stackoverflow.com/search?q={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -98415,7 +98492,7 @@ export const bangs = [
|
|||||||
r: 12469,
|
r: 12469,
|
||||||
s: "startpage.com",
|
s: "startpage.com",
|
||||||
sc: "Search",
|
sc: "Search",
|
||||||
t: "s",
|
t: "startpage",
|
||||||
u: "http://startpage.com/do/metasearch.pl?query={{{s}}}",
|
u: "http://startpage.com/do/metasearch.pl?query={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -106788,15 +106865,6 @@ export const bangs = [
|
|||||||
t: "tva",
|
t: "tva",
|
||||||
u: "https://tweakers.net/aanbod/zoeken/?keyword={{{s}}}",
|
u: "https://tweakers.net/aanbod/zoeken/?keyword={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
c: "Entertainment",
|
|
||||||
d: "www.tv.com",
|
|
||||||
r: 0,
|
|
||||||
s: "TV.com",
|
|
||||||
sc: "TV",
|
|
||||||
t: "tvcom",
|
|
||||||
u: "http://www.tv.com/search?q={{{s}}}",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
c: "Entertainment",
|
c: "Entertainment",
|
||||||
d: "www.thetvdb.com",
|
d: "www.thetvdb.com",
|
||||||
@ -106956,7 +107024,7 @@ export const bangs = [
|
|||||||
r: 31,
|
r: 31,
|
||||||
s: "tv.com",
|
s: "tv.com",
|
||||||
sc: "TV",
|
sc: "TV",
|
||||||
t: "tv",
|
t: "tvcom",
|
||||||
u: "http://www.tv.com/search?q={{{s}}}",
|
u: "http://www.tv.com/search?q={{{s}}}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -93,17 +93,25 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --- Container layout unchanged --- */
|
/* --- Container layout unchanged --- */
|
||||||
.url-container {
|
.main-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
justify-content: center;
|
||||||
margin-top: 16px;
|
min-height: 100vh;
|
||||||
|
padding: 20px 0px;
|
||||||
}
|
}
|
||||||
.content-container {
|
.content-container {
|
||||||
max-width: 36rem;
|
max-width: 36rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
|
.url-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* --- URL input element styling adjustments --- */
|
/* --- URL input element styling adjustments --- */
|
||||||
.url-input {
|
.url-input {
|
||||||
@ -168,23 +176,13 @@ textarea {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 32px;
|
gap: 24px;
|
||||||
}
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
.settings-links-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 32px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.browser-link-container {
|
.browser-link-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
}
|
||||||
.browser-instruction {
|
.browser-instruction {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -208,3 +206,19 @@ textarea {
|
|||||||
background-color: var(--input-bg-color);
|
background-color: var(--input-bg-color);
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Mobile --- */
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.settings-links-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
.main-container {
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
11
src/main.ts
11
src/main.ts
@ -4,7 +4,7 @@ import "./global.css";
|
|||||||
function noSearchDefaultPageRender() {
|
function noSearchDefaultPageRender() {
|
||||||
const app = document.querySelector<HTMLDivElement>("#app")!;
|
const app = document.querySelector<HTMLDivElement>("#app")!;
|
||||||
app.innerHTML = `
|
app.innerHTML = `
|
||||||
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh;">
|
<main class="main-container">
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<h1 class="bang-title">💣 Bang!</h1>
|
<h1 class="bang-title">💣 Bang!</h1>
|
||||||
<p>
|
<p>
|
||||||
@ -18,7 +18,7 @@ function noSearchDefaultPageRender() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="url-input"
|
class="url-input"
|
||||||
value="https://bang.gbrown.org?q=%s"
|
value="${import.meta.env.VITE_BANG_URL}?q=%s"
|
||||||
readonly
|
readonly
|
||||||
/>
|
/>
|
||||||
<button class="copy-button">
|
<button class="copy-button">
|
||||||
@ -41,7 +41,7 @@ function noSearchDefaultPageRender() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Engine URL:</b></td>
|
<td><b>Engine URL:</b></td>
|
||||||
<td>https://bang.gbrown.org?q=%s</td>
|
<td>${import.meta.env.VITE_BANG_URL}?q=%s</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Alias:</b></td>
|
<td><b>Alias:</b></td>
|
||||||
@ -75,7 +75,7 @@ function noSearchDefaultPageRender() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const copyButton = app.querySelector<HTMLButtonElement>(".copy-button")!;
|
const copyButton = app.querySelector<HTMLButtonElement>(".copy-button")!;
|
||||||
@ -113,7 +113,8 @@ function noSearchDefaultPageRender() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? "sg";
|
const envDefaultBang = import.meta.env.VITE_DEFAULT_BANG ?? "g";
|
||||||
|
const LS_DEFAULT_BANG = localStorage.getItem("default-bang") ?? envDefaultBang;
|
||||||
const defaultBang = bangs.find((b) => b.t === LS_DEFAULT_BANG);
|
const defaultBang = bangs.find((b) => b.t === LS_DEFAULT_BANG);
|
||||||
|
|
||||||
function getBangredirectUrl() {
|
function getBangredirectUrl() {
|
||||||
|
Reference in New Issue
Block a user