added: serving missing.svg on error instead of an invalid image URL

This commit is contained in:
partisan 2024-10-19 14:02:27 +02:00
parent 1721db85a7
commit 787816d0ab
7 changed files with 263 additions and 57 deletions

108
images.go
View file

@ -68,16 +68,18 @@ func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string
if results == nil {
combinedResults = fetchImageResults(query, safe, lang, page)
if len(combinedResults) > 0 {
combinedResults = filterValidImages(combinedResults)
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
}
} else {
_, _, imageResults := convertToSpecificResults(results)
combinedResults = imageResults
combinedResults = filterValidImages(imageResults)
}
case <-time.After(2 * time.Second):
printInfo("Cache check timeout")
combinedResults = fetchImageResults(query, safe, lang, page)
if len(combinedResults) > 0 {
combinedResults = filterValidImages(combinedResults)
resultsCache.Set(cacheKey, convertToSearchResults(combinedResults))
}
}
@ -87,6 +89,7 @@ func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string
func fetchImageResults(query, safe, lang string, page int) []ImageSearchResult {
var results []ImageSearchResult
safeBool := safe == "active"
for _, engine := range imageSearchEngines {
printInfo("Using image search engine: %s", engine.Name)
@ -107,20 +110,28 @@ func fetchImageResults(query, safe, lang string, page int) []ImageSearchResult {
hash := hex.EncodeToString(hasher.Sum(nil))
filename := hash + ".webp"
// Set the Full URL to point to the cached image path
cacheURL := "/image_cache/" + filename
imageResult.ProxyFull = cacheURL
// Assign the ID
imageResult.ID = hash
// Start caching in the background
go func(originalURL, filename string) {
_, err := cacheImage(originalURL, filename)
// Set the ProxyFull URL
imageResult.ProxyFull = "/image_cache/" + filename
// Start caching and validation in the background
go func(imgResult ImageSearchResult, originalURL, filename string) {
_, success, err := cacheImage(originalURL, filename, imgResult.ID)
if err != nil {
printWarn("Failed to cache image %s: %v", originalURL, err)
}
}(imageResult.Full, filename)
if !success {
// Remove the image result from the cache
removeImageResultFromCache(query, page, safeBool, lang, imgResult.ID)
}
}(imageResult, imageResult.Full, filename)
} else {
// When hard cache is not enabled, use the imgproxy URLs
imageResult.ProxyThumb = "/imgproxy?url=" + imageResult.Thumb // Proxied thumbnail
imageResult.ProxyFull = "/imgproxy?url=" + imageResult.Full // Proxied full-size image
}
results = append(results, imageResult)
}
@ -151,3 +162,82 @@ func wrapImageSearchFunc(f func(string, string, string, int) ([]ImageSearchResul
return searchResults, duration, nil
}
}
// func isValidImageURL(imageURL string) bool {
// client := &http.Client{
// Timeout: 10 * time.Second,
// Transport: &http.Transport{
// TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
// },
// }
// req, err := http.NewRequest("GET", imageURL, nil)
// if err != nil {
// return false
// }
// // Set headers to mimic a real browser
// req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "+
// "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36")
// req.Header.Set("Accept", "image/webp,image/*,*/*;q=0.8")
// req.Header.Set("Accept-Language", "en-US,en;q=0.9")
// req.Header.Set("Referer", imageURL) // Some servers require a referer
// resp, err := client.Do(req)
// if err != nil {
// return false
// }
// defer resp.Body.Close()
// if resp.StatusCode < 200 || resp.StatusCode >= 400 {
// return false
// }
// // Limit the amount of data read to 10KB
// limitedReader := io.LimitReader(resp.Body, 10240) // 10KB
// // Attempt to decode image configuration
// _, _, err = image.DecodeConfig(limitedReader)
// if err != nil {
// return false
// }
// return true
// }
// // This function can be used alternatively to isValidImageURL(), Its slower but reliable
// func isImageAccessible(imageURL string) bool {
// client := &http.Client{
// Timeout: 5 * time.Second,
// CheckRedirect: func(req *http.Request, via []*http.Request) error {
// if len(via) >= 10 {
// return http.ErrUseLastResponse
// }
// return nil
// },
// }
// resp, err := client.Get(imageURL)
// if err != nil {
// return false
// }
// defer resp.Body.Close()
// if resp.StatusCode < 200 || resp.StatusCode >= 400 {
// return false
// }
// // Read the entire image data
// data, err := io.ReadAll(resp.Body)
// if err != nil {
// return false
// }
// // Try to decode the image
// _, _, err = image.Decode(bytes.NewReader(data))
// if err != nil {
// return false
// }
// return true
// }