fix: unescape HTML entities in result titles
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6s
Mirror to GitHub / mirror (push) Failing after 3s
Tests / test (push) Failing after 19s

Wikipedia returns HTML entities like <span> which were being
double-escaped by Go templates. Now using html.UnescapeString and
template.HTML to render properly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ashisgreat22 2026-03-22 22:19:07 +01:00
parent 37420ae5a8
commit 23dcdef26f
2 changed files with 13 additions and 3 deletions

View file

@ -1,7 +1,7 @@
{{define "result_item"}} {{define "result_item"}}
<article class="result"> <article class="result">
<div class="result_header"> <div class="result_header">
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a> <a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.SafeTitle}}</a>
</div> </div>
<div class="result_url"> <div class="result_url">
<img class="result-favicon" src="https://www.google.com/s2/favicons?domain={{.URL | urlquery}}&sz=32" alt="" loading="lazy" onerror="this.style.display='none'"> <img class="result-favicon" src="https://www.google.com/s2/favicons?domain={{.URL | urlquery}}&sz=32" alt="" loading="lazy" onerror="this.style.display='none'">
@ -9,7 +9,7 @@
<span class="engine-badge">{{.Engine}}</span> <span class="engine-badge">{{.Engine}}</span>
</div> </div>
{{if .Content}} {{if .Content}}
<p class="result_content">{{.Content}}</p> <p class="result_content">{{.SafeContent}}</p>
{{end}} {{end}}
</article> </article>
{{end}} {{end}}

View file

@ -19,6 +19,7 @@ package views
import ( import (
"embed" "embed"
"encoding/xml" "encoding/xml"
"html"
"html/template" "html/template"
"io/fs" "io/fs"
"net/http" "net/http"
@ -70,6 +71,10 @@ type ResultView struct {
// TemplateName is the actual template to dispatch to, computed from Template. // TemplateName is the actual template to dispatch to, computed from Template.
// "videos" maps to "video_item", everything else maps to "result_item". // "videos" maps to "video_item", everything else maps to "result_item".
TemplateName string TemplateName string
// SafeTitle and SafeContent are HTML-unescaped versions for rendering.
// The API returns HTML entities which Go templates escape by default.
SafeTitle template.HTML
SafeContent template.HTML
} }
// PageNumber represents a numbered pagination button. // PageNumber represents a numbered pagination button.
@ -205,7 +210,12 @@ func FromResponse(resp contracts.SearchResponse, query string, pageno int, activ
r.URL = &safe r.URL = &safe
} }
r.Thumbnail = util.SanitizeResultURL(r.Thumbnail) r.Thumbnail = util.SanitizeResultURL(r.Thumbnail)
pd.Results[i] = ResultView{MainResult: r, TemplateName: tmplName} pd.Results[i] = ResultView{
MainResult: r,
TemplateName: tmplName,
SafeTitle: template.HTML(html.UnescapeString(r.Title)),
SafeContent: template.HTML(html.UnescapeString(r.Content)),
}
} }
// Convert answers (they're map[string]any — extract string values). // Convert answers (they're map[string]any — extract string values).