add simple settings template, cleanup

This commit is contained in:
admin 2024-04-15 08:35:17 +02:00
parent 85be52091e
commit 446b8009a2
11 changed files with 203 additions and 164 deletions

View file

@ -4,11 +4,11 @@
- [x] Text results - [x] Text results
- [x] Image results - [x] Image results
- [X] Video results
- [x] HTML+CSS site (no JS version) - [x] HTML+CSS site (no JS version)
## Pending Tasks ## Pending Tasks
- [ ] Video results
- [ ] Forums results - [ ] Forums results
- [ ] Map results - [ ] Map results
- [ ] Torrent results - [ ] Torrent results
@ -21,16 +21,14 @@
# Go Search Engine # Go Search Engine
A self-hosted aggregate search engine that respects privacy, contains no ads, and serves as a proxy to Google website. A self-hosted aggregate search engine that respects privacy, contains no ads, and serves as a proxy/alternative to Google website.
## Features ## Features
- Image search using the Qwant API.
- Text search using Google search results. - Text search using Google search results.
- Responsive web interface for displaying search results with previews. - Image search using the Qwant API.
- Video search using Piped API.
- Image viewing using proxy and direct links to image source pages for image searches. - Image viewing using proxy and direct links to image source pages for image searches.
- Display of text search results with links to source content.
## Getting Started ## Getting Started
@ -43,8 +41,9 @@ A self-hosted aggregate search engine that respects privacy, contains no ads, an
```bash ```bash
git clone https://weforgecode.xyz/Spitfire/Search.git git clone https://weforgecode.xyz/Spitfire/Search.git
cd search cd Search
go run main.go text.go images.go imageproxy.go chmod +x ./run.sh
./run.sh
``` ```
## Project Structure ## Project Structure
@ -55,7 +54,9 @@ go run main.go text.go images.go imageproxy.go
- `imageproxy.go`: Part of images.go srach logic, handles image reuslts and displays them using proxy. - `imageproxy.go`: Part of images.go srach logic, handles image reuslts and displays them using proxy.
- `/templates`: Directory containing HTML templates for rendering the search interface and results. - `/templates`: Directory containing HTML templates for rendering the search interface and results.
- `search.html`: The main search page template. - `search.html`: The main search page template.
- `text.html`: Template for displaying text search results.
- `images.html`: Template for displaying image search results. - `images.html`: Template for displaying image search results.
- `text.html`: (If applicable) Template for displaying text search results. - `videos.html`: Template for displaying video search results.
- `/static/css`: Directory for CSS stylesheets. - `/static/css`: Directory for CSS stylesheets.
- `style.css`: The main stylesheet for the search interface and results. - `style.css`: The main stylesheet for the search interface and results.
- `/static/css`: Directory for fonts and icons (as font).

14
main.go
View file

@ -63,18 +63,14 @@ var languageOptions = []LanguageOption{
{Code: "lang_vi", Name: "Tiếng Việt (Vietnamese)"}, {Code: "lang_vi", Name: "Tiếng Việt (Vietnamese)"},
} }
// var funcs = template.FuncMap{
// "title": func(s string) string { return strings.Title(s) },
// "url_for": func(filename string) string { return "/" + filename },
// }
// var templates = template.Must(template.New("").Funcs(funcs).ParseFiles("templates/results.html"))
func main() { func main() {
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
http.HandleFunc("/", handleSearch) http.HandleFunc("/", handleSearch)
http.HandleFunc("/search", handleSearch) http.HandleFunc("/search", handleSearch)
http.HandleFunc("/img_proxy", handleImageProxy) http.HandleFunc("/img_proxy", handleImageProxy)
http.HandleFunc("/settings", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "templates/settings.html")
})
fmt.Println("Server is listening on http://localhost:5000") fmt.Println("Server is listening on http://localhost:5000")
log.Fatal(http.ListenAndServe(":5000", nil)) log.Fatal(http.ListenAndServe(":5000", nil))
} }
@ -102,7 +98,7 @@ func handleSearch(w http.ResponseWriter, r *http.Request) {
} }
if query == "" { if query == "" {
http.ServeFile(w, r, "static/search.html") http.ServeFile(w, r, "templates/search.html")
return return
} }
@ -114,6 +110,6 @@ func handleSearch(w http.ResponseWriter, r *http.Request) {
case "video": case "video":
videoSearchEndpointHandler(w, r) videoSearchEndpointHandler(w, r)
default: default:
http.ServeFile(w, r, "static/search.html") http.ServeFile(w, r, "templates/search.html")
} }
} }

2
run.sh
View file

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
go run main.go text.go images.go imageproxy.go video.go $ go run main.go text-google.go images.go imageproxy.go video.go

View file

@ -1150,7 +1150,7 @@ p {
background-color: inherit; background-color: inherit;
font-size: 14px; font-size: 14px;
font-family: 'Inter'; font-family: 'Inter';
margin-right: 14px; margin-right: 10px;
color: var(--search-button); color: var(--search-button);
margin-top: 72px; margin-top: 72px;
padding-bottom: 11px; padding-bottom: 11px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,28 +0,0 @@
{% extends "results_layout.html" %}
{% block body %}
<p class="fetched fetched_dif fetched_vid">{{ lang_data.results.results }} {{ fetched }} {{ lang_data.results.seconds }}</p>
{% if results %}
{% for result in results %}
<div><div class="video__results">
<div class="video__img__results">
<a href="{{ result[0] }}"> <img src="{{ result[6] }}">
<div class="duration">{{ result[7] }}</div>
</img></a>
</div>
<div class="results video-results-margin">
<a {% if settings.new_tab == "active" %} target="_blank" {% endif %} href="{{ result[0] }}"><h3 class="video_title" href="{{ result[0] }}">{{ result[1] }}</h3></a>
<p class="stats">{{ result[3] }} • {{ result[2] }}</p>
<p class="publish__info">{{ result[5] }} <span class="pipe">|</span> {{ result[4] }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="no-results-found">
Your search '{{ q }}' came back with no results.<br>
Try rephrasing your search term and/or recorrect any spelling mistakes.
</div>
{% endif %}
{% endblock %}

View file

@ -8,14 +8,14 @@
</head> </head>
<body> <body>
<div class="settings-search-div settings-search-div-search"> <div class="settings-search-div settings-search-div-search">
<!-- Assuming you have specific styles for this in your CSS --> <a id="openSettings" class="material-symbols-outlined" href="/settings">tune</a>
</div> </div>
<form action="/search" class="search-container" method="post" autocomplete="off"> <form action="/search" class="search-container" method="post" autocomplete="off">
<h1>Ocásek</h1> <h1>Ocásek</h1>
<div class="wrapper"> <div class="wrapper">
<input type="text" name="q" autofocus id="search-input" placeholder="Type to search..." /> <input type="text" name="q" autofocus id="search-input" placeholder="Type to search..." />
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="text" type="submit">search</button> <button id="search-wrapper-ico" class="material-icons-round" name="t" value="text" type="submit">search</button>
<a id="clearSearch" class="material-icons-round">close</a> <a id="clearSearch" class="material-symbols-outline">close</a>
</div> </div>
<div class="search-button-wrapper"> <div class="search-button-wrapper">
<input type="hidden" name="p" value="1"> <input type="hidden" name="p" value="1">

70
templates/settings.html Normal file
View file

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Settings</title>
<link rel="stylesheet" type="text/css" href="static/css/style.css">
</head>
<body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off">
<h1 class="logomobile"><a class="no-decoration" href="./">Ocásek</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input" placeholder="Type to search..." />
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="text">search</button>
<input type="submit" class="hide" name="t" value="text" />
</div>
<div class="sub-search-button-wrapper">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button>
<button name="t" value="text" class="clickable">Web</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button>
<button name="t" value="image" class="clickable">Images</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button>
<button name="t" value="video" class="clickable">Videos</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="reddit">forum</button>
<button name="t" value="forum" class="clickable">Forums</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="torrent">share</button>
<button name="t" value="torrent" class="clickable">Torrents</button>
</div>
</div>
</div>
</form>
<div class="results_settings">
<form>
<h1>Settings</h1>
<h2>Theme</h2>
<label for="theme-dark">Dark Theme:</label>
<input type="checkbox" class="results-settings" id="theme-dark" name="theme" value="dark"><br>
<h2>Language</h2>
<label for="ui-language">UI Language:</label>
<select id="ui-language" class="results-settings" name="ui_language">
<option value="english">English</option>
<option value="deutsch">Deutsch</option>
</select><br>
<label for="search-language">Search Language:</label>
<select id="search-language" class="results-settings" name="search_language">
<option value="english">English</option>
<option value="deutsch">Deutsch</option>
</select>
<h2>Privacy</h2>
<label for="theme-dark">Use JavaScript:</label>
<input type="checkbox" class="results-settings" id="theme-dark" name="theme" value="dark"><br>
<label for="theme-dark">Use search suggestions:</label>
<input type="checkbox" class="results-settings" id="theme-dark" name="theme" value="dark"><br><br>
<input type="submit" class="results-settings" value="Save">
</form>
<div>
</body>
</html>

113
text-google.go Normal file
View file

@ -0,0 +1,113 @@
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
type TextSearchResult struct {
URL string
Header string
Description string
}
func PerformTextSearch(query, safe, lang string) ([]TextSearchResult, error) {
var results []TextSearchResult
client := &http.Client{}
safeParam := "&safe=off"
if safe == "active" {
safeParam = "&safe=active"
}
langParam := ""
if lang != "" {
langParam = "&lr=" + lang
}
searchURL := "https://www.google.com/search?q=" + url.QueryEscape(query) + safeParam + langParam
req, err := http.NewRequest("GET", searchURL, nil)
if err != nil {
log.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, err
}
doc.Find(".yuRUbf").Each(func(i int, s *goquery.Selection) {
link := s.Find("a")
href, _ := link.Attr("href")
header := link.Find("h3").Text()
header = strings.TrimSpace(strings.TrimSuffix(header, ""))
descSelection := doc.Find(".VwiC3b").Eq(i)
description := ""
if descSelection.Length() > 0 {
description = descSelection.Text()
}
results = append(results, TextSearchResult{
URL: href,
Header: header,
Description: description,
})
})
return results, nil
}
func handleTextSearch(w http.ResponseWriter, query, safe, lang string) {
// Perform the text search
results, err := PerformTextSearch(query, safe, lang)
if err != nil {
log.Printf("Error performing text search: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// Assuming you have a separate template for text search results
tmpl, err := template.ParseFiles("templates/text.html") // Ensure this path matches your templates' location
if err != nil {
log.Printf("Error parsing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
data := struct {
Results []TextSearchResult // Ensure this type matches the structure expected by your template
Query string
Fetched string
LanguageOptions []LanguageOption
CurrentLang string
}{
Results: results,
Query: query,
Fetched: fmt.Sprintf("%.2f seconds", time.Since(time.Now()).Seconds()), // Example fetched time, adjust as necessary
LanguageOptions: languageOptions, // Assuming this is defined globally or elsewhere
CurrentLang: lang,
}
err = tmpl.Execute(w, data)
if err != nil {
log.Printf("Error executing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}

113
text.go
View file

@ -1,113 +0,0 @@
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
type TextSearchResult struct {
URL string
Header string
Description string
}
func PerformTextSearch(query, safe, lang string) ([]TextSearchResult, error) {
var results []TextSearchResult
client := &http.Client{}
safeParam := "&safe=off"
if safe == "active" {
safeParam = "&safe=active"
}
langParam := ""
if lang != "" {
langParam = "&lr=" + lang
}
searchURL := "https://www.google.com/search?q=" + url.QueryEscape(query) + safeParam + langParam
req, err := http.NewRequest("GET", searchURL, nil)
if err != nil {
log.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, err
}
doc.Find(".yuRUbf").Each(func(i int, s *goquery.Selection) {
link := s.Find("a")
href, _ := link.Attr("href")
header := link.Find("h3").Text()
header = strings.TrimSpace(strings.TrimSuffix(header, ""))
descSelection := doc.Find(".VwiC3b").Eq(i)
description := ""
if descSelection.Length() > 0 {
description = descSelection.Text()
}
results = append(results, TextSearchResult{
URL: href,
Header: header,
Description: description,
})
})
return results, nil
}
func handleTextSearch(w http.ResponseWriter, query, safe, lang string) {
// Perform the text search
results, err := PerformTextSearch(query, safe, lang)
if err != nil {
log.Printf("Error performing text search: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// Assuming you have a separate template for text search results
tmpl, err := template.ParseFiles("templates/results.html") // Ensure this path matches your templates' location
if err != nil {
log.Printf("Error parsing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
data := struct {
Results []TextSearchResult // Ensure this type matches the structure expected by your template
Query string
Fetched string
LanguageOptions []LanguageOption
CurrentLang string
}{
Results: results,
Query: query,
Fetched: fmt.Sprintf("%.2f seconds", time.Since(time.Now()).Seconds()), // Example fetched time, adjust as necessary
LanguageOptions: languageOptions, // Assuming this is defined globally or elsewhere
CurrentLang: lang,
}
err = tmpl.Execute(w, data)
if err != nil {
log.Printf("Error executing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}