2024-04-05 12:44:11 +02:00
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"time"
)
2024-06-14 17:56:20 +02:00
var imageSearchEngines [ ] SearchEngine
2024-04-07 15:48:25 +02:00
2024-06-10 11:49:40 +02:00
func init ( ) {
2024-06-14 17:56:20 +02:00
imageSearchEngines = [ ] SearchEngine {
{ Name : "Qwant" , Func : wrapImageSearchFunc ( PerformQwantImageSearch ) , Weight : 1 } ,
2024-08-12 12:56:42 +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 } ,
2024-04-05 12:44:11 +02:00
}
}
2024-08-11 21:45:52 +02:00
func handleImageSearch ( w http . ResponseWriter , settings UserSettings , query , safe , lang string , page int ) {
2024-05-24 14:07:16 +02:00
startTime := time . Now ( )
2024-04-05 12:44:11 +02:00
2024-05-24 14:07:16 +02:00
cacheKey := CacheKey { Query : query , Page : page , Safe : safe == "true" , Lang : lang , Type : "image" }
combinedResults := getImageResultsFromCacheOrFetch ( cacheKey , query , safe , lang , page )
elapsedTime := time . Since ( startTime )
2024-04-07 15:48:25 +02:00
tmpl , err := template . New ( "images.html" ) . Funcs ( funcs ) . ParseFiles ( "templates/images.html" )
2024-04-05 12:44:11 +02:00
if err != nil {
log . Printf ( "Error parsing template: %v" , err )
http . Error ( w , "Internal Server Error" , http . StatusInternalServerError )
return
}
data := struct {
2024-04-08 13:15:23 +02:00
Results [ ] ImageSearchResult
Query string
Page int
Fetched string
LanguageOptions [ ] LanguageOption
CurrentLang string
HasPrevPage bool
HasNextPage bool
2024-08-08 23:09:07 +02:00
NoResults bool
2024-08-11 21:45:52 +02:00
Theme string
2024-04-05 12:44:11 +02:00
} {
2024-05-24 14:07:16 +02:00
Results : combinedResults ,
2024-04-08 13:15:23 +02:00
Query : query ,
Page : page ,
2024-05-24 14:07:16 +02:00
Fetched : fmt . Sprintf ( "%.2f seconds" , elapsedTime . Seconds ( ) ) ,
2024-04-08 13:15:23 +02:00
LanguageOptions : languageOptions ,
CurrentLang : lang ,
HasPrevPage : page > 1 ,
2024-05-24 14:07:16 +02:00
HasNextPage : len ( combinedResults ) >= 50 ,
2024-08-08 23:09:07 +02:00
NoResults : len ( combinedResults ) == 0 ,
2024-08-11 21:45:52 +02:00
Theme : settings . Theme ,
2024-04-05 12:44:11 +02:00
}
err = tmpl . Execute ( w , data )
if err != nil {
log . Printf ( "Error executing template: %v" , err )
http . Error ( w , "Internal Server Error" , http . StatusInternalServerError )
}
}
2024-05-24 14:07:16 +02:00
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 {
log . Println ( "Cache hit" )
cacheChan <- results
} else {
log . Println ( "Cache miss" )
cacheChan <- nil
}
} ( )
select {
case results := <- cacheChan :
if results == nil {
2024-06-10 11:49:40 +02:00
combinedResults = fetchImageResults ( query , safe , lang , page )
2024-06-12 14:51:45 +02:00
if len ( combinedResults ) > 0 {
resultsCache . Set ( cacheKey , convertToSearchResults ( combinedResults ) )
}
2024-05-24 14:07:16 +02:00
} else {
_ , _ , imageResults := convertToSpecificResults ( results )
combinedResults = imageResults
}
case <- time . After ( 2 * time . Second ) :
log . Println ( "Cache check timeout" )
2024-06-10 11:49:40 +02:00
combinedResults = fetchImageResults ( query , safe , lang , page )
2024-06-12 14:51:45 +02:00
if len ( combinedResults ) > 0 {
resultsCache . Set ( cacheKey , convertToSearchResults ( combinedResults ) )
}
2024-05-24 14:07:16 +02:00
}
return combinedResults
}
2024-06-10 11:49:40 +02:00
func fetchImageResults ( query , safe , lang string , page int ) [ ] ImageSearchResult {
2024-06-12 14:51:45 +02:00
var results [ ] ImageSearchResult
2024-05-24 14:07:16 +02:00
2024-06-16 00:14:21 +02:00
for _ , engine := range imageSearchEngines {
2024-06-12 14:51:45 +02:00
log . Printf ( "Using image search engine: %s" , engine . Name )
2024-06-16 00:14:21 +02:00
searchResults , duration , err := engine . Func ( query , safe , lang , page )
2024-06-14 17:56:20 +02:00
updateEngineMetrics ( & engine , duration , err == nil )
2024-06-12 14:51:45 +02:00
if err != nil {
log . Printf ( "Error performing image search with %s: %v" , engine . Name , err )
continue
}
2024-06-14 17:56:20 +02:00
for _ , result := range searchResults {
results = append ( results , result . ( ImageSearchResult ) )
}
2024-06-16 00:14:21 +02:00
// If results are found, break out of the loop
2024-06-12 14:51:45 +02:00
if len ( results ) > 0 {
break
}
2024-06-10 11:49:40 +02:00
}
2024-05-24 14:07:16 +02:00
2024-06-16 00:14:21 +02:00
// If no results found after trying all engines
if len ( results ) == 0 {
2024-08-08 23:09:07 +02:00
log . Printf ( "No image results found for query: %s, trying other nodes" , query )
2024-08-09 12:59:37 +02:00
results = tryOtherNodesForImageSearch ( query , safe , lang , page , [ ] string { hostID } )
2024-06-16 00:14:21 +02:00
}
2024-05-24 14:07:16 +02:00
return results
}
2024-06-10 11:49:40 +02:00
2024-06-14 17:56:20 +02:00
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
2024-06-10 11:49:40 +02:00
}
2024-06-14 17:56:20 +02:00
return searchResults , duration , nil
2024-06-10 11:49:40 +02:00
}
}