299 lines
9.4 KiB
Go
Executable file
299 lines
9.4 KiB
Go
Executable file
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
// LanguageOption represents a language option for search
|
|
type LanguageOption struct {
|
|
Code string
|
|
Name string
|
|
}
|
|
|
|
var settings UserSettings
|
|
|
|
var languageOptions = []LanguageOption{
|
|
{Code: "", Name: "Any Language"},
|
|
{Code: "en", Name: "English"},
|
|
{Code: "af", Name: "Afrikaans"},
|
|
{Code: "ar", Name: "العربية (Arabic)"},
|
|
{Code: "hy", Name: "Հայերեն (Armenian)"},
|
|
{Code: "be", Name: "Беларуская (Belarusian)"},
|
|
{Code: "bg", Name: "български (Bulgarian)"},
|
|
{Code: "ca", Name: "Català (Catalan)"},
|
|
{Code: "zh-CN", Name: "中文 (简体) (Chinese Simplified)"},
|
|
{Code: "zh-TW", Name: "中文 (繁體) (Chinese Traditional)"},
|
|
{Code: "hr", Name: "Hrvatski (Croatian)"},
|
|
{Code: "cs", Name: "Čeština (Czech)"},
|
|
{Code: "da", Name: "Dansk (Danish)"},
|
|
{Code: "nl", Name: "Nederlands (Dutch)"},
|
|
{Code: "eo", Name: "Esperanto"},
|
|
{Code: "et", Name: "Eesti (Estonian)"},
|
|
{Code: "tl", Name: "Filipino (Tagalog)"},
|
|
{Code: "fi", Name: "Suomi (Finnish)"},
|
|
{Code: "fr", Name: "Français (French)"},
|
|
{Code: "de", Name: "Deutsch (German)"},
|
|
{Code: "el", Name: "Ελληνικά (Greek)"},
|
|
{Code: "iw", Name: "עברית (Hebrew)"},
|
|
{Code: "hi", Name: "हिन्दी (Hindi)"},
|
|
{Code: "hu", Name: "magyar (Hungarian)"},
|
|
{Code: "is", Name: "íslenska (Icelandic)"},
|
|
{Code: "id", Name: "Bahasa Indonesia (Indonesian)"},
|
|
{Code: "it", Name: "italiano (Italian)"},
|
|
{Code: "ja", Name: "日本語 (Japanese)"},
|
|
{Code: "ko", Name: "한국어 (Korean)"},
|
|
{Code: "lv", Name: "latviešu (Latvian)"},
|
|
{Code: "lt", Name: "lietuvių (Lithuanian)"},
|
|
{Code: "no", Name: "norsk (Norwegian)"},
|
|
{Code: "fa", Name: "فارسی (Persian)"},
|
|
{Code: "pl", Name: "polski (Polish)"},
|
|
{Code: "pt", Name: "português (Portuguese)"},
|
|
{Code: "ro", Name: "română (Romanian)"},
|
|
{Code: "ru", Name: "русский (Russian)"},
|
|
{Code: "sr", Name: "српски (Serbian)"},
|
|
{Code: "sk", Name: "slovenčina (Slovak)"},
|
|
{Code: "sl", Name: "slovenščina (Slovenian)"},
|
|
{Code: "es", Name: "español (Spanish)"},
|
|
{Code: "sw", Name: "Kiswahili (Swahili)"},
|
|
{Code: "sv", Name: "svenska (Swedish)"},
|
|
{Code: "th", Name: "ไทย (Thai)"},
|
|
{Code: "tr", Name: "Türkçe (Turkish)"},
|
|
{Code: "uk", Name: "українська (Ukrainian)"},
|
|
{Code: "vi", Name: "Tiếng Việt (Vietnamese)"},
|
|
}
|
|
|
|
func handleSearch(w http.ResponseWriter, r *http.Request) {
|
|
query, safe, lang, searchType, page := parseSearchParams(r)
|
|
|
|
settings = loadUserSettings(w, r)
|
|
|
|
theme := r.URL.Query().Get("theme")
|
|
if theme != "" {
|
|
settings.Theme = theme
|
|
saveUserSettings(w, settings)
|
|
} else if settings.Theme == "" {
|
|
settings.Theme = "dark"
|
|
}
|
|
|
|
if safe != "" && safe != settings.SafeSearch {
|
|
settings.SafeSearch = safe
|
|
saveUserSettings(w, settings)
|
|
}
|
|
|
|
// Update site language if provided, or use existing settings
|
|
if lang != "" && lang != settings.SiteLanguage {
|
|
settings.SiteLanguage = lang
|
|
saveUserSettings(w, settings)
|
|
} else if settings.SiteLanguage == "" {
|
|
settings.SiteLanguage = normalizeLangCode(r.Header.Get("Accept-Language"))
|
|
saveUserSettings(w, settings)
|
|
}
|
|
|
|
// Update search language (can be empty)
|
|
searchLang := r.URL.Query().Get("search_lang")
|
|
if searchLang != settings.SearchLanguage {
|
|
settings.SearchLanguage = searchLang
|
|
saveUserSettings(w, settings)
|
|
}
|
|
|
|
switch settings.Theme {
|
|
case "dark", "black", "night", "latte":
|
|
settings.IsThemeDark = true
|
|
default:
|
|
settings.IsThemeDark = false
|
|
}
|
|
|
|
InitializeLanguage(settings.SiteLanguage)
|
|
|
|
// Translate the "Any Language" option after initialization
|
|
for i, option := range languageOptions {
|
|
if option.Code == "" {
|
|
languageOptions[i].Name = Translate("any_language")
|
|
}
|
|
}
|
|
|
|
// Determine the paths for SVG and PNG icons
|
|
iconPathSVG, iconPathPNG := GetIconPath()
|
|
|
|
if query == "" {
|
|
data := struct {
|
|
LanguageOptions []LanguageOption
|
|
CurrentLang string
|
|
CurrentSearchLang string
|
|
Theme string
|
|
Safe string
|
|
IsThemeDark bool
|
|
IconPathSVG string
|
|
IconPathPNG string
|
|
}{
|
|
LanguageOptions: languageOptions,
|
|
CurrentLang: settings.SiteLanguage,
|
|
CurrentSearchLang: settings.SearchLanguage,
|
|
Theme: settings.Theme,
|
|
Safe: settings.SafeSearch,
|
|
IsThemeDark: settings.IsThemeDark,
|
|
IconPathSVG: iconPathSVG,
|
|
IconPathPNG: iconPathPNG,
|
|
}
|
|
|
|
// Add Translate to the template functions
|
|
tmpl, err := template.New("search.html").Funcs(template.FuncMap{
|
|
"translate": Translate,
|
|
}).ParseFiles("templates/search.html")
|
|
if err != nil {
|
|
printErr("Error parsing template: %v", err)
|
|
http.Error(w, Translate("internal_server_error"), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
err = tmpl.Execute(w, data)
|
|
if err != nil {
|
|
printErr("Error executing template: %v", err)
|
|
http.Error(w, Translate("internal_server_error"), http.StatusInternalServerError)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Handle different search types
|
|
switch searchType {
|
|
case "image":
|
|
handleImageSearch(w, r, settings, query, page)
|
|
case "video":
|
|
handleVideoSearch(w, settings, query, page)
|
|
case "map":
|
|
handleMapSearch(w, settings, query)
|
|
case "forum":
|
|
handleForumsSearch(w, settings, query, page)
|
|
case "file":
|
|
handleFileSearch(w, settings, query, page)
|
|
case "text":
|
|
fallthrough
|
|
default:
|
|
HandleTextSearch(w, settings, query, page)
|
|
}
|
|
}
|
|
|
|
func parseSearchParams(r *http.Request) (query, safe, lang, searchType string, page int) {
|
|
if r.Method == "GET" {
|
|
query = r.URL.Query().Get("q")
|
|
safe = r.URL.Query().Get("safe")
|
|
lang = r.URL.Query().Get("lang")
|
|
searchType = r.URL.Query().Get("t")
|
|
pageStr := r.URL.Query().Get("p")
|
|
page = parsePageParameter(pageStr)
|
|
} else if r.Method == "POST" {
|
|
query = r.FormValue("q")
|
|
safe = r.FormValue("safe")
|
|
lang = r.FormValue("lang")
|
|
searchType = r.FormValue("t")
|
|
pageStr := r.FormValue("p")
|
|
page = parsePageParameter(pageStr)
|
|
}
|
|
|
|
if searchType == "" {
|
|
searchType = "text"
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func parsePageParameter(pageStr string) int {
|
|
page, err := strconv.Atoi(pageStr)
|
|
if err != nil || page < 1 {
|
|
page = 1
|
|
}
|
|
return page
|
|
}
|
|
|
|
func runServer() {
|
|
|
|
if config.WebsiteEnabled {
|
|
// Website-related endpoints
|
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
|
http.HandleFunc("/", handleSearch)
|
|
http.HandleFunc("/search", handleSearch)
|
|
http.HandleFunc("/suggestions", handleSuggestions)
|
|
http.HandleFunc("/settings", handleSettings)
|
|
http.HandleFunc("/save-settings", handleSaveSettings)
|
|
http.HandleFunc("/image/", handleImageServe)
|
|
http.HandleFunc("/image_status", handleImageStatus)
|
|
http.HandleFunc("/privacy", handlePrivacyPage)
|
|
http.HandleFunc("/opensearch.xml", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/opensearchdescription+xml")
|
|
http.ServeFile(w, r, "static/opensearch.xml")
|
|
})
|
|
printInfo("Website functionality enabled.")
|
|
} else {
|
|
// Redirect all website routes to a "service disabled" handler
|
|
http.HandleFunc("/static/", handleWebsiteDisabled)
|
|
http.HandleFunc("/", handleWebsiteDisabled)
|
|
http.HandleFunc("/search", handleWebsiteDisabled)
|
|
http.HandleFunc("/settings", handleWebsiteDisabled)
|
|
http.HandleFunc("/save-settings", handleWebsiteDisabled)
|
|
http.HandleFunc("/image/", handleWebsiteDisabled)
|
|
http.HandleFunc("/image_status", handleWebsiteDisabled)
|
|
http.HandleFunc("/privacy", handleWebsiteDisabled)
|
|
http.HandleFunc("/opensearch.xml", handleWebsiteDisabled)
|
|
printInfo("Website functionality disabled.")
|
|
}
|
|
|
|
if config.NodesEnabled {
|
|
http.HandleFunc("/node", handleNodeRequest)
|
|
}
|
|
|
|
printMessage("Server is listening on http://localhost:%d", config.Port)
|
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil))
|
|
}
|
|
|
|
func handleWebsiteDisabled(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
_, _ = w.Write([]byte("The website functionality is currently disabled."))
|
|
}
|
|
|
|
func handlePrivacyPage(w http.ResponseWriter, r *http.Request) {
|
|
settings := loadUserSettings(w, r)
|
|
iconPathSVG, iconPathPNG := GetIconPath()
|
|
|
|
// Define the data structure for the template
|
|
data := struct {
|
|
Theme string
|
|
IconPathSVG string
|
|
IconPathPNG string
|
|
IsThemeDark bool
|
|
CookieRows []CookieRow
|
|
CurrentLang string
|
|
Safe string
|
|
LanguageOptions []LanguageOption
|
|
}{
|
|
Theme: settings.Theme,
|
|
IconPathSVG: iconPathSVG,
|
|
IconPathPNG: iconPathPNG,
|
|
IsThemeDark: settings.IsThemeDark,
|
|
CookieRows: generateCookieTable(r),
|
|
CurrentLang: settings.SiteLanguage,
|
|
Safe: settings.SafeSearch,
|
|
LanguageOptions: languageOptions,
|
|
}
|
|
|
|
// Parse the template
|
|
tmpl, err := template.New("privacy.html").ParseFiles("templates/privacy.html")
|
|
if err != nil {
|
|
log.Printf("Error parsing template: %v", err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Set the response content type
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
|
|
// Execute the template
|
|
if err := tmpl.Execute(w, data); err != nil {
|
|
log.Printf("Error executing template: %v", err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
}
|
|
}
|