2024-08-13 16:31:28 +02:00
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"time"
)
var imageSearchEngines [ ] SearchEngine
func init ( ) {
imageSearchEngines = [ ] SearchEngine {
{ Name : "Qwant" , Func : wrapImageSearchFunc ( PerformQwantImageSearch ) , Weight : 1 } ,
2024-08-29 17:20:47 +02:00
{ Name : "DeviantArt" , Func : wrapImageSearchFunc ( PerformDeviantArtImageSearch ) , Weight : 2 } ,
2024-08-13 16:31:28 +02:00
{ Name : "Bing" , Func : wrapImageSearchFunc ( PerformBingImageSearch ) , Weight : 2 } , // Bing sometimes returns with low amount of images, this leads to danamica page loading not working
{ Name : "Imgur" , Func : wrapImageSearchFunc ( PerformImgurImageSearch ) , Weight : 3 } ,
}
}
func handleImageSearch ( w http . ResponseWriter , settings UserSettings , query string , page int ) {
startTime := time . Now ( )
2024-08-18 14:49:42 +02:00
cacheKey := CacheKey { Query : query , Page : page , Safe : settings . SafeSearch == "active" , Lang : settings . Language , Type : "image" }
2024-08-13 16:31:28 +02:00
combinedResults := getImageResultsFromCacheOrFetch ( cacheKey , query , settings . SafeSearch , settings . Language , page )
elapsedTime := time . Since ( startTime )
tmpl , err := template . New ( "images.html" ) . Funcs ( funcs ) . ParseFiles ( "templates/images.html" )
if err != nil {
log . Printf ( "Error parsing template: %v" , err )
http . Error ( w , "Internal Server Error" , http . StatusInternalServerError )
return
}
data := struct {
Results [ ] ImageSearchResult
Query string
Page int
Fetched string
HasPrevPage bool
HasNextPage bool
NoResults bool
2024-08-13 16:38:02 +02:00
LanguageOptions [ ] LanguageOption
CurrentLang string
2024-08-13 16:31:28 +02:00
Theme string
2024-08-13 16:38:02 +02:00
Safe string
2024-08-28 21:31:27 +02:00
IsThemeDark bool
2024-08-13 16:31:28 +02:00
} {
Results : combinedResults ,
Query : query ,
Page : page ,
Fetched : fmt . Sprintf ( "%.2f seconds" , elapsedTime . Seconds ( ) ) ,
HasPrevPage : page > 1 ,
HasNextPage : len ( combinedResults ) >= 50 ,
NoResults : len ( combinedResults ) == 0 ,
2024-08-13 16:38:02 +02:00
LanguageOptions : languageOptions ,
CurrentLang : settings . Language ,
2024-08-13 16:31:28 +02:00
Theme : settings . Theme ,
2024-08-13 16:38:02 +02:00
Safe : settings . SafeSearch ,
2024-08-28 21:31:27 +02:00
IsThemeDark : settings . IsThemeDark ,
2024-08-13 16:31:28 +02:00
}
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 {
cacheChan := make ( chan [ ] SearchResult )
var combinedResults [ ] ImageSearchResult
go func ( ) {
results , exists := resultsCache . Get ( cacheKey )
if exists {
printInfo ( "Cache hit" )
cacheChan <- results
} else {
printInfo ( "Cache miss" )
cacheChan <- nil
}
} ( )
select {
case results := <- cacheChan :
if results == nil {
combinedResults = fetchImageResults ( query , safe , lang , page )
if len ( combinedResults ) > 0 {
resultsCache . Set ( cacheKey , convertToSearchResults ( combinedResults ) )
}
} else {
_ , _ , imageResults := convertToSpecificResults ( results )
combinedResults = imageResults
}
case <- time . After ( 2 * time . Second ) :
printInfo ( "Cache check timeout" )
combinedResults = fetchImageResults ( query , safe , lang , page )
if len ( combinedResults ) > 0 {
resultsCache . Set ( cacheKey , convertToSearchResults ( combinedResults ) )
}
}
return combinedResults
}
func fetchImageResults ( query , safe , lang string , page int ) [ ] ImageSearchResult {
var results [ ] ImageSearchResult
for _ , engine := range imageSearchEngines {
printInfo ( "Using image search engine: %s" , engine . Name )
searchResults , duration , err := engine . Func ( query , safe , lang , page )
updateEngineMetrics ( & engine , duration , err == nil )
if err != nil {
printWarn ( "Error performing image search with %s: %v" , engine . Name , err )
continue
}
for _ , result := range searchResults {
results = append ( results , result . ( ImageSearchResult ) )
}
// If results are found, break out of the loop
if len ( results ) > 0 {
break
}
}
// If no results found after trying all engines
if len ( results ) == 0 {
printWarn ( "No image results found for query: %s, trying other nodes" , query )
results = tryOtherNodesForImageSearch ( query , safe , lang , page , [ ] string { hostID } )
}
return results
}
func wrapImageSearchFunc ( f func ( string , string , string , int ) ( [ ] ImageSearchResult , time . Duration , error ) ) func ( string , string , string , int ) ( [ ] SearchResult , time . Duration , error ) {
return func ( query , safe , lang string , page int ) ( [ ] SearchResult , time . Duration , error ) {
imageResults , duration , err := f ( query , safe , lang , page )
if err != nil {
return nil , duration , err
}
searchResults := make ( [ ] SearchResult , len ( imageResults ) )
for i , result := range imageResults {
searchResults [ i ] = result
}
return searchResults , duration , nil
}
}