added lang support to all html templates and cleaned up template rendering

This commit is contained in:
partisan 2024-10-08 22:11:06 +02:00
parent 5dd3114e2d
commit d9d0301548
18 changed files with 645 additions and 410 deletions

View file

@ -3,7 +3,9 @@ package main
import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"html/template"
"net/http"
"strings"
)
@ -15,9 +17,35 @@ var (
"add": func(a, b int) int {
return a + b
},
"translate": Translate,
"toJSON": func(v interface{}) (string, error) {
jsonBytes, err := json.Marshal(v)
if err != nil {
return "", err
}
return string(jsonBytes), nil
},
}
)
// Helper function to render templates without elapsed time measurement
func renderTemplate(w http.ResponseWriter, tmplName string, data map[string]interface{}) {
// Parse the template with common functions (including translate)
tmpl, err := template.New(tmplName).Funcs(funcs).ParseFiles("templates/" + tmplName)
if err != nil {
printErr("Error parsing template: %v", err)
http.Error(w, Translate("internal_server_error"), http.StatusInternalServerError)
return
}
// Execute the template
err = tmpl.Execute(w, data)
if err != nil {
printErr("Error executing template: %v", err)
http.Error(w, Translate("internal_server_error"), http.StatusInternalServerError)
}
}
func generateStrongRandomString(length int) string {
bytes := make([]byte, length)
_, err := rand.Read(bytes)

View file

@ -2,7 +2,6 @@ package main
import (
"fmt"
"html/template"
"net/http"
"net/url"
"regexp"
@ -44,59 +43,30 @@ func handleFileSearch(w http.ResponseWriter, settings UserSettings, query string
cacheKey := CacheKey{Query: query, Page: page, Safe: settings.SafeSearch == "active", Lang: settings.SearchLanguage, Type: "file"}
combinedResults := getFileResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page)
// Sort the results by the number of seeders
sort.Slice(combinedResults, func(i, j int) bool { return combinedResults[i].Seeders > combinedResults[j].Seeders })
elapsedTime := time.Since(startTime)
funcMap := template.FuncMap{
"sub": func(a, b int) int { return a - b },
"add": func(a, b int) int { return a + b },
}
tmpl, err := template.New("files.html").Funcs(funcMap).ParseFiles("templates/files.html")
if err != nil {
printErr("Failed to load template: %v", err)
http.Error(w, "Failed to load template", http.StatusInternalServerError)
return
// Prepare the data to pass to the template
data := map[string]interface{}{
"Results": combinedResults,
"Query": query,
"Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")), // Time for fetching results
"Category": "all",
"Sort": "seed",
"Page": page,
"HasPrevPage": page > 1,
"HasNextPage": len(combinedResults) > 0,
"LanguageOptions": languageOptions,
"CurrentLang": settings.SearchLanguage,
"Theme": settings.Theme,
"Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark,
}
data := struct {
Results []TorrentResult
Query string
Fetched string
Category string
Sort string
Page int
HasPrevPage bool
HasNextPage bool
LanguageOptions []LanguageOption
CurrentLang string
Theme string
Safe string
IsThemeDark bool
}{
Results: combinedResults,
Query: query,
Fetched: fmt.Sprintf("%.2f seconds", elapsedTime.Seconds()),
Category: "all",
Sort: "seed",
Page: page,
HasPrevPage: page > 1,
HasNextPage: len(combinedResults) > 0,
LanguageOptions: languageOptions,
CurrentLang: settings.SearchLanguage,
Theme: settings.Theme,
Safe: settings.SafeSearch,
IsThemeDark: settings.IsThemeDark,
}
// // Debugging: Print results before rendering template
// for _, result := range combinedResults {
// fmt.Printf("Title: %s, Magnet: %s\n", result.Title, result.Magnet)
// }
if err := tmpl.Execute(w, data); err != nil {
printErr("Failed to render template: %v", err)
http.Error(w, "Failed to render template", http.StatusInternalServerError)
}
// Render the template without measuring the time
renderTemplate(w, "files.html", data)
}
func getFileResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TorrentResult {

View file

@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"fmt"
"html/template"
"log"
"math"
"net/http"
@ -99,48 +98,34 @@ func PerformRedditSearch(query string, safe string, page int) ([]ForumSearchResu
}
func handleForumsSearch(w http.ResponseWriter, settings UserSettings, query string, page int) {
// Start measuring the time for fetching results
startTime := time.Now()
// Perform the forum search
results, err := PerformRedditSearch(query, settings.SafeSearch, page)
if err != nil || len(results) == 0 { // 0 == 0 to force search by other node
if err != nil || len(results) == 0 {
log.Printf("No results from primary search, trying other nodes")
results = tryOtherNodesForForumSearch(query, settings.SafeSearch, settings.SearchLanguage, page)
}
data := struct {
Query string
Results []ForumSearchResult
Page int
HasPrevPage bool
HasNextPage bool
LanguageOptions []LanguageOption
CurrentLang string
Theme string
Safe string
IsThemeDark bool
}{
Query: query,
Results: results,
Page: page,
HasPrevPage: page > 1,
HasNextPage: len(results) == 25,
LanguageOptions: languageOptions,
CurrentLang: settings.SearchLanguage,
Theme: settings.Theme,
Safe: settings.SafeSearch,
IsThemeDark: settings.IsThemeDark,
// Measure the elapsed time for fetching results
elapsedTime := time.Since(startTime)
// Prepare the data to pass to the template
data := map[string]interface{}{
"Query": query,
"Results": results,
"Page": page,
"Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")), // Time for fetching results
"HasPrevPage": page > 1,
"HasNextPage": len(results) == 25, // Assuming 25 results per page
"LanguageOptions": languageOptions,
"CurrentLang": settings.SearchLanguage,
"Theme": settings.Theme,
"Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark,
}
funcMap := template.FuncMap{
"sub": func(a, b int) int { return a - b },
"add": func(a, b int) int { return a + b },
}
tmpl, err := template.New("forums.html").Funcs(funcMap).ParseFiles("templates/forums.html")
if err != nil {
http.Error(w, fmt.Sprintf("Error loading template: %v", err), http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, data); err != nil {
http.Error(w, fmt.Sprintf("Error rendering template: %v", err), http.StatusInternalServerError)
}
// Render the template without measuring the time
renderTemplate(w, "forums.html", data)
}

View file

@ -2,8 +2,6 @@ package main
import (
"fmt"
"html/template"
"log"
"net/http"
"time"
)
@ -26,46 +24,25 @@ func handleImageSearch(w http.ResponseWriter, settings UserSettings, query strin
combinedResults := getImageResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page)
elapsedTime := time.Since(startTime)
tmpl, err := template.New("images.html").Funcs(funcs).ParseFiles("templates/images.html")
if err != nil {
log.Printf("Error parsing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
// Prepare the data to pass to the template
data := map[string]interface{}{
"Results": combinedResults,
"Query": query,
"Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")), // Time for fetching
"Page": page,
"HasPrevPage": page > 1,
"HasNextPage": len(combinedResults) >= 50,
"NoResults": len(combinedResults) == 0,
"LanguageOptions": languageOptions,
"CurrentLang": settings.SearchLanguage,
"Theme": settings.Theme,
"Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark,
}
data := struct {
Results []ImageSearchResult
Query string
Page int
Fetched string
HasPrevPage bool
HasNextPage bool
NoResults bool
LanguageOptions []LanguageOption
CurrentLang string
Theme string
Safe string
IsThemeDark bool
}{
Results: combinedResults,
Query: query,
Page: page,
Fetched: fmt.Sprintf("%.2f seconds", elapsedTime.Seconds()),
HasPrevPage: page > 1,
HasNextPage: len(combinedResults) >= 50,
NoResults: len(combinedResults) == 0,
LanguageOptions: languageOptions,
CurrentLang: settings.SearchLanguage,
Theme: settings.Theme,
Safe: settings.SafeSearch,
IsThemeDark: settings.IsThemeDark,
}
err = tmpl.Execute(w, data)
if err != nil {
printErr("Error executing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
// Render the template without measuring the time
renderTemplate(w, "images.html", data)
}
func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []ImageSearchResult {

View file

@ -1,4 +1,3 @@
msgid "settings_title"
msgstr "Settings"
@ -29,10 +28,10 @@ msgstr "Latte"
msgid "safe_search"
msgstr "Safe Search"
msgid "safe_search_off"
msgid "off"
msgstr "Off"
msgid "safe_search_on"
msgid "on"
msgstr "On"
msgid "site_language"
@ -41,5 +40,152 @@ msgstr "Site Language"
msgid "search_language"
msgstr "Search Language"
msgid "no_results"
msgstr "No results found for '%s'. Try different keywords."
msgid "no_more_results"
msgstr "Looks like this is the end of results."
msgid "safe_search_off"
msgstr "Safe Search Off"
msgid "safe_search_on"
msgstr "Safe Search On"
msgid "save_settings"
msgstr "Save Settings"
msgstr "Save settings"
msgid "page_title"
msgstr "Search results for '%s'"
msgid "site_name"
msgstr "Ocásek"
msgid "search"
msgstr "Search"
msgid "web"
msgstr "Web"
msgid "image"
msgstr "Image"
msgid "images"
msgstr "Images"
msgid "video"
msgstr "Video"
msgid "videos"
msgstr "Videos"
msgid "forum"
msgstr "Forum"
msgid "forums"
msgstr "Forums"
msgid "map"
msgstr "Map"
msgid "maps"
msgstr "Maps"
msgid "file"
msgstr "File"
msgid "torrents"
msgstr "Torrents"
msgid "searching_for_new_results"
msgstr "Searching for new results..."
msgid "previous"
msgstr "Previous"
msgid "next"
msgstr "Next"
msgid "fetched_in"
msgstr "Fetched in %s seconds"
msgid "sort_seeders"
msgstr "Number of Seeders"
msgid "sort_leechers"
msgstr "Number of Leechers"
msgid "sort_lth"
msgstr "Size (Low to High)"
msgid "sort_htl"
msgstr "Size (High to Low)"
msgid "category_all"
msgstr "All Categories"
msgid "category_movie"
msgstr "Movies"
msgid "category_audiobook"
msgstr "Audiobooks"
msgid "category_tv"
msgstr "TV Shows"
msgid "category_games"
msgstr "Games"
msgid "category_software"
msgstr "Software"
msgid "category_anime"
msgstr "Anime"
msgid "category_music"
msgstr "Music"
msgid "category_xxx"
msgstr "XXX (18+)"
msgid "apply_settings"
msgstr "Apply settings"
msgid "error"
msgstr "Error"
msgid "views"
msgstr "views"
msgid "seeders"
msgstr "Seeders"
msgid "leechers"
msgstr "Leechers"
msgid "no_results_found"
msgstr "Your search '%s' came back with no results."
msgid "suggest_rephrase"
msgstr "Try rephrasing your search term and/or correct any spelling mistakes."
msgid "streets"
msgstr "Streets"
msgid "satellite"
msgstr "Satellite"
msgid "esri_satellite"
msgstr "Esri Satellite"
msgid "topographic"
msgstr "Topographic"
msgid "locate_me"
msgstr "Locate Me"
msgid "you_are_within"
msgstr "You are within "
msgid "meters_from_point"
msgstr "meters from this point"

View file

@ -1,4 +1,3 @@
msgid "settings_title"
msgstr "Ustawienia"
@ -29,17 +28,164 @@ msgstr "Latte"
msgid "safe_search"
msgstr "Bezpieczne wyszukiwanie"
msgid "safe_search_off"
msgid "off"
msgstr "Wyłączone"
msgid "safe_search_on"
msgid "on"
msgstr "Włączone"
msgid "site_language"
msgstr "Język witryny"
msgstr "Język strony"
msgid "search_language"
msgstr "Język wyszukiwania"
msgid "no_results"
msgstr "Nie znaleziono wyników dla '%s'. Spróbuj innych słów kluczowych."
msgid "no_more_results"
msgstr "Wygląda na to, że to koniec wyników."
msgid "safe_search_off"
msgstr "Wyłączony filtr"
msgid "safe_search_on"
msgstr "Włączony filtr"
msgid "save_settings"
msgstr "Zapisz ustawienia"
msgid "page_title"
msgstr "Wyniki wyszukiwania dla '%s'"
msgid "site_name"
msgstr "Ocásek"
msgid "search"
msgstr "Szukaj"
msgid "web"
msgstr "Strona"
msgid "image"
msgstr "Obraz"
msgid "images"
msgstr "Obrazy"
msgid "video"
msgstr "Wideo"
msgid "videos"
msgstr "Wideo"
msgid "forum"
msgstr "Forum"
msgid "forums"
msgstr "Fora"
msgid "map"
msgstr "Mapa"
msgid "maps"
msgstr "Mapy"
msgid "file"
msgstr "Plik"
msgid "torrents"
msgstr "Torrenty"
msgid "searching_for_new_results"
msgstr "Wyszukiwanie nowych wyników..."
msgid "previous"
msgstr "Poprzednie"
msgid "next"
msgstr "Następne"
msgid "fetched_in"
msgstr "Pobrano w %s sekund"
msgid "sort_seeders"
msgstr "Liczba seedów"
msgid "sort_leechers"
msgstr "Liczba leechów"
msgid "sort_lth"
msgstr "Rozmiar (od najmniejszego)"
msgid "sort_htl"
msgstr "Rozmiar (od największego)"
msgid "category_all"
msgstr "Wszystkie kategorie"
msgid "category_movie"
msgstr "Filmy"
msgid "category_audiobook"
msgstr "Audiobooki"
msgid "category_tv"
msgstr "Seriale TV"
msgid "category_games"
msgstr "Gry"
msgid "category_software"
msgstr "Oprogramowanie"
msgid "category_anime"
msgstr "Anime"
msgid "category_music"
msgstr "Muzyka"
msgid "category_xxx"
msgstr "XXX (18+)"
msgid "apply_settings"
msgstr "Zastosuj ustawienia"
msgid "error"
msgstr "Błąd"
msgid "views"
msgstr "Wyświetlenia"
msgid "seeders"
msgstr "Seedy"
msgid "leechers"
msgstr "Leechy"
msgid "no_results_found"
msgstr "Twoje wyszukiwanie '%s' nie zwróciło żadnych wyników."
msgid "suggest_rephrase"
msgstr "Spróbuj zmienić zapytanie lub poprawić błędy ortograficzne."
msgid "streets"
msgstr "Ulice"
msgid "satellite"
msgstr "Satelita"
msgid "esri_satellite"
msgstr "Esri Satelita"
msgid "topographic"
msgstr "Topograficzna"
msgid "locate_me"
msgstr "Zlokalizuj mnie"
msgid "you_are_within"
msgstr "Znajdujesz się w odległości "
msgid "meters_from_point"
msgstr "metrów od tego punktu"

18
main.go
View file

@ -126,11 +126,25 @@ func handleSearch(w http.ResponseWriter, r *http.Request) {
IsThemeDark: settings.IsThemeDark,
}
tmpl := template.Must(template.ParseFiles("templates/search.html"))
tmpl.Execute(w, data)
// 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, settings, query, page)

23
map.go
View file

@ -3,9 +3,9 @@ package main
import (
"encoding/json"
"fmt"
"html/template"
"net/http"
"net/url"
"time"
)
type NominatimResponse struct {
@ -44,31 +44,32 @@ func geocodeQuery(query string) (latitude, longitude string, found bool, err err
}
func handleMapSearch(w http.ResponseWriter, settings UserSettings, query string) {
// Start measuring the time for geocoding the query
startTime := time.Now()
// Geocode the query to get coordinates
latitude, longitude, found, err := geocodeQuery(query)
if err != nil {
printDebug("Error geocoding query: %s, error: %v", query, err)
http.Error(w, "Failed to find location", http.StatusInternalServerError)
http.Error(w, Translate("internal_server_error"), http.StatusInternalServerError)
return
}
// Use a template to serve the map page
// Measure the elapsed time for geocoding
elapsedTime := time.Since(startTime)
// Prepare the data to pass to the template
data := map[string]interface{}{
"Query": query,
"Latitude": latitude,
"Longitude": longitude,
"Found": found,
"Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")),
"Theme": settings.Theme,
"Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark,
}
tmpl, err := template.ParseFiles("templates/map.html")
if err != nil {
printErr("Error loading map template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
tmpl.Execute(w, data)
// Render the template
renderTemplate(w, "map.html", data)
}

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>{{.Query}} - Ocásek</title>
<title>{{ translate "page_title" .Query }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
</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>
<h1 class="logomobile"><a class="no-decoration" href="./">{{ translate "site_name" }}</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="file">search</button>
@ -26,70 +26,70 @@
<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>
<button name="t" value="text" class="clickable">{{ translate "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>
<button name="t" value="image" class="clickable">{{ translate "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>
<button name="t" value="video" class="clickable">{{ translate "videos" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
<button name="t" value="forum" class="clickable">Forums</button>
<button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
</div>
<div id="content" class="js-enabled">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
<button name="t" value="map" class="clickable">Maps</button>
<button name="t" value="map" class="clickable">{{ translate "maps" }}</button>
</div>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="file">share</button>
<button name="t" value="file" class="clickable search-active">Torrents</button>
<button name="t" value="file" class="clickable search-active">{{ translate "torrents" }}</button>
</div>
</div>
</form>
<p class="fetched fetched_dif fetched_tor">Fetched in {{ .Fetched }} seconds</p>
<p class="fetched fetched_dif fetched_tor">{{ translate "fetched_in" .Fetched }}</p>
{{ if .Results }}
<form action="/search" class="torrent-sort" method="GET">
<input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="file">
<select class="torrent-settings" name="sort">
<option value="seed" {{ if eq .Sort "seed" }} selected {{ end }}>Number of Seeders</option>
<option value="leech" {{ if eq .Sort "leech" }} selected {{ end }}>Number of Leechers</option>
<option value="lth" {{ if eq .Sort "lth" }} selected {{ end }}>Size (Low to High)</option>
<option value="htl" {{ if eq .Sort "htl" }} selected {{ end }}>Size (High to Low)</option>
<option value="seed" {{ if eq .Sort "seed" }} selected {{ end }}>{{ translate "sort_seeders" }}</option>
<option value="leech" {{ if eq .Sort "leech" }} selected {{ end }}>{{ translate "sort_leechers" }}</option>
<option value="lth" {{ if eq .Sort "lth" }} selected {{ end }}>{{ translate "sort_lth" }}</option>
<option value="htl" {{ if eq .Sort "htl" }} selected {{ end }}>{{ translate "sort_htl" }}</option>
</select>
<select class="torrent-cat" name="cat">
<option value="all" {{ if eq .Category "all" }} selected {{ end }}>All Categories</option>
<option value="movie" {{ if eq .Category "movie" }} selected {{ end }}>Movies</option>
<option value="audiobook" {{ if eq .Category "audiobook" }} selected {{ end }}>Audiobooks</option>
<option value="tv" {{ if eq .Category "tv" }} selected {{ end }}>TV Shows</option>
<option value="games" {{ if eq .Category "games" }} selected {{ end }}>Games</option>
<option value="software" {{ if eq .Category "software" }} selected {{ end }}>Software</option>
<option value="anime" {{ if eq .Category "anime" }} selected {{ end }}>Anime</option>
<option value="music" {{ if eq .Category "music" }} selected {{ end }}>Music</option>
<option value="all" {{ if eq .Category "all" }} selected {{ end }}>{{ translate "category_all" }}</option>
<option value="movie" {{ if eq .Category "movie" }} selected {{ end }}>{{ translate "category_movie" }}</option>
<option value="audiobook" {{ if eq .Category "audiobook" }} selected {{ end }}>{{ translate "category_audiobook" }}</option>
<option value="tv" {{ if eq .Category "tv" }} selected {{ end }}>{{ translate "category_tv" }}</option>
<option value="games" {{ if eq .Category "games" }} selected {{ end }}>{{ translate "category_games" }}</option>
<option value="software" {{ if eq .Category "software" }} selected {{ end }}>{{ translate "category_software" }}</option>
<option value="anime" {{ if eq .Category "anime" }} selected {{ end }}>{{ translate "category_anime" }}</option>
<option value="music" {{ if eq .Category "music" }} selected {{ end }}>{{ translate "category_music" }}</option>
{{ if eq .Safe "disabled" }}
<option value="xxx" {{ if eq .Category "xxx" }} selected {{ end }}>XXX (18+)</option>
<option value="xxx" {{ if eq .Category "xxx" }} selected {{ end }}>{{ translate "category_xxx" }}</option>
{{ end }}
</select>
<button type="submit" class="torrent-sort-save">Apply settings</button>
<button type="submit" class="torrent-sort-save">{{ translate "apply_settings" }}</button>
</form>
<div class="clean">
{{ range .Results }}
<div class="results" id="results">
{{ if .Error }}
<div class="error">{{ .Error }}</div>
<div class="error">{{ translate "error" }}: {{ .Error }}</div>
{{ else }}
<a id="link" href="{{ .URL }}">{{ .URL }}</a>
<a class="torrent" href="magnet:{{ .Magnet }}"><h3>{{ .Title }}</h3></a>
<p class="stats">{{ if .Views }}{{ .Views }} views • {{ end }}{{ .Size }}</p>
<p class="publish__info"> Seeders: <span class="seeders">{{ .Seeders }}</span> | Leechers: <span class="leechers">{{ .Leechers }}</span></p>
<p class="stats">{{ if .Views }}{{ .Views }} {{ translate "views" }} • {{ end }}{{ .Size }}</p>
<p class="publish__info">{{ translate "seeders" }}: <span class="seeders">{{ .Seeders }}</span> | {{ translate "leechers" }}: <span class="leechers">{{ .Leechers }}</span></p>
{{ end }}
</div>
{{ end }}
@ -99,17 +99,17 @@
<input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="file">
{{ if .HasPrevPage }}
<button type="submit" name="p" value="{{ sub .Page 1 }}">Previous</button>
<button type="submit" name="p" value="{{ sub .Page 1 }}">{{ translate "previous" }}</button>
{{ end }}
{{ if .HasNextPage }}
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
<button type="submit" name="p" value="{{ add .Page 1 }}">{{ translate "next" }}</button>
{{ end }}
</form>
</div>
{{ else }}
<div class="no-results-found">
Your search '{{ .Query }}' came back with no results.<br>
Try rephrasing your search term and/or recorrect any spelling mistakes.
{{ translate "no_results_found" .Query }}<br>
{{ translate "suggest_rephrase" }}
</div>
{{ end }}
<script defer src="/static/js/autocomplete.js"></script>

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>{{.Query}} - Ocásek</title>
<title>{{ translate "page_title" .Query }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
</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>
<h1 class="logomobile"><a class="no-decoration" href="./">{{ translate "site_name" }}</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="forum">search</button>
@ -25,44 +25,44 @@
<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>
<button name="t" value="text" class="clickable">{{ translate "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>
<button name="t" value="image" class="clickable">{{ translate "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>
<button name="t" value="video" class="clickable">{{ translate "videos" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="forum">forum</button>
<button name="t" value="forum" class="clickable search-active">Forums</button>
<button name="t" value="forum" class="clickable search-active">{{ translate "forums" }}</button>
</div>
<div id="content" class="js-enabled">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
<button name="t" value="map" class="clickable">Maps</button>
<button name="t" value="map" class="clickable">{{ translate "maps" }}</button>
</div>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
<button name="t" value="file" class="clickable">Torrents</button>
<button name="t" value="file" class="clickable">{{ translate "torrents" }}</button>
</div>
</div>
</form>
<form class="results_settings" action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}">
<select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option>
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select>
<select class="results-settings" name="lang" id="languageSelect">
{{range .LanguageOptions}}
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option>
{{end}}
</select>
<button class="results-save" name="t" value="forum">Apply settings</button>
<button class="results-save" name="t" value="forum">{{ translate "save_settings" }}</button>
</form>
<div class="results" id="results">
{{if .Results}}
@ -75,13 +75,13 @@
<br>
{{end}}
{{else if .NoResults}}
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
<div class="no-results">{{ translate "no_results" .Query }}</div>
{{else}}
<div class="no-more-results">Looks like this is the end of results.</div>
<div class="no-more-results">{{ translate "no_more_results" }}</div>
{{end}}
</div>
<div class="message-bottom-left" id="message-bottom-left">
<span>Searching for new results...</span>
<span>{{ translate "searching_for_new_results" }}</span>
</div>
<div class="prev-next prev-img" id="prev-next">
<form action="/search" method="get">
@ -89,10 +89,10 @@
<input type="hidden" name="t" value="forum">
<div id="content" class="js-enabled">
{{ if .HasPrevPage }}
<button type="submit" name="p" value="{{ sub .Page 1 }}">Previous</button>
<button type="submit" name="p" value="{{ sub .Page 1 }}">{{ translate "previous" }}</button>
{{ end }}
{{ if .HasNextPage }}
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
<button type="submit" name="p" value="{{ add .Page 1 }}">{{ translate "next" }}</button>
{{ end }}
</div>
</form>

View file

@ -6,15 +6,15 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>{{.Query}} - Ocásek</title>
<title>{{ translate "page_title" .Query }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/style-fixedwidth.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
</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>
<h1 class="logomobile"><a class="no-decoration" href="./">{{ translate "site_name" }}</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="image">search</button>
@ -27,44 +27,44 @@
<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>
<button name="t" value="text" class="clickable">{{ translate "web" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="image">image</button>
<button name="t" value="image" class="clickable search-active">Images</button>
<button name="t" value="image" class="clickable search-active">{{ translate "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>
<button name="t" value="video" class="clickable">{{ translate "videos" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
<button name="t" value="forum" class="clickable">Forums</button>
<button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
</div>
<div id="content" class="js-enabled">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
<button name="t" value="map" class="clickable">Maps</button>
<button name="t" value="map" class="clickable">{{ translate "maps" }}</button>
</div>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
<button name="t" value="file" class="clickable">Torrents</button>
<button name="t" value="file" class="clickable">{{ translate "torrents" }}</button>
</div>
</div>
</form>
<form class="results_settings" action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}">
<select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option>
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select>
<select class="results-settings" name="lang" id="languageSelect">
{{range .LanguageOptions}}
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option>
{{end}}
</select>
<button class="results-save" name="t" value="image">Apply settings</button>
<button class="results-save" name="t" value="image">{{ translate "save_settings" }}</button>
</form>
<div class="search-results" id="results">
@ -78,7 +78,7 @@
<div class="resolution">{{ .Width }} × {{ .Height }}</div>
<div class="details">
<span class="img_title clickable">{{ .Title }}</span>
<a href="{{ .Source }}" target="_blank" class="img_source">Source</a>
<a href="{{ .Source }}" target="_blank" class="img_source">{{ translate "source" }}</a>
</div>
</div>
{{ end }}
@ -90,24 +90,22 @@
<input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="image">
{{ if .HasPrevPage }}
<!-- Subtract 1 from the current page for the Previous button -->
<button type="submit" name="p" value="{{ sub .Page 1 }}">Previous</button>
<button type="submit" name="p" value="{{ sub .Page 1 }}">{{ translate "previous" }}</button>
{{ end }}
{{ if .HasNextPage }}
<!-- Add 1 to the current page for the Next button -->
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
<button type="submit" name="p" value="{{ add .Page 1 }}">{{ translate "next" }}</button>
{{ end }}
</form>
</div>
</noscript>
{{ else if .NoResults }}
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
<div class="no-results">{{ translate "no_results" .Query }}</div>
{{ else }}
<div class="no-more-results">Looks like this is the end of results.</div>
<div class="no-more-results">{{ translate "no_more_results" }}</div>
{{ end }}
</div>
<div class="message-bottom-left" id="message-bottom-left">
<span>Searching for new results...</span>
<span>{{ translate "searching_for_new_results" }}</span>
</div>
<div id="image-viewer-overlay" style="display: none;"></div>

View file

@ -6,10 +6,10 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>{{ .Query }} - Ocásek</title>
<title>{{ translate "page_title" .Query }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css" />
<style>
@ -28,7 +28,7 @@
</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>
<h1 class="logomobile"><a class="no-decoration" href="./">{{ translate "site_name" }}</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="map">search</button>
@ -41,27 +41,27 @@
<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>
<button name="t" value="text" class="clickable">{{ translate "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>
<button name="t" value="image" class="clickable">{{ translate "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>
<button name="t" value="video" class="clickable">{{ translate "videos" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
<button name="t" value="forum" class="clickable">Forums</button>
<button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="map">map</button>
<button name="t" value="map" class="clickable search-active">Maps</button>
<button name="t" value="map" class="clickable search-active">{{ translate "maps" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
<button name="t" value="file" class="clickable">Torrents</button>
<button name="t" value="file" class="clickable">{{ translate "torrents" }}</button>
</div>
</div>
</form>
@ -69,7 +69,7 @@
<div id="map"></div>
{{ else }}
<div id="map"></div>
<div class="message">No results found for "{{ .Query }}". Please try another search.</div>
<div class="message">{{ translate "no_results" .Query }}</div>
{{ end }}
{{ if .Found }}
<script>
@ -98,10 +98,10 @@
});
var baseMaps = {
"Streets": streets,
"Satellite": satellite,
"Esri Satellite": esriSat,
"Topographic": topo
"{{ translate "streets" }}": streets,
"{{ translate "satellite" }}": satellite,
"{{ translate "esri_satellite" }}": esriSat,
"{{ translate "topographic" }}": topo
};
streets.addTo(map); // Add default layer
@ -120,7 +120,7 @@
L.Control.geolocate = L.Control.extend({
onAdd: function(map) {
var div = L.DomUtil.create('div', 'leaflet-control-locate');
div.title = 'Locate Me';
div.title = '{{ translate "locate_me" }}';
L.DomEvent.on(div, 'click', function() {
map.locate({setView: true, maxZoom: 16});
});
@ -138,7 +138,7 @@
function onLocationFound(e) {
var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map)
.bindPopup("You are within " + radius + " meters from this point").openPopup();
.bindPopup("{{ translate "you_are_within" }}" + radius + " {{ translate "meters_from_point" }}").openPopup();
L.circle(e.latlng, radius).addTo(map);
}

View file

@ -6,11 +6,11 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>Search with Ocásek</title>
<title>{{ translate "search_page_title" }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/style-search.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
</head>
<body>
<script defer src="/static/js/autocomplete.js"></script>
@ -70,19 +70,19 @@
<button class="material-icons-round clickable settings-icon-link settings-icon-link-search">menu</button>
</div>
<div class="search-menu settings-menu-hidden">
<h2>Settings</h2>
<h2>{{ translate "settings" }}</h2>
<div class="settings-content">
<button id="settingsButton" onclick="window.location.href='/settings'">All settings</button> <!-- Well its unessesary to use js here but this menu will not work without js anyway -->
<button id="settingsButton" onclick="window.location.href='/settings'">{{ translate "all_settings" }}</button> <!-- Well its unessesary to use js here but this menu will not work without js anyway -->
<div class="theme-settings theme-mini-settings">
<p><span class="highlight">Current theme: </span> <span id="theme_name">{{.Theme}}</span></p>
<p><span class="highlight">{{ translate "current_theme" }}: </span> <span id="theme_name">{{.Theme}}</span></p>
<div class="themes-settings-menu">
<div><img class="view-image-search clickable" id="dark_theme" alt="Dark Theme" src="/static/images/dark.webp"></div>
<div><img class="view-image-search clickable" id="light_theme" alt="Light Theme" src="/static/images/light.webp"></div>
<div><img class="view-image-search clickable" id="dark_theme" alt="{{ translate "dark_theme" }}" src="/static/images/dark.webp"></div>
<div><img class="view-image-search clickable" id="light_theme" alt="{{ translate "light_theme" }}" src="/static/images/light.webp"></div>
</div>
</div>
<select class="lang" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option>
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select>
<select class="lang" name="site_lang" id="siteLanguageSelect">
{{range .LanguageOptions}}
@ -93,9 +93,9 @@
</div>
<form action="/search" class="search-container" method="post" autocomplete="off">
<div class="search-page-content">
<h1>Ocásek</h1>
<h1>{{ translate "site_name" }}</h1>
<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="{{ translate "type_to_search" }}" -->
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="web" type="submit">search</button>
<div class="autocomplete">
<ul></ul>
@ -106,32 +106,32 @@
<div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button>
<p>Web</p>
<p>{{ translate "web" }}</p>
</div>
<div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button>
<p>Images</p>
<p>{{ translate "images" }}</p>
</div>
<div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button>
<p>Videos</p>
<p>{{ translate "videos" }}</p>
</div>
<div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
<p>Forums</p>
<p>{{ translate "forums" }}</p>
</div>
<div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
<p>Maps</p>
<p>{{ translate "maps" }}</p>
</div>
<div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
<p>Torrents</p>
<p>{{ translate "torrents" }}</p>
</div>
</div>
</div>

View file

@ -68,8 +68,8 @@
<div class="settings-row">
<p>{{ translate "safe_search" }}</p>
<select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "on" }}</option>
</select>
</div>

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>{{.Query}} - Ocásek</title>
<title>{{ translate "page_title" .Query }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
</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>
<h1 class="logomobile"><a class="no-decoration" href="./">{{ translate "site_name" }}</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="text">search</button>
@ -26,44 +26,44 @@
<div class="sub-search-button-wrapper">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="text">search</button>
<button name="t" value="text" class="clickable search-active">Web</button>
<button name="t" value="text" class="clickable search-active">{{ translate "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>
<button name="t" value="image" class="clickable">{{ translate "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>
<button name="t" value="video" class="clickable">{{ translate "videos" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
<button name="t" value="forum" class="clickable">Forums</button>
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">image</button>
<button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
</div>
<div id="content" class="js-enabled">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
<button name="t" value="map" class="clickable">Maps</button>
<button name="t" value="map" class="clickable">{{ translate "maps" }}</button>
</div>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
<button name="t" value="file" class="clickable">Torrents</button>
<button name="t" value="file" class="clickable">{{ translate "torrents" }}</button>
</div>
</div>
</form>
<form class="results_settings" action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}">
<select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option>
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select>
<select class="results-settings" name="lang" id="languageSelect">
{{range .LanguageOptions}}
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option>
{{end}}
</select>
<button class="results-save" name="t" value="text">Apply settings</button>
<button class="results-save" name="t" value="text">{{ translate "save_settings" }}</button>
</form>
<div class="results" id="results">
{{if .Results}}
@ -76,13 +76,13 @@
<br>
{{end}}
{{else if .NoResults}}
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
<div class="no-results">{{ translate "no_results" .Query }}</div>
{{else}}
<div class="no-more-results">Looks like this is the end of results.</div>
<div class="no-more-results">{{ translate "no_more_results" }}</div>
{{end}}
</div>
<div class="message-bottom-left" id="message-bottom-left">
<span>Searching for new results...</span>
<span>{{ translate "searching_for_new_results" }}</span>
</div>
<div class="prev-next prev-img" id="prev-next">
<form action="/search" method="get">
@ -90,10 +90,10 @@
<input type="hidden" name="t" value="text">
<div id="content" class="js-enabled">
{{ if .HasPrevPage }}
<button type="submit" name="p" value="{{ sub .Page 1 }}">Previous</button>
<button type="submit" name="p" value="{{ sub .Page 1 }}">{{ translate "previous" }}</button>
{{ end }}
{{ if .HasNextPage }}
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
<button type="submit" name="p" value="{{ add .Page 1 }}">{{ translate "next" }}</button>
{{ end }}
</div>
</form>

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }}
<meta name="darkreader-lock">
{{ end }}
<title>{{.Query}} - Ocásek</title>
<title>{{ translate "page_title" .Query }}</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.css">
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
<link rel="search" type="application/opensearchdescription+xml" title="{{ translate "site_name" }}" href="/opensearch.xml">
</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>
<h1 class="logomobile"><a class="no-decoration" href="./">{{ translate "site_name" }}</a></h1>
<div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/>
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="video">search</button>
@ -26,34 +26,34 @@
<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>
<button name="t" value="text" class="clickable">{{ translate "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>
<button name="t" value="image" class="clickable">{{ translate "images" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable search-active" name="t" value="video">movie</button>
<button name="t" value="video" class="clickable search-active">Videos</button>
<button name="t" value="video" class="clickable search-active">{{ translate "videos" }}</button>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button>
<button name="t" value="forum" class="clickable">Forums</button>
<button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
</div>
<div id="content" class="js-enabled">
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button>
<button name="t" value="map" class="clickable">Maps</button>
<button name="t" value="map" class="clickable">{{ translate "maps" }}</button>
</div>
</div>
<div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button>
<button name="t" value="file" class="clickable">Torrents</button>
<button name="t" value="file" class="clickable">{{ translate "torrents" }}</button>
</div>
</div>
</form>
<!-- Results go here -->
<p class="fetched fetched_dif fetched_vid"><!-- { fetched } --></p>
<p class="fetched fetched_dif fetched_vid">{{ translate "fetched_in" .Fetched }}</p>
{{ if .Results }}
{{ range .Results }}
<div>
@ -75,17 +75,17 @@
</div>
{{ end }}
{{ else }}
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
<div class="no-results">{{ translate "no_results" .Query }}</div>
{{ end }}
<div class="prev-next prev-img" id="prev-next">
<form action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="video">
{{ if .HasPrevPage }}
<button type="submit" name="p" value="{{ sub .Page 1 }}">Previous</button>
<button type="submit" name="p" value="{{ sub .Page 1 }}">{{ translate "previous" }}</button>
{{ end }}
{{ if .HasNextPage }}
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
<button type="submit" name="p" value="{{ add .Page 1 }}">{{ translate "next" }}</button>
{{ end }}
</form>
</div>

63
text.go
View file

@ -2,7 +2,6 @@ package main
import (
"fmt"
"html/template"
"net/http"
"time"
)
@ -25,57 +24,35 @@ func HandleTextSearch(w http.ResponseWriter, settings UserSettings, query string
cacheKey := CacheKey{Query: query, Page: page, Safe: settings.SafeSearch == "active", Lang: settings.SearchLanguage, Type: "text"}
combinedResults := getTextResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page)
hasPrevPage := page > 1 // dupe
hasPrevPage := page > 1
//displayResults(w, combinedResults, query, lang, time.Since(startTime).Seconds(), page, hasPrevPage, hasNextPage)
// Prefetch next and previous pages
// Prefetch next and previous pages asynchronously
go prefetchPage(query, settings.SafeSearch, settings.SearchLanguage, page+1)
if hasPrevPage {
go prefetchPage(query, settings.SafeSearch, settings.SearchLanguage, page-1)
}
elapsedTime := time.Since(startTime)
tmpl, err := template.New("text.html").Funcs(funcs).ParseFiles("templates/text.html")
if err != nil {
printErr("Error parsing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
// Prepare the data to pass to the template
data := map[string]interface{}{
"Results": combinedResults,
"Query": query,
"Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")), // Time for fetching results
"Page": page,
"HasPrevPage": page > 1,
"HasNextPage": len(combinedResults) >= 50,
"NoResults": len(combinedResults) == 0,
"LanguageOptions": languageOptions,
"CurrentLang": settings.SearchLanguage,
"Theme": settings.Theme,
"Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark,
"Trans": Translate,
}
data := struct {
Results []TextSearchResult
Query string
Page int
Fetched string
HasPrevPage bool
HasNextPage bool
NoResults bool
LanguageOptions []LanguageOption
CurrentLang string
Theme string
Safe string
IsThemeDark bool
}{
Results: combinedResults,
Query: query,
Page: page,
Fetched: fmt.Sprintf("%.2f seconds", elapsedTime.Seconds()),
HasPrevPage: page > 1,
HasNextPage: len(combinedResults) >= 50,
NoResults: len(combinedResults) == 0,
LanguageOptions: languageOptions,
CurrentLang: settings.SearchLanguage,
Theme: settings.Theme,
Safe: settings.SafeSearch,
IsThemeDark: settings.IsThemeDark,
}
err = tmpl.Execute(w, data)
if err != nil {
printErr("Error executing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
// Render the template without measuring time
renderTemplate(w, "text.html", data)
}
func getTextResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TextSearchResult {

View file

@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"fmt"
"html/template"
"net/http"
"net/url"
"sync"
@ -158,17 +157,12 @@ func handleVideoSearch(w http.ResponseWriter, settings UserSettings, query strin
}
elapsed := time.Since(start)
tmpl, err := template.New("videos.html").Funcs(funcs).ParseFiles("templates/videos.html")
if err != nil {
printErr("Error parsing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, map[string]interface{}{
// Prepare the data to pass to the template
data := map[string]interface{}{
"Results": results,
"Query": query,
"Fetched": fmt.Sprintf("%.2f seconds", elapsed.Seconds()),
"Fetched": fmt.Sprintf("%.2f %s", elapsed.Seconds(), Translate("seconds")),
"Page": page,
"HasPrevPage": page > 1,
"HasNextPage": len(results) > 0,
@ -177,11 +171,10 @@ func handleVideoSearch(w http.ResponseWriter, settings UserSettings, query strin
"Theme": settings.Theme,
"Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark,
})
if err != nil {
printErr("Error executing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
// Render the template without measuring time
renderTemplate(w, "videos.html", data)
}
func fetchVideoResults(query, safe, lang string, page int) []VideoResult {