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: "Auto-detect"}, {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) // Load user settings settings = loadUserSettings(w, r) // Update theme if provided, or use existing settings theme := r.URL.Query().Get("theme") if theme != "" { settings.Theme = theme saveUserSettings(w, settings) // Save if theme is updated } else if settings.Theme == "" { settings.Theme = "dark" // Default theme } // Update safe search if provided, or use existing settings if safe != "" && safe != settings.SafeSearch { settings.SafeSearch = safe saveUserSettings(w, settings) // Save if safe search is updated } // Update language if provided, or use existing settings if lang != "" && lang != settings.Language { settings.Language = lang saveUserSettings(w, settings) // Save if language is updated } else if settings.Language == "" { // If no language set, auto-detect from browser or default to "en" settings.Language = normalizeLangCode(r.Header.Get("Accept-Language")) saveUserSettings(w, settings) // Save if language is auto-detected } // This will do for now (to handle Dark Reader addon) switch settings.Theme { case "dark", "black", "night", "latte": settings.IsThemeDark = true default: settings.IsThemeDark = false } // Check if there is a search query if query == "" { // If no query is provided, render the search page template data := struct { LanguageOptions []LanguageOption CurrentLang string Theme string Safe string IsThemeDark bool }{ LanguageOptions: languageOptions, CurrentLang: settings.Language, Theme: settings.Theme, Safe: settings.SafeSearch, IsThemeDark: settings.IsThemeDark, } tmpl := template.Must(template.ParseFiles("templates/search.html")) tmpl.Execute(w, data) return } // Handle search based on the type switch searchType { case "image": handleImageSearch(w, 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() { http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) http.HandleFunc("/", handleSearch) http.HandleFunc("/search", handleSearch) http.HandleFunc("/suggestions", handleSuggestions) http.HandleFunc("/imgproxy", handleImageProxy) http.HandleFunc("/node", handleNodeRequest) http.HandleFunc("/settings", handleSettings) http.HandleFunc("/save-settings", handleSaveSettings) 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") }) initializeTorrentSites() config := loadConfig() generateOpenSearchXML(config) printMessage("Server is listening on http://localhost:%d", config.Port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil)) // Start automatic update checker go checkForUpdates() }