Compare commits
No commits in common. "ee56414b0e017c270d68eeb61fbe4cf569ba503d" and "485b602df932b32292494ad6321e0e03c1e0b4dc" have entirely different histories.
ee56414b0e
...
485b602df9
16 changed files with 49 additions and 278 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
config.json
|
|
||||||
opensearch.xml
|
|
29
images.go
29
images.go
|
@ -90,9 +90,7 @@ func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string
|
||||||
case results := <-cacheChan:
|
case results := <-cacheChan:
|
||||||
if results == nil {
|
if results == nil {
|
||||||
combinedResults = fetchImageResults(query, safe, lang, page)
|
combinedResults = fetchImageResults(query, safe, lang, page)
|
||||||
if len(combinedResults) > 0 {
|
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
||||||
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
_, _, imageResults := convertToSpecificResults(results)
|
_, _, imageResults := convertToSpecificResults(results)
|
||||||
combinedResults = imageResults
|
combinedResults = imageResults
|
||||||
|
@ -100,31 +98,20 @@ func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string
|
||||||
case <-time.After(2 * time.Second):
|
case <-time.After(2 * time.Second):
|
||||||
log.Println("Cache check timeout")
|
log.Println("Cache check timeout")
|
||||||
combinedResults = fetchImageResults(query, safe, lang, page)
|
combinedResults = fetchImageResults(query, safe, lang, page)
|
||||||
if len(combinedResults) > 0 {
|
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
||||||
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return combinedResults
|
return combinedResults
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchImageResults(query, safe, lang string, page int) []ImageSearchResult {
|
func fetchImageResults(query, safe, lang string, page int) []ImageSearchResult {
|
||||||
var results []ImageSearchResult
|
engine := selectImageEngine()
|
||||||
var err error
|
log.Printf("Using image search engine: %s", engine.Name)
|
||||||
|
|
||||||
for attempts := 0; attempts < len(imageEngines); attempts++ {
|
results, err := engine.Func(query, safe, lang, page)
|
||||||
engine := selectImageEngine()
|
if err != nil {
|
||||||
log.Printf("Using image search engine: %s", engine.Name)
|
log.Printf("Error performing image search with %s: %v", engine.Name, err)
|
||||||
|
return nil
|
||||||
results, err = engine.Func(query, safe, lang, page)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error performing image search with %s: %v", engine.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
116
init.go
116
init.go
|
@ -1,116 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Configuration structure
|
|
||||||
type Config struct {
|
|
||||||
Port int
|
|
||||||
OpenSearch OpenSearchConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenSearchConfig struct {
|
|
||||||
Domain string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default configuration values
|
|
||||||
var defaultConfig = Config{
|
|
||||||
Port: 5000,
|
|
||||||
OpenSearch: OpenSearchConfig{
|
|
||||||
Domain: "localhost",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const configFilePath = "config.json"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Run the initialization process
|
|
||||||
err := initConfig()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error during initialization:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the main application
|
|
||||||
runServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func initConfig() error {
|
|
||||||
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
|
|
||||||
return createConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Configuration file already exists.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createConfig() error {
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
|
|
||||||
fmt.Println("Configuration file not found.")
|
|
||||||
fmt.Print("Do you want to use default values? (yes/no): ")
|
|
||||||
useDefaults, _ := reader.ReadString('\n')
|
|
||||||
|
|
||||||
config := defaultConfig
|
|
||||||
if useDefaults != "yes\n" {
|
|
||||||
fmt.Print("Enter port (default 5000): ")
|
|
||||||
portStr, _ := reader.ReadString('\n')
|
|
||||||
if portStr != "\n" {
|
|
||||||
port, err := strconv.Atoi(portStr[:len(portStr)-1])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
config.Port = port
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Print("Enter your domain address (e.g., domain.com): ")
|
|
||||||
domain, _ := reader.ReadString('\n')
|
|
||||||
if domain != "\n" {
|
|
||||||
config.OpenSearch.Domain = domain[:len(domain)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
saveConfig(config)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveConfig(config Config) {
|
|
||||||
file, err := os.Create(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error creating config file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
configData, err := json.MarshalIndent(config, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error marshalling config data:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = file.Write(configData)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error writing to config file:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfig() Config {
|
|
||||||
configFile, err := os.Open(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error opening config file: %v", err)
|
|
||||||
}
|
|
||||||
defer configFile.Close()
|
|
||||||
|
|
||||||
var config Config
|
|
||||||
if err := json.NewDecoder(configFile).Decode(&config); err != nil {
|
|
||||||
log.Fatalf("Error decoding config file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
34
main.go
34
main.go
|
@ -63,6 +63,19 @@ var languageOptions = []LanguageOption{
|
||||||
{Code: "lang_vi", Name: "Tiếng Việt (Vietnamese)"},
|
{Code: "lang_vi", Name: "Tiếng Việt (Vietnamese)"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||||
|
http.HandleFunc("/", handleSearch)
|
||||||
|
http.HandleFunc("/search", handleSearch)
|
||||||
|
http.HandleFunc("/img_proxy", handleImageProxy)
|
||||||
|
http.HandleFunc("/settings", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.ServeFile(w, r, "templates/settings.html")
|
||||||
|
})
|
||||||
|
initializeTorrentSites()
|
||||||
|
fmt.Println("Server is listening on http://localhost:5000")
|
||||||
|
log.Fatal(http.ListenAndServe(":5000", nil))
|
||||||
|
}
|
||||||
|
|
||||||
func handleSearch(w http.ResponseWriter, r *http.Request) {
|
func handleSearch(w http.ResponseWriter, r *http.Request) {
|
||||||
query, safe, lang, searchType, page := parseSearchParams(r)
|
query, safe, lang, searchType, page := parseSearchParams(r)
|
||||||
|
|
||||||
|
@ -120,24 +133,3 @@ func parsePageParameter(pageStr string) int {
|
||||||
}
|
}
|
||||||
return page
|
return page
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServer() {
|
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
|
||||||
http.HandleFunc("/", handleSearch)
|
|
||||||
http.HandleFunc("/search", handleSearch)
|
|
||||||
http.HandleFunc("/img_proxy", handleImageProxy)
|
|
||||||
http.HandleFunc("/settings", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
http.ServeFile(w, r, "templates/settings.html")
|
|
||||||
})
|
|
||||||
http.HandleFunc("/opensearch.xml", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/opensearchdescription+xml")
|
|
||||||
http.ServeFile(w, r, "static/opensearch.xml")
|
|
||||||
})
|
|
||||||
initializeTorrentSites()
|
|
||||||
|
|
||||||
config := loadConfig()
|
|
||||||
generateOpenSearchXML(config)
|
|
||||||
|
|
||||||
fmt.Printf("Server is listening on http://localhost:%d\n", config.Port)
|
|
||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", config.Port), nil))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/xml"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OpenSearchDescription struct {
|
|
||||||
XMLName xml.Name `xml:"OpenSearchDescription"`
|
|
||||||
Xmlns string `xml:"xmlns,attr"`
|
|
||||||
ShortName string `xml:"ShortName"`
|
|
||||||
Description string `xml:"Description"`
|
|
||||||
Tags string `xml:"Tags"`
|
|
||||||
URL URL `xml:"Url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type URL struct {
|
|
||||||
Type string `xml:"type,attr"`
|
|
||||||
Template string `xml:"template,attr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateOpenSearchXML(config Config) {
|
|
||||||
opensearch := OpenSearchDescription{
|
|
||||||
Xmlns: "http://a9.com/-/spec/opensearch/1.1/",
|
|
||||||
ShortName: "Ocásek",
|
|
||||||
Description: "Search engine",
|
|
||||||
Tags: "search, engine",
|
|
||||||
URL: URL{
|
|
||||||
Type: "text/html",
|
|
||||||
Template: fmt.Sprintf("https://%s/search?q={searchTerms}", config.OpenSearch.Domain),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create("static/opensearch.xml")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error creating OpenSearch file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
enc := xml.NewEncoder(file)
|
|
||||||
enc.Indent(" ", " ")
|
|
||||||
if err := enc.Encode(opensearch); err != nil {
|
|
||||||
fmt.Println("Error encoding OpenSearch XML:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("OpenSearch description file generated successfully.")
|
|
||||||
}
|
|
2
run.sh
2
run.sh
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
go run main.go common.go init.go open-search.go images.go imageproxy.go images-quant.go images-imgur.go video.go map.go text.go text-searchxng.go text-librex.go text-google.go cache.go forums.go files.go files-torrentgalaxy.go files-thepiratebay.go agent.go
|
go run main.go common.go images.go imageproxy.go images-quant.go images-imgur.go video.go map.go text.go text-searchxng.go text-librex.go text-google.go cache.go forums.go files.go files-torrentgalaxy.go files-thepiratebay.go agent.go
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{.Query}} - Ocásek</title>
|
<title>{{.Query}} - Ocásek</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{.Query}} - Ocásek</title>
|
<title>{{.Query}} - Ocásek</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{.Query}} - Ocásek</title>
|
<title>{{.Query}} - Ocásek</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{ .Query }} - Ocásek</title>
|
<title>{{ .Query }} - Ocásek</title>
|
||||||
<link rel="stylesheet" href="/static/css/style.css">
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Search with Ocásek</title>
|
<title>Search with Ocásek</title>
|
||||||
<link rel="stylesheet" href="/static/css/style.css">
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" href="/opensearch.xml">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="settings-search-div settings-search-div-search">
|
<div class="settings-search-div settings-search-div-search">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Settings - Ocásek</title>
|
<title>Settings - Ocásek</title>
|
||||||
<link rel="stylesheet" type="text/css" href="static/css/style.css">
|
<link rel="stylesheet" type="text/css" href="static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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">
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{.Query}} - Ocásek</title>
|
<title>{{.Query}} - Ocásek</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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">
|
||||||
|
|
|
@ -5,16 +5,15 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{.Query}} - Ocásek</title>
|
<title>{{.Query}} - Ocásek</title>
|
||||||
<link rel="stylesheet" href="/static/css/style.css">
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="Ocásek" 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="./">Ocásek</a></h1>
|
||||||
<div class="wrapper-results">
|
<div class="wrapper-results">
|
||||||
<input type="text" name="q" value="{{ .Query }}" id="search-input" placeholder="Type to search..." />
|
<input type="text" name="q" value="{{ .Query }}" id="search-input" placeholder="Type to search..." />
|
||||||
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="video">search</button>
|
<button id="search-wrapper-ico" class="material-icons-round" name="t" value="video">search</button>
|
||||||
<input type="submit" class="hide" name="t" value="video" />
|
<input type="submit" class="hide" name="t" value="video" />
|
||||||
</div>
|
</div>
|
||||||
<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>
|
||||||
|
@ -33,16 +32,17 @@
|
||||||
<button name="t" value="forum" class="clickable">Forums</button>
|
<button name="t" value="forum" class="clickable">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">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">Torrents</button>
|
||||||
</div>
|
</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"><!-- { fetched } --></p>
|
||||||
|
@ -51,11 +51,11 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="video__results">
|
<div class="video__results">
|
||||||
<div class="video__img__results">
|
<div class="video__img__results">
|
||||||
<a href="{{ .Href }}"> <img src="{{ .Image }}">
|
<a href="{{ .Href }}"> <img src="{{ .Image }}">
|
||||||
<div class="duration">{{ .Duration }}</div>
|
<div class="duration">{{ .Duration }}</div>
|
||||||
</img></a>
|
</img></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="results video-results-margin">
|
<div class="results video-results-margin">
|
||||||
<h3 class="video_title" href="{{ .Href }}">{{ .Title }}</h3></a>
|
<h3 class="video_title" href="{{ .Href }}">{{ .Title }}</h3></a>
|
||||||
<p class="stats">{{ .Views }} <span class="pipe">|</span> {{ .Date }}</p>
|
<p class="stats">{{ .Views }} <span class="pipe">|</span> {{ .Date }}</p>
|
||||||
<p class="publish__info">YouTube <span class="pipe">|</span> {{ .Creator }}</p>
|
<p class="publish__info">YouTube <span class="pipe">|</span> {{ .Creator }}</p>
|
||||||
|
@ -64,20 +64,9 @@
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
|
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>>
|
||||||
{{ end }}
|
{{ 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>
|
|
||||||
{{ end }}
|
|
||||||
{{ if .HasNextPage }}
|
|
||||||
<button type="submit" name="p" value="{{ add .Page 1 }}">Next</button>
|
|
||||||
{{ end }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<script>
|
<script>
|
||||||
// Check if JavaScript is enabled and modify the DOM accordingly
|
// Check if JavaScript is enabled and modify the DOM accordingly
|
||||||
document.getElementById('content').classList.remove('js-enabled');
|
document.getElementById('content').classList.remove('js-enabled');
|
||||||
|
|
33
text.go
33
text.go
|
@ -69,9 +69,7 @@ func getTextResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string,
|
||||||
case results := <-cacheChan:
|
case results := <-cacheChan:
|
||||||
if results == nil {
|
if results == nil {
|
||||||
combinedResults = fetchTextResults(query, safe, lang, page)
|
combinedResults = fetchTextResults(query, safe, lang, page)
|
||||||
if len(combinedResults) > 0 {
|
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
||||||
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
textResults, _, _ := convertToSpecificResults(results)
|
textResults, _, _ := convertToSpecificResults(results)
|
||||||
combinedResults = textResults
|
combinedResults = textResults
|
||||||
|
@ -79,9 +77,7 @@ func getTextResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string,
|
||||||
case <-time.After(2 * time.Second):
|
case <-time.After(2 * time.Second):
|
||||||
log.Println("Cache check timeout")
|
log.Println("Cache check timeout")
|
||||||
combinedResults = fetchTextResults(query, safe, lang, page)
|
combinedResults = fetchTextResults(query, safe, lang, page)
|
||||||
if len(combinedResults) > 0 {
|
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
||||||
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return combinedResults
|
return combinedResults
|
||||||
|
@ -92,31 +88,20 @@ func prefetchPage(query, safe, lang string, page int) {
|
||||||
if _, exists := resultsCache.Get(cacheKey); !exists {
|
if _, exists := resultsCache.Get(cacheKey); !exists {
|
||||||
log.Printf("Page %d not cached, caching now...", page)
|
log.Printf("Page %d not cached, caching now...", page)
|
||||||
pageResults := fetchTextResults(query, safe, lang, page)
|
pageResults := fetchTextResults(query, safe, lang, page)
|
||||||
if len(pageResults) > 0 {
|
resultsCache.Set(cacheKey, convertToSearchResults(pageResults))
|
||||||
resultsCache.Set(cacheKey, convertToSearchResults(pageResults))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Page %d already cached", page)
|
log.Printf("Page %d already cached", page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTextResults(query, safe, lang string, page int) []TextSearchResult {
|
func fetchTextResults(query, safe, lang string, page int) []TextSearchResult {
|
||||||
var results []TextSearchResult
|
engine := selectSearchEngine()
|
||||||
var err error
|
log.Printf("Using search engine: %s", engine.Name)
|
||||||
|
|
||||||
for attempts := 0; attempts < len(searchEngines); attempts++ {
|
results, err := engine.Func(query, safe, lang, page)
|
||||||
engine := selectSearchEngine()
|
if err != nil {
|
||||||
log.Printf("Using search engine: %s", engine.Name)
|
log.Printf("Error performing search with %s: %v", engine.Name, err)
|
||||||
|
return nil
|
||||||
results, err = engine.Func(query, safe, lang, page)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error performing search with %s: %v", engine.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(results) > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
11
video.go
11
video.go
|
@ -180,23 +180,16 @@ func handleVideoSearch(w http.ResponseWriter, query, safe, lang string, page int
|
||||||
}
|
}
|
||||||
|
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
tmpl, err := template.New("videos.html").Funcs(funcs).ParseFiles("templates/videos.html")
|
tmpl, err := template.ParseFiles("templates/videos.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error parsing template: %v", err)
|
log.Printf("Error parsing template: %v", err)
|
||||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tmpl.Execute(w, map[string]interface{}{
|
tmpl.Execute(w, map[string]interface{}{
|
||||||
"Results": results,
|
"Results": results,
|
||||||
"Query": query,
|
"Query": query,
|
||||||
"Fetched": fmt.Sprintf("%.2f seconds", elapsed.Seconds()),
|
"Fetched": fmt.Sprintf("%.2f seconds", elapsed.Seconds()),
|
||||||
"Page": page,
|
|
||||||
"HasPrevPage": page > 1,
|
|
||||||
"HasNextPage": len(results) > 0, // assuming you have a way to determine if there are more pages
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error executing template: %v", err)
|
|
||||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue