mirror of
https://github.com/searxng/searxng.git
synced 2026-06-11 04:17:50 +02:00
177 lines
5.5 KiB
Python
177 lines
5.5 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""Fireball_ is a Germany-based, privacy-focused search engine.
|
|
|
|
It likely doesn't have its own index, but it's unclear where its results come from.
|
|
|
|
.. _Fireball: https://fireball.com
|
|
"""
|
|
|
|
import typing as t
|
|
|
|
from datetime import datetime
|
|
from urllib.parse import urlencode
|
|
|
|
from searx.enginelib import EngineCache
|
|
from searx.exceptions import SearxEngineAPIException
|
|
from searx.extended_types import SXNG_Response
|
|
|
|
from searx.result_types import EngineResults
|
|
from searx.network import post
|
|
from searx.utils import html_to_text
|
|
|
|
if t.TYPE_CHECKING:
|
|
from searx.search.processors import OnlineParams
|
|
|
|
about = {
|
|
"website": "https://fireball.com",
|
|
"official_api_documentation": None,
|
|
"use_official_api": False,
|
|
"require_api_key": False,
|
|
"results": "JSON",
|
|
}
|
|
|
|
base_url = "https://fireball.com"
|
|
categories = ["general"]
|
|
fireball_category = "web" # values: "web", "news", "videos"
|
|
|
|
paging = False
|
|
safesearch = True
|
|
|
|
safe_search_map = {0: "off", 1: "moderate", 2: "strict"}
|
|
|
|
CACHE: EngineCache
|
|
"""Cache to store the settings cookie (contains e.g. language, safesearch, ...)."""
|
|
|
|
CACHE_VALID_DURATION = 30 * 24 * 3600 # one month, same as website
|
|
"""Duration how long settings cookies are valid."""
|
|
|
|
|
|
def init(_):
|
|
if fireball_category not in ("web", "news", "videos"):
|
|
raise ValueError(f"Unsupported category: {fireball_category}")
|
|
|
|
|
|
def setup(engine_settings: dict[str, t.Any]) -> bool:
|
|
global CACHE # pylint: disable=global-statement
|
|
CACHE = EngineCache(engine_settings["name"])
|
|
return True
|
|
|
|
|
|
def _cache_key(fireball_settings: dict[str, str]) -> str:
|
|
return f"fireball_settings_{fireball_settings['safesearch']}_{fireball_settings['market']}"
|
|
|
|
|
|
def _get_search_settings_cookie(params: 'OnlineParams') -> str:
|
|
"""
|
|
Get a 'fireball' cookie for the given locale and safesearch setting set in params.
|
|
"""
|
|
|
|
# the language is set by only specifying the search country
|
|
# on their website, they only list DE and US, but in fact it
|
|
# supports much more countries
|
|
country = "US"
|
|
if params["searxng_locale"] != "all":
|
|
language_parts = params["searxng_locale"].split("-")
|
|
country = language_parts[-1].upper()
|
|
|
|
fireball_settings = {
|
|
"action": "save",
|
|
"language": "en", # language is irrelevant, only changes UI language
|
|
"market": country,
|
|
"adprovider": "automatic",
|
|
"target": "_blank",
|
|
"tiles": "on",
|
|
"safesearch": safe_search_map[params["safesearch"]],
|
|
}
|
|
cache_key = _cache_key(fireball_settings)
|
|
|
|
cached_cookie = CACHE.get(cache_key)
|
|
if cached_cookie:
|
|
return cached_cookie
|
|
|
|
resp = post("https://fireball.com/settings", data=fireball_settings)
|
|
if not resp.ok:
|
|
raise SearxEngineAPIException("failed to obtain cookie for settings")
|
|
|
|
cookie = resp.cookies.get("fireball")
|
|
if not cookie:
|
|
raise SearxEngineAPIException("failed to obtain cookie for settings")
|
|
|
|
CACHE.set(cache_key, cookie, expire=CACHE_VALID_DURATION)
|
|
return cookie
|
|
|
|
|
|
def request(query: str, params: 'OnlineParams'):
|
|
# no matter the category, the request is always the same
|
|
# i.e. we get all different categories with one HTTP request
|
|
|
|
args = {
|
|
"f": "web",
|
|
"q": query,
|
|
}
|
|
|
|
params["url"] = f"{base_url}/getResults/?{urlencode(args)}"
|
|
params["cookies"]["fireball"] = _get_search_settings_cookie(params)
|
|
|
|
# referer header has to be set, otherwise the requests get blocked
|
|
params["headers"]["Referer"] = f"{base_url}/search?{urlencode(args)}"
|
|
|
|
|
|
def response(resp: 'SXNG_Response') -> EngineResults:
|
|
res = EngineResults()
|
|
|
|
json_data = resp.json()
|
|
|
|
for result in json_data.get(fireball_category, {}).get("results", []):
|
|
published_date = None
|
|
if result.get("page_age"):
|
|
published_date = datetime.fromisoformat(result["page_age"])
|
|
|
|
if fireball_category == "web":
|
|
res.add(
|
|
res.types.MainResult(
|
|
url=result["url"],
|
|
title=html_to_text(result["title"]),
|
|
content=html_to_text(result["description"]),
|
|
publishedDate=published_date,
|
|
)
|
|
)
|
|
elif fireball_category == "news":
|
|
thumbnail: str | None = None
|
|
if result.get("thumbnail"):
|
|
thumbnail = result["thumbnail"]["src"]
|
|
|
|
res.add(
|
|
res.types.MainResult(
|
|
url=result["url"],
|
|
title=html_to_text(result["title"]),
|
|
content=html_to_text(result["description"]),
|
|
thumbnail=thumbnail or "",
|
|
publishedDate=published_date,
|
|
)
|
|
)
|
|
elif fireball_category == "videos":
|
|
thumbnail = None
|
|
if result.get("thumbnail"):
|
|
thumbnail = result["thumbnail"]["original"]
|
|
|
|
length = None
|
|
if result.get("video"):
|
|
length = result["video"].get("duration")
|
|
|
|
res.add(
|
|
res.types.LegacyResult(
|
|
{
|
|
"template": "videos.html",
|
|
"url": result["url"],
|
|
"title": html_to_text(result["title"]),
|
|
"content": html_to_text(result["description"]),
|
|
"thumbnail": thumbnail,
|
|
"length": length,
|
|
"publishedDate": published_date,
|
|
}
|
|
)
|
|
)
|
|
|
|
return res
|