diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9655535 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# Use Alpine Linux as the base image +FROM alpine:3.20 + +# Update and install Golang and Git +RUN apk update && apk add --no-cache go git + +# Create a new user and switch to it +RUN adduser -D myuser +USER myuser + +# Set the working directory +WORKDIR /home/myuser + +# Clone the Git repository +RUN git clone https://weforge.xyz/Spitfire/Search.git + +# Change directory to the cloned repository +WORKDIR /home/myuser/Search + +# Ensure the run.sh script is executable +RUN chmod +x run.sh + +# Expose the application's port +EXPOSE 5000 + +# Define environment variables for port and domain with default values +ENV PORT= +ENV DOMAIN= +ENV SKIP_CONFIG="--skip-config-check" + +# Run the run.sh script on container start +CMD ["sh", "-c", "./run.sh $SKIP_CONFIG --port ${PORT:-} --domain ${DOMAIN:-}"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..65b8600 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +

+ Logo +

+ +

+ QGato Search Engine +

+ +

+A self-hosted private metasearch engine that aims to be more resource-efficient than its competition. +

+ +# Bare in mind that this project is still WIP + +## Comparison to other search engines + + +| Feature | Whoogle [1] | Araa-Search | LibreY | 4get | SearchXNG | *QGato* | +| :------------------------- | ------------------ | ------------------------- | ------------------------ | ------------------------ | ------------------------- | ---------------------------------------------------- | +| Works without JavaScript | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| Music search | ❓ | ❌ | ❌ | ✅ | ✅ | ✅ | +| Torrent search | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | +| API | ❌ | ❓ [2] | ✅ | ✅ | ✅ | ✅ | +| Scalable | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | +| Not Resource Hungry | ❓ Moderate | ❌ Very resource hungry | ❌ Moderate 200-400mb~ | ❌ Moderate 200-400mb~ | ❌ Moderate 200-300MiB~ | ✅ about 15-20MiB at idle, 17-22MiB when searching | +| Result caching | ❌ | ❌ | ❓ | ❓ | ❓ | ✅ | +| Dynamic Page Loading | ❓ Not specified | ❌ | ❌ | ❌ | ✅ | ✅ | +| User themable | ❌ | ✅ | ❌ | ❌ | ✅[3] | ✅ | +| Unusual logo choice | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | + +[1]: I was not able to check this since their site does not work, same for the community instances. + +[2]: In the project repo they specify that it has API, but It looks like they are no loger supporting it. Or just removed "API" button and documentation, since I was not able to find it anymore. + +[3]: It is called 'User Themable' because you want to give the user freedom of choice for their theme, not by hard-setting one theme in the backend and calling it themable. + +## Features + +### For Casual Users + +- **Works out of the box** - No configuration required, just works by default. +- **No tracking or ads** - Fully private, ad-free experience. +- **Custom themes** - Personalize the look and feel. +- **Search suggestions** - Get faster results with helpful suggestions. +- **Privacy-first** - Open-source and transparent (unlike DuckDuckGo). +- **Annoyance-free** - No pop-ups, crypto, or clutter (I'm looking at you, Brave). + +### For Self-Hosting + +- **Self-hosted option** - Run on your own server for even more privacy. +- **Lightweight** - Low memory footprint (15-22MiB) even during searches. +- **Decentralized** - No single point of failure. +- **Results caching in RAM** - Faster response times through caching. +- **Configurable** - Tweak features via `config.ini`. +- **Flexible media support** - Images optionally stored on HDD/SSD for caching and improved response time. + +### Results Sources + +- **Search suggestions** - Sources include Yahoo, Startpage, Qwant, Ecosia, Brave, Edge, and DuckDuckGo. +- **Text search** - Google, Brave, DuckDuckGo, LibreX/Y. +- **Image search** - Sources include Qwant, Bing, and Imgur. +- **Video search** - Utilizes the Piped API. +- **Maps** - Integrated OpenStreetMap. +- **File downloads** - Access via torrent sources. + +## Getting Started + +### Prerequisites + +- Go (version 1.18 or higher recommended) +- Git (unexpected) +- Access to the internet for fetching results (even more unexpected) + +### Running the QGato + +Linux: + +```bash +git clone https://weforgecode.xyz/Spitfire/Search.git +cd Search +chmod +x ./run.sh +./run.sh +``` + +Windows: + +```powershell +git clone https://weforgecode.xyz/Spitfire/Search.git +cd Search +.\run.bat +``` + +*Its that easy!* + +### Configuring + +Configuration is done via the ``config.ini`` file. +On first start, you will be guided through the basic setup. +More advanced setup and all options will be listed here later, as this is still being updated. + +## License + +[![](https://www.gnu.org/graphics/agplv3-with-text-162x68.png)](https://www.gnu.org/licenses/agpl-3.0.html) diff --git a/init.go b/init.go index 52789b7..de32e07 100644 --- a/init.go +++ b/init.go @@ -1,6 +1,8 @@ package main import ( + "flag" + "os" "time" ) @@ -35,14 +37,43 @@ const configFilePath = "config.ini" var config Config func main() { - err := initConfig() - if err != nil { - printErr("Error during initialization:") - return + // Command-line flags + portFlag := flag.Int("port", 0, "Port number to run the application (overrides config)") + domainFlag := flag.String("domain", "", "Domain address for the application (overrides config)") + skipConfigFlag := flag.Bool("skip-config-check", false, "Skip interactive prompts and load config.ini") + + // Parse command-line flags + flag.Parse() + + if *skipConfigFlag { + // Skip interactive configuration + if _, err := os.Stat(configFilePath); err == nil { + // Load from config file if it exists + config = loadConfig() + } else { + // Use defaults if config file does not exist + config = defaultConfig + saveConfig(config) // Save the defaults to config.ini + printInfo("Configuration saved to %s", configFilePath) + } + } else { + // Initialize configuration interactively or from config file + err := initConfig() + if err != nil { + printErr("Error during initialization:") + return + } + } + + // Override with command-line arguments if provided + if *portFlag != 0 { + config.Port = *portFlag + } + if *domainFlag != "" { + config.Domain = *domainFlag } loadNodeConfig() - // go checkMasterHeartbeat() // Not currently used if config.AuthCode == "" { config.AuthCode = generateStrongRandomString(64) @@ -57,14 +88,6 @@ func main() { } config.PeerID = hostID - // if len(config.Peers) > 0 { - // time.Sleep(2 * time.Second) // Give some time for connections to establish - // startElection() - // } - - // Start automatic update checker, not used now - //go checkForUpdates() - InitializeLanguage("en") // Initialize language before generating OpenSearch generateOpenSearchXML(config) diff --git a/run.bat b/run.bat index 0f68a88..3fedce2 100755 --- a/run.bat +++ b/run.bat @@ -1,6 +1,36 @@ @echo off setlocal enabledelayedexpansion +rem Initialize variables +set SKIP_CONFIG="" +set PORT="" +set DOMAIN="" + +rem Parse arguments +:parse_args +if "%~1"=="" goto end_parse +if "%~1"=="--port" ( + set PORT=%~2 + shift + shift + goto parse_args +) +if "%~1"=="--domain" ( + set DOMAIN=%~2 + shift + shift + goto parse_args +) +if "%~1"=="--skip-config-check" ( + set SKIP_CONFIG=--skip-config-check + shift + goto parse_args +) +echo Unknown argument: %~1 +exit /b 1 + +:end_parse + rem Use the current directory where the script is executed pushd %~dp0 @@ -10,8 +40,16 @@ for %%f in (*.go) do ( set GO_FILES=!GO_FILES! %%f ) -rem Run the Go program with all the .go files -go run !GO_FILES! +rem Construct the command +set CMD=go run !GO_FILES! !SKIP_CONFIG! +if not "%PORT%"=="" set CMD=!CMD! --port %PORT% +if not "%DOMAIN%"=="" set CMD=!CMD! --domain %DOMAIN% + +rem Informative output +echo Starting application with command: !CMD! + +rem Run the Go program with the constructed command +call !CMD! rem Return to the original directory popd diff --git a/run.sh b/run.sh index 1c13eb4..b703495 100755 --- a/run.sh +++ b/run.sh @@ -1,7 +1,42 @@ #!/bin/sh -# List all go files in this directory +# Initialize variables +SKIP_CONFIG="" +PORT="" +DOMAIN="" + +# Parse arguments +while [ $# -gt 0 ]; do + case $1 in + --port) + PORT=$2 + shift 2 + ;; + --domain) + DOMAIN=$2 + shift 2 + ;; + --skip-config-check) + SKIP_CONFIG="--skip-config-check" + shift + ;; + *) + echo "Unknown argument: $1" + exit 1 + ;; + esac +done + +# List all Go files in this directory GO_FILES=$(find . -name '*.go' -print) -# Run the Go program with the specified files first, followed by the remaining files -go run $FILES $GO_FILES +# Construct the command +CMD="go run $GO_FILES $SKIP_CONFIG" +[ -n "$PORT" ] && CMD="$CMD --port $PORT" +[ -n "$DOMAIN" ] && CMD="$CMD --domain $DOMAIN" + +# Informative output +echo "Starting application with command: $CMD" + +# Run the Go program with the constructed command +eval $CMD