80 lines
2.3 KiB
Python
80 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import urllib.parse
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterable
|
|
|
|
from reader import EntrySearchResult
|
|
from reader import Feed
|
|
from reader import HighlightedString
|
|
from reader import Reader
|
|
|
|
|
|
def create_search_context(query: str, reader: Reader) -> dict:
|
|
"""Build context for search.html template.
|
|
|
|
Args:
|
|
query (str): The search query.
|
|
reader (Reader): Custom Reader instance.
|
|
|
|
Returns:
|
|
dict: Context dictionary for rendering the search results.
|
|
"""
|
|
search_results: Iterable[EntrySearchResult] = reader.search_entries(query)
|
|
|
|
results: list[dict] = []
|
|
for result in search_results:
|
|
feed: Feed = reader.get_feed(result.feed_url)
|
|
feed_url: str = urllib.parse.quote(feed.url)
|
|
|
|
# Prefer summary, fall back to content
|
|
if ".summary" in result.content:
|
|
highlighted = result.content[".summary"]
|
|
else:
|
|
content_keys = [k for k in result.content if k.startswith(".content")]
|
|
highlighted = result.content[content_keys[0]] if content_keys else None
|
|
|
|
summary: str = add_spans(highlighted) if highlighted else "(no preview available)"
|
|
|
|
results.append({
|
|
"title": add_spans(result.metadata.get(".title")),
|
|
"summary": summary,
|
|
"feed_url": feed_url,
|
|
})
|
|
|
|
return {
|
|
"query": query,
|
|
"search_amount": {"total": len(results)},
|
|
"results": results,
|
|
}
|
|
|
|
|
|
def add_spans(highlighted_string: HighlightedString | None) -> str:
|
|
"""Wrap all highlighted parts with <span> tags.
|
|
|
|
Args:
|
|
highlighted_string (HighlightedString | None): The highlighted string to process.
|
|
|
|
Returns:
|
|
str: The processed string with <span> tags around highlighted parts.
|
|
"""
|
|
if highlighted_string is None:
|
|
return ""
|
|
|
|
value: str = highlighted_string.value
|
|
parts: list[str] = []
|
|
last_index = 0
|
|
|
|
for txt_slice in highlighted_string.highlights:
|
|
parts.extend((
|
|
value[last_index : txt_slice.start],
|
|
f"<span class='bg-warning'>{value[txt_slice.start : txt_slice.stop]}</span>",
|
|
))
|
|
last_index = txt_slice.stop
|
|
|
|
# add any trailing text
|
|
parts.append(value[last_index:])
|
|
|
|
return "".join(parts)
|