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 ( import (
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/json"
"html/template" "html/template"
"net/http"
"strings" "strings"
) )
@ -15,9 +17,35 @@ var (
"add": func(a, b int) int { "add": func(a, b int) int {
return a + b 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 { func generateStrongRandomString(length int) string {
bytes := make([]byte, length) bytes := make([]byte, length)
_, err := rand.Read(bytes) _, err := rand.Read(bytes)

View file

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"net/url" "net/url"
"regexp" "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"} cacheKey := CacheKey{Query: query, Page: page, Safe: settings.SafeSearch == "active", Lang: settings.SearchLanguage, Type: "file"}
combinedResults := getFileResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page) 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 }) sort.Slice(combinedResults, func(i, j int) bool { return combinedResults[i].Seeders > combinedResults[j].Seeders })
elapsedTime := time.Since(startTime) elapsedTime := time.Since(startTime)
funcMap := template.FuncMap{
"sub": func(a, b int) int { return a - b }, // Prepare the data to pass to the template
"add": func(a, b int) int { return a + b }, data := map[string]interface{}{
} "Results": combinedResults,
tmpl, err := template.New("files.html").Funcs(funcMap).ParseFiles("templates/files.html") "Query": query,
if err != nil { "Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")), // Time for fetching results
printErr("Failed to load template: %v", err) "Category": "all",
http.Error(w, "Failed to load template", http.StatusInternalServerError) "Sort": "seed",
return "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 { // Render the template without measuring the time
Results []TorrentResult renderTemplate(w, "files.html", data)
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)
}
} }
func getFileResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TorrentResult { func getFileResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TorrentResult {

View file

@ -3,7 +3,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"log" "log"
"math" "math"
"net/http" "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) { 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) 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") log.Printf("No results from primary search, trying other nodes")
results = tryOtherNodesForForumSearch(query, settings.SafeSearch, settings.SearchLanguage, page) results = tryOtherNodesForForumSearch(query, settings.SafeSearch, settings.SearchLanguage, page)
} }
data := struct { // Measure the elapsed time for fetching results
Query string elapsedTime := time.Since(startTime)
Results []ForumSearchResult
Page int // Prepare the data to pass to the template
HasPrevPage bool data := map[string]interface{}{
HasNextPage bool "Query": query,
LanguageOptions []LanguageOption "Results": results,
CurrentLang string "Page": page,
Theme string "Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")), // Time for fetching results
Safe string "HasPrevPage": page > 1,
IsThemeDark bool "HasNextPage": len(results) == 25, // Assuming 25 results per page
}{ "LanguageOptions": languageOptions,
Query: query, "CurrentLang": settings.SearchLanguage,
Results: results, "Theme": settings.Theme,
Page: page, "Safe": settings.SafeSearch,
HasPrevPage: page > 1, "IsThemeDark": settings.IsThemeDark,
HasNextPage: len(results) == 25,
LanguageOptions: languageOptions,
CurrentLang: settings.SearchLanguage,
Theme: settings.Theme,
Safe: settings.SafeSearch,
IsThemeDark: settings.IsThemeDark,
} }
funcMap := template.FuncMap{ // Render the template without measuring the time
"sub": func(a, b int) int { return a - b }, renderTemplate(w, "forums.html", data)
"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)
}
} }

View file

@ -2,8 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"html/template"
"log"
"net/http" "net/http"
"time" "time"
) )
@ -26,46 +24,25 @@ func handleImageSearch(w http.ResponseWriter, settings UserSettings, query strin
combinedResults := getImageResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page) combinedResults := getImageResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page)
elapsedTime := time.Since(startTime) elapsedTime := time.Since(startTime)
tmpl, err := template.New("images.html").Funcs(funcs).ParseFiles("templates/images.html")
if err != nil { // Prepare the data to pass to the template
log.Printf("Error parsing template: %v", err) data := map[string]interface{}{
http.Error(w, "Internal Server Error", http.StatusInternalServerError) "Results": combinedResults,
return "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 { // Render the template without measuring the time
Results []ImageSearchResult renderTemplate(w, "images.html", data)
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)
}
} }
func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []ImageSearchResult { func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []ImageSearchResult {

View file

@ -1,4 +1,3 @@
msgid "settings_title" msgid "settings_title"
msgstr "Settings" msgstr "Settings"
@ -29,10 +28,10 @@ msgstr "Latte"
msgid "safe_search" msgid "safe_search"
msgstr "Safe Search" msgstr "Safe Search"
msgid "safe_search_off" msgid "off"
msgstr "Off" msgstr "Off"
msgid "safe_search_on" msgid "on"
msgstr "On" msgstr "On"
msgid "site_language" msgid "site_language"
@ -41,5 +40,152 @@ msgstr "Site Language"
msgid "search_language" msgid "search_language"
msgstr "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" 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" msgid "settings_title"
msgstr "Ustawienia" msgstr "Ustawienia"
@ -29,17 +28,164 @@ msgstr "Latte"
msgid "safe_search" msgid "safe_search"
msgstr "Bezpieczne wyszukiwanie" msgstr "Bezpieczne wyszukiwanie"
msgid "safe_search_off" msgid "off"
msgstr "Wyłączone" msgstr "Wyłączone"
msgid "safe_search_on" msgid "on"
msgstr "Włączone" msgstr "Włączone"
msgid "site_language" msgid "site_language"
msgstr "Język witryny" msgstr "Język strony"
msgid "search_language" msgid "search_language"
msgstr "Język wyszukiwania" 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" msgid "save_settings"
msgstr "Zapisz ustawienia" 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, IsThemeDark: settings.IsThemeDark,
} }
tmpl := template.Must(template.ParseFiles("templates/search.html")) // Add Translate to the template functions
tmpl.Execute(w, data) 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 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 { switch searchType {
case "image": case "image":
handleImageSearch(w, settings, query, page) handleImageSearch(w, settings, query, page)

23
map.go
View file

@ -3,9 +3,9 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"net/url" "net/url"
"time"
) )
type NominatimResponse struct { 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) { 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 // Geocode the query to get coordinates
latitude, longitude, found, err := geocodeQuery(query) latitude, longitude, found, err := geocodeQuery(query)
if err != nil { if err != nil {
printDebug("Error geocoding query: %s, error: %v", query, err) 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 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{}{ data := map[string]interface{}{
"Query": query, "Query": query,
"Latitude": latitude, "Latitude": latitude,
"Longitude": longitude, "Longitude": longitude,
"Found": found, "Found": found,
"Fetched": fmt.Sprintf("%.2f %s", elapsedTime.Seconds(), Translate("seconds")),
"Theme": settings.Theme, "Theme": settings.Theme,
"Safe": settings.SafeSearch, "Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark, "IsThemeDark": settings.IsThemeDark,
} }
tmpl, err := template.ParseFiles("templates/map.html") // Render the template
if err != nil { renderTemplate(w, "map.html", data)
printErr("Error loading map template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
tmpl.Execute(w, data)
} }

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> </head>
<body> <body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off"> <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"> <div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/> <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> <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="sub-search-button-wrapper">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button> <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>
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button> <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> </div>
<div class="search-container-results-btn"> <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 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>
</div> </div>
</form> </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 }} {{ if .Results }}
<form action="/search" class="torrent-sort" method="GET"> <form action="/search" class="torrent-sort" method="GET">
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="file"> <input type="hidden" name="t" value="file">
<select class="torrent-settings" name="sort"> <select class="torrent-settings" name="sort">
<option value="seed" {{ if eq .Sort "seed" }} selected {{ end }}>Number of Seeders</option> <option value="seed" {{ if eq .Sort "seed" }} selected {{ end }}>{{ translate "sort_seeders" }}</option>
<option value="leech" {{ if eq .Sort "leech" }} selected {{ end }}>Number of Leechers</option> <option value="leech" {{ if eq .Sort "leech" }} selected {{ end }}>{{ translate "sort_leechers" }}</option>
<option value="lth" {{ if eq .Sort "lth" }} selected {{ end }}>Size (Low to High)</option> <option value="lth" {{ if eq .Sort "lth" }} selected {{ end }}>{{ translate "sort_lth" }}</option>
<option value="htl" {{ if eq .Sort "htl" }} selected {{ end }}>Size (High to Low)</option> <option value="htl" {{ if eq .Sort "htl" }} selected {{ end }}>{{ translate "sort_htl" }}</option>
</select> </select>
<select class="torrent-cat" name="cat"> <select class="torrent-cat" name="cat">
<option value="all" {{ if eq .Category "all" }} selected {{ end }}>All Categories</option> <option value="all" {{ if eq .Category "all" }} selected {{ end }}>{{ translate "category_all" }}</option>
<option value="movie" {{ if eq .Category "movie" }} selected {{ end }}>Movies</option> <option value="movie" {{ if eq .Category "movie" }} selected {{ end }}>{{ translate "category_movie" }}</option>
<option value="audiobook" {{ if eq .Category "audiobook" }} selected {{ end }}>Audiobooks</option> <option value="audiobook" {{ if eq .Category "audiobook" }} selected {{ end }}>{{ translate "category_audiobook" }}</option>
<option value="tv" {{ if eq .Category "tv" }} selected {{ end }}>TV Shows</option> <option value="tv" {{ if eq .Category "tv" }} selected {{ end }}>{{ translate "category_tv" }}</option>
<option value="games" {{ if eq .Category "games" }} selected {{ end }}>Games</option> <option value="games" {{ if eq .Category "games" }} selected {{ end }}>{{ translate "category_games" }}</option>
<option value="software" {{ if eq .Category "software" }} selected {{ end }}>Software</option> <option value="software" {{ if eq .Category "software" }} selected {{ end }}>{{ translate "category_software" }}</option>
<option value="anime" {{ if eq .Category "anime" }} selected {{ end }}>Anime</option> <option value="anime" {{ if eq .Category "anime" }} selected {{ end }}>{{ translate "category_anime" }}</option>
<option value="music" {{ if eq .Category "music" }} selected {{ end }}>Music</option> <option value="music" {{ if eq .Category "music" }} selected {{ end }}>{{ translate "category_music" }}</option>
{{ if eq .Safe "disabled" }} {{ 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 }} {{ end }}
</select> </select>
<button type="submit" class="torrent-sort-save">Apply settings</button> <button type="submit" class="torrent-sort-save">{{ translate "apply_settings" }}</button>
</form> </form>
<div class="clean"> <div class="clean">
{{ range .Results }} {{ range .Results }}
<div class="results" id="results"> <div class="results" id="results">
{{ if .Error }} {{ if .Error }}
<div class="error">{{ .Error }}</div> <div class="error">{{ translate "error" }}: {{ .Error }}</div>
{{ else }} {{ else }}
<a id="link" href="{{ .URL }}">{{ .URL }}</a> <a id="link" href="{{ .URL }}">{{ .URL }}</a>
<a class="torrent" href="magnet:{{ .Magnet }}"><h3>{{ .Title }}</h3></a> <a class="torrent" href="magnet:{{ .Magnet }}"><h3>{{ .Title }}</h3></a>
<p class="stats">{{ if .Views }}{{ .Views }} views • {{ end }}{{ .Size }}</p> <p class="stats">{{ if .Views }}{{ .Views }} {{ translate "views" }} • {{ end }}{{ .Size }}</p>
<p class="publish__info"> Seeders: <span class="seeders">{{ .Seeders }}</span> | Leechers: <span class="leechers">{{ .Leechers }}</span></p> <p class="publish__info">{{ translate "seeders" }}: <span class="seeders">{{ .Seeders }}</span> | {{ translate "leechers" }}: <span class="leechers">{{ .Leechers }}</span></p>
{{ end }} {{ end }}
</div> </div>
{{ end }} {{ end }}
@ -99,17 +99,17 @@
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="file"> <input type="hidden" name="t" value="file">
{{ if .HasPrevPage }} {{ 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 }} {{ end }}
{{ if .HasNextPage }} {{ 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 }} {{ end }}
</form> </form>
</div> </div>
{{ else }} {{ else }}
<div class="no-results-found"> <div class="no-results-found">
Your search '{{ .Query }}' came back with no results.<br> {{ translate "no_results_found" .Query }}<br>
Try rephrasing your search term and/or recorrect any spelling mistakes. {{ translate "suggest_rephrase" }}
</div> </div>
{{ end }} {{ end }}
<script defer src="/static/js/autocomplete.js"></script> <script defer src="/static/js/autocomplete.js"></script>

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> </head>
<body> <body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off"> <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"> <div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/> <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> <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="sub-search-button-wrapper">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button> <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>
<div class="search-container-results-btn"> <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 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>
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button> <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> </div>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button> <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>
</div> </div>
</form> </form>
<form class="results_settings" action="/search" method="get"> <form class="results_settings" action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<select class="results-settings" name="safe" id="safeSearchSelect"> <select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option> <option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option> <option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select> </select>
<select class="results-settings" name="lang" id="languageSelect"> <select class="results-settings" name="lang" id="languageSelect">
{{range .LanguageOptions}} {{range .LanguageOptions}}
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option> <option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option>
{{end}} {{end}}
</select> </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> </form>
<div class="results" id="results"> <div class="results" id="results">
{{if .Results}} {{if .Results}}
@ -75,13 +75,13 @@
<br> <br>
{{end}} {{end}}
{{else if .NoResults}} {{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}} {{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}} {{end}}
</div> </div>
<div class="message-bottom-left" id="message-bottom-left"> <div class="message-bottom-left" id="message-bottom-left">
<span>Searching for new results...</span> <span>{{ translate "searching_for_new_results" }}</span>
</div> </div>
<div class="prev-next prev-img" id="prev-next"> <div class="prev-next prev-img" id="prev-next">
<form action="/search" method="get"> <form action="/search" method="get">
@ -89,10 +89,10 @@
<input type="hidden" name="t" value="forum"> <input type="hidden" name="t" value="forum">
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
{{ if .HasPrevPage }} {{ 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 }} {{ end }}
{{ if .HasNextPage }} {{ 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 }} {{ end }}
</div> </div>
</form> </form>

View file

@ -6,15 +6,15 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/style-fixedwidth.css"> <link rel="stylesheet" href="/static/css/style-fixedwidth.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> </head>
<body> <body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off"> <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"> <div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/> <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> <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="sub-search-button-wrapper">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button> <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>
<div class="search-container-results-btn"> <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 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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button> <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>
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button> <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> </div>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button> <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>
</div> </div>
</form> </form>
<form class="results_settings" action="/search" method="get"> <form class="results_settings" action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<select class="results-settings" name="safe" id="safeSearchSelect"> <select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option> <option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option> <option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select> </select>
<select class="results-settings" name="lang" id="languageSelect"> <select class="results-settings" name="lang" id="languageSelect">
{{range .LanguageOptions}} {{range .LanguageOptions}}
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option> <option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option>
{{end}} {{end}}
</select> </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> </form>
<div class="search-results" id="results"> <div class="search-results" id="results">
@ -78,7 +78,7 @@
<div class="resolution">{{ .Width }} × {{ .Height }}</div> <div class="resolution">{{ .Width }} × {{ .Height }}</div>
<div class="details"> <div class="details">
<span class="img_title clickable">{{ .Title }}</span> <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>
</div> </div>
{{ end }} {{ end }}
@ -90,24 +90,22 @@
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="image"> <input type="hidden" name="t" value="image">
{{ if .HasPrevPage }} {{ if .HasPrevPage }}
<!-- Subtract 1 from the current page for the Previous button --> <button type="submit" name="p" value="{{ sub .Page 1 }}">{{ translate "previous" }}</button>
<button type="submit" name="p" value="{{ sub .Page 1 }}">Previous</button>
{{ end }} {{ end }}
{{ if .HasNextPage }} {{ if .HasNextPage }}
<!-- Add 1 to the current page for the Next button --> <button type="submit" name="p" value="{{ add .Page 1 }}">{{ translate "next" }}</button>
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
{{ end }} {{ end }}
</form> </form>
</div> </div>
</noscript> </noscript>
{{ else if .NoResults }} {{ 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 }} {{ 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 }} {{ end }}
</div> </div>
<div class="message-bottom-left" id="message-bottom-left"> <div class="message-bottom-left" id="message-bottom-left">
<span>Searching for new results...</span> <span>{{ translate "searching_for_new_results" }}</span>
</div> </div>
<div id="image-viewer-overlay" style="display: none;"></div> <div id="image-viewer-overlay" style="display: none;"></div>

View file

@ -6,10 +6,10 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> <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" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css" />
<style> <style>
@ -28,7 +28,7 @@
</head> </head>
<body> <body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off"> <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"> <div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/> <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> <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="sub-search-button-wrapper">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button> <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>
<div class="search-container-results-btn"> <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 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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button> <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>
</div> </div>
</form> </form>
@ -69,7 +69,7 @@
<div id="map"></div> <div id="map"></div>
{{ else }} {{ else }}
<div id="map"></div> <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 }} {{ end }}
{{ if .Found }} {{ if .Found }}
<script> <script>
@ -98,10 +98,10 @@
}); });
var baseMaps = { var baseMaps = {
"Streets": streets, "{{ translate "streets" }}": streets,
"Satellite": satellite, "{{ translate "satellite" }}": satellite,
"Esri Satellite": esriSat, "{{ translate "esri_satellite" }}": esriSat,
"Topographic": topo "{{ translate "topographic" }}": topo
}; };
streets.addTo(map); // Add default layer streets.addTo(map); // Add default layer
@ -120,7 +120,7 @@
L.Control.geolocate = L.Control.extend({ L.Control.geolocate = L.Control.extend({
onAdd: function(map) { onAdd: function(map) {
var div = L.DomUtil.create('div', 'leaflet-control-locate'); var div = L.DomUtil.create('div', 'leaflet-control-locate');
div.title = 'Locate Me'; div.title = '{{ translate "locate_me" }}';
L.DomEvent.on(div, 'click', function() { L.DomEvent.on(div, 'click', function() {
map.locate({setView: true, maxZoom: 16}); map.locate({setView: true, maxZoom: 16});
}); });
@ -138,7 +138,7 @@
function onLocationFound(e) { function onLocationFound(e) {
var radius = e.accuracy / 2; var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map) 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); L.circle(e.latlng, radius).addTo(map);
} }

View file

@ -6,11 +6,11 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/style-search.css"> <link rel="stylesheet" href="/static/css/style-search.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> </head>
<body> <body>
<script defer src="/static/js/autocomplete.js"></script> <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> <button class="material-icons-round clickable settings-icon-link settings-icon-link-search">menu</button>
</div> </div>
<div class="search-menu settings-menu-hidden"> <div class="search-menu settings-menu-hidden">
<h2>Settings</h2> <h2>{{ translate "settings" }}</h2>
<div class="settings-content"> <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"> <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 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="dark_theme" alt="{{ translate "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="light_theme" alt="{{ translate "light_theme" }}" src="/static/images/light.webp"></div>
</div> </div>
</div> </div>
<select class="lang" name="safe" id="safeSearchSelect"> <select class="lang" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option> <option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option> <option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select> </select>
<select class="lang" name="site_lang" id="siteLanguageSelect"> <select class="lang" name="site_lang" id="siteLanguageSelect">
{{range .LanguageOptions}} {{range .LanguageOptions}}
@ -93,9 +93,9 @@
</div> </div>
<form action="/search" class="search-container" method="post" autocomplete="off"> <form action="/search" class="search-container" method="post" autocomplete="off">
<div class="search-page-content"> <div class="search-page-content">
<h1>Ocásek</h1> <h1>{{ translate "site_name" }}</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="{{ translate "type_to_search" }}" -->
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="web" type="submit">search</button> <button id="search-wrapper-ico" class="material-icons-round" name="t" value="web" type="submit">search</button>
<div class="autocomplete"> <div class="autocomplete">
<ul></ul> <ul></ul>
@ -106,32 +106,32 @@
<div class="icon-button"> <div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</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>
<div class="icon-button"> <div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</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>
<div class="icon-button"> <div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</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>
<div class="icon-button"> <div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</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>
<div class="icon-button"> <div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</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>
<div class="icon-button"> <div class="icon-button">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</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> </div>
</div> </div>

View file

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

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> </head>
<body> <body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off"> <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"> <div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/> <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> <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="sub-search-button-wrapper">
<div class="search-container-results-btn"> <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 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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="video">movie</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</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">Forums</button> <button name="t" value="forum" class="clickable">{{ translate "forums" }}</button>
</div> </div>
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button> <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> </div>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button> <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>
</div> </div>
</form> </form>
<form class="results_settings" action="/search" method="get"> <form class="results_settings" action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<select class="results-settings" name="safe" id="safeSearchSelect"> <select class="results-settings" name="safe" id="safeSearchSelect">
<option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>Safe Search Off</option> <option value="disabled" {{if eq .Safe "disabled"}}selected{{end}}>{{ translate "safe_search_off" }}</option>
<option value="active" {{if eq .Safe "active"}}selected{{end}}>Safe Search On</option> <option value="active" {{if eq .Safe "active"}}selected{{end}}>{{ translate "safe_search_on" }}</option>
</select> </select>
<select class="results-settings" name="lang" id="languageSelect"> <select class="results-settings" name="lang" id="languageSelect">
{{range .LanguageOptions}} {{range .LanguageOptions}}
<option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option> <option value="{{.Code}}" {{if eq .Code $.CurrentLang}}selected{{end}}>{{.Name}}</option>
{{end}} {{end}}
</select> </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> </form>
<div class="results" id="results"> <div class="results" id="results">
{{if .Results}} {{if .Results}}
@ -76,13 +76,13 @@
<br> <br>
{{end}} {{end}}
{{else if .NoResults}} {{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}} {{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}} {{end}}
</div> </div>
<div class="message-bottom-left" id="message-bottom-left"> <div class="message-bottom-left" id="message-bottom-left">
<span>Searching for new results...</span> <span>{{ translate "searching_for_new_results" }}</span>
</div> </div>
<div class="prev-next prev-img" id="prev-next"> <div class="prev-next prev-img" id="prev-next">
<form action="/search" method="get"> <form action="/search" method="get">
@ -90,10 +90,10 @@
<input type="hidden" name="t" value="text"> <input type="hidden" name="t" value="text">
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
{{ if .HasPrevPage }} {{ 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 }} {{ end }}
{{ if .HasNextPage }} {{ 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 }} {{ end }}
</div> </div>
</form> </form>

View file

@ -6,14 +6,14 @@
{{ if .IsThemeDark }} {{ if .IsThemeDark }}
<meta name="darkreader-lock"> <meta name="darkreader-lock">
{{ end }} {{ 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.css">
<link rel="stylesheet" href="/static/css/{{.Theme}}.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> </head>
<body> <body>
<form action="/search" id="prev-next-form" class="results-search-container" method="GET" autocomplete="off"> <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"> <div class="wrapper-results">
<input type="text" name="q" value="{{ .Query }}" id="search-input"/> <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> <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="sub-search-button-wrapper">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="text">search</button> <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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="image">image</button> <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>
<div class="search-container-results-btn"> <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 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>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="forum">forum</button> <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>
<div id="content" class="js-enabled"> <div id="content" class="js-enabled">
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="map">map</button> <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> </div>
<div class="search-container-results-btn"> <div class="search-container-results-btn">
<button id="sub-search-wrapper-ico" class="material-icons-round clickable" name="t" value="file">share</button> <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>
</div> </div>
</form> </form>
<!-- Results go here --> <!-- 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 }} {{ if .Results }}
{{ range .Results }} {{ range .Results }}
<div> <div>
@ -75,17 +75,17 @@
</div> </div>
{{ end }} {{ end }}
{{ else }} {{ else }}
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div> <div class="no-results">{{ translate "no_results" .Query }}</div>
{{ end }} {{ end }}
<div class="prev-next prev-img" id="prev-next"> <div class="prev-next prev-img" id="prev-next">
<form action="/search" method="get"> <form action="/search" method="get">
<input type="hidden" name="q" value="{{ .Query }}"> <input type="hidden" name="q" value="{{ .Query }}">
<input type="hidden" name="t" value="video"> <input type="hidden" name="t" value="video">
{{ if .HasPrevPage }} {{ 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 }} {{ end }}
{{ if .HasNextPage }} {{ 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 }} {{ end }}
</form> </form>
</div> </div>

63
text.go
View file

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"time" "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"} cacheKey := CacheKey{Query: query, Page: page, Safe: settings.SafeSearch == "active", Lang: settings.SearchLanguage, Type: "text"}
combinedResults := getTextResultsFromCacheOrFetch(cacheKey, query, settings.SafeSearch, settings.SearchLanguage, page) 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 asynchronously
// Prefetch next and previous pages
go prefetchPage(query, settings.SafeSearch, settings.SearchLanguage, page+1) go prefetchPage(query, settings.SafeSearch, settings.SearchLanguage, page+1)
if hasPrevPage { if hasPrevPage {
go prefetchPage(query, settings.SafeSearch, settings.SearchLanguage, page-1) go prefetchPage(query, settings.SafeSearch, settings.SearchLanguage, page-1)
} }
elapsedTime := time.Since(startTime) elapsedTime := time.Since(startTime)
tmpl, err := template.New("text.html").Funcs(funcs).ParseFiles("templates/text.html")
if err != nil { // Prepare the data to pass to the template
printErr("Error parsing template: %v", err) data := map[string]interface{}{
http.Error(w, "Internal Server Error", http.StatusInternalServerError) "Results": combinedResults,
return "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 { // Render the template without measuring time
Results []TextSearchResult renderTemplate(w, "text.html", data)
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)
}
} }
func getTextResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TextSearchResult { func getTextResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TextSearchResult {

View file

@ -3,7 +3,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"net/url" "net/url"
"sync" "sync"
@ -158,17 +157,12 @@ func handleVideoSearch(w http.ResponseWriter, settings UserSettings, query strin
} }
elapsed := time.Since(start) 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, "Results": results,
"Query": query, "Query": query,
"Fetched": fmt.Sprintf("%.2f seconds", elapsed.Seconds()), "Fetched": fmt.Sprintf("%.2f %s", elapsed.Seconds(), Translate("seconds")),
"Page": page, "Page": page,
"HasPrevPage": page > 1, "HasPrevPage": page > 1,
"HasNextPage": len(results) > 0, "HasNextPage": len(results) > 0,
@ -177,11 +171,10 @@ func handleVideoSearch(w http.ResponseWriter, settings UserSettings, query strin
"Theme": settings.Theme, "Theme": settings.Theme,
"Safe": settings.SafeSearch, "Safe": settings.SafeSearch,
"IsThemeDark": settings.IsThemeDark, "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 { func fetchVideoResults(query, safe, lang string, page int) []VideoResult {