fix(prefs): persist favicon choice and apply to HTML results
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 9s
Mirror to GitHub / mirror (push) Failing after 5s
Tests / test (push) Successful in 28s

- Save favicon cookie on POST /preferences; reflect selection in template
- Add getFaviconService helper; pass favicon service into FromResponse
- Compute ResultView.FaviconIconURL (none/google/duckduckgo/self proxy)
- Update result_item and video_item templates; add httpapi/views tests

Made-with: Cursor
This commit is contained in:
ashisgreat22 2026-03-23 23:08:21 +01:00
parent 518215f62e
commit 90ea4c9f56
7 changed files with 171 additions and 43 deletions

View file

@ -45,7 +45,7 @@ func NewHandler(searchSvc *search.Service, autocompleteSuggestions func(ctx cont
searchSvc: searchSvc,
autocompleteSvc: autocompleteSuggestions,
sourceURL: sourceURL,
faviconCache: faviconCache,
faviconCache: faviconCache,
}
}
@ -65,6 +65,17 @@ func (h *Handler) getTheme(r *http.Request) string {
return "light"
}
// getFaviconService returns the favicon provider from cookie (default "none").
func (h *Handler) getFaviconService(r *http.Request) string {
if cookie, err := r.Cookie("favicon"); err == nil {
switch cookie.Value {
case "none", "google", "duckduckgo", "self":
return cookie.Value
}
}
return "none"
}
// Index renders the homepage with the search box.
func (h *Handler) Index(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
@ -103,7 +114,7 @@ func (h *Handler) Search(w http.ResponseWriter, r *http.Request) {
req, err := search.ParseSearchRequest(r)
if err != nil {
if format == "html" || format == "" {
pd := views.PageData{SourceURL: h.sourceURL, Query: q, Theme: h.getTheme(r)}
pd := views.PageData{SourceURL: h.sourceURL, Query: q, Theme: h.getTheme(r), FaviconService: h.getFaviconService(r)}
if views.IsHTMXRequest(r) {
views.RenderSearchFragment(w, pd)
} else {
@ -118,7 +129,7 @@ func (h *Handler) Search(w http.ResponseWriter, r *http.Request) {
resp, err := h.searchSvc.Search(r.Context(), req)
if err != nil {
if req.Format == contracts.FormatHTML {
pd := views.PageData{SourceURL: h.sourceURL, Query: req.Query, Theme: h.getTheme(r)}
pd := views.PageData{SourceURL: h.sourceURL, Query: req.Query, Theme: h.getTheme(r), FaviconService: h.getFaviconService(r)}
if views.IsHTMXRequest(r) {
views.RenderSearchFragment(w, pd)
} else {
@ -132,7 +143,7 @@ func (h *Handler) Search(w http.ResponseWriter, r *http.Request) {
if req.Format == contracts.FormatHTML {
pd := views.FromResponse(resp, req.Query, req.Pageno,
r.FormValue("category"), r.FormValue("time"), r.FormValue("type"))
r.FormValue("category"), r.FormValue("time"), r.FormValue("type"), h.getFaviconService(r))
pd.Theme = h.getTheme(r)
if err := views.RenderSearchAuto(w, r, pd); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
@ -182,6 +193,19 @@ func (h *Handler) Preferences(w http.ResponseWriter, r *http.Request) {
SameSite: http.SameSiteLaxMode,
})
}
// Persist favicon provider preference.
favicon := strings.TrimSpace(r.FormValue("favicon"))
switch favicon {
case "none", "google", "duckduckgo", "self":
http.SetCookie(w, &http.Cookie{
Name: "favicon",
Value: favicon,
Path: "/",
MaxAge: 86400 * 365,
HttpOnly: false,
SameSite: http.SameSiteLaxMode,
})
}
http.Redirect(w, r, "/preferences", http.StatusFound)
return
}
@ -192,7 +216,7 @@ func (h *Handler) Preferences(w http.ResponseWriter, r *http.Request) {
theme = cookie.Value
}
}
if err := views.RenderPreferences(w, h.sourceURL, theme); err != nil {
if err := views.RenderPreferences(w, h.sourceURL, theme, h.getFaviconService(r)); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}