From 235307b156164d8a562594bd4d3485b39e83c98d Mon Sep 17 00:00:00 2001 From: Allen Date: Sat, 12 Oct 2024 21:33:22 +0200 Subject: [PATCH] [init] poc frontend for searxng --- .env.example => .env.example_hearchco | 0 .env.example_searxng | 14 ++ .tool-versions | 3 + Makefile | 21 +-- README.md | 36 ++++- .../components/results/general/single.svelte | 43 ++++-- src/lib/components/results/images/main.svelte | 6 +- .../components/results/images/single.svelte | 81 ++++++++---- src/lib/components/themetoggle/main.svelte | 11 +- src/lib/functions/api/fetchversion.js | 8 +- src/routes/search/+page.js | 125 ++++++++++++------ 11 files changed, 259 insertions(+), 89 deletions(-) rename .env.example => .env.example_hearchco (100%) create mode 100644 .env.example_searxng create mode 100644 .tool-versions diff --git a/.env.example b/.env.example_hearchco similarity index 100% rename from .env.example rename to .env.example_hearchco diff --git a/.env.example_searxng b/.env.example_searxng new file mode 100644 index 0000000..53796ea --- /dev/null +++ b/.env.example_searxng @@ -0,0 +1,14 @@ +PUBLIC_UI_VERSION=dev + +# hearchco webui +PUBLIC_URI=https://hearchco.pi.local + +# searxNG +PUBLIC_SEARXNG=true +API_URI=https://search.pi.local +# allow self-signed https certificates (to searxng api) +NODE_TLS_REJECT_UNAUTHORIZED=0 + +# PUBLIC_API_URI is the webui which your devices should reach +# PUBLIC_API_URI must be allowed in cors (http headers) searxNG settings.yml +PUBLIC_API_URI=https://hearchco.pi.local diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..5c9cf07 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,3 @@ +#nodejs 21.5.0 +nodejs 18.19.0 + diff --git a/Makefile b/Makefile index 9f72639..decb69b 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,31 @@ install: - pnpm install --frozen-lockfile + yarn install --frozen-lockfile + sed -i -E 's|npm:@sveltejs/kit@[^/"]+|@sveltejs/kit|g' ./node_modules/@hearchco/sveltekit-adapter-aws/handler/index.js update: - pnpm update + yarn update dev: - pnpm run dev + yarn run dev -- --host 0.0.0.0 --port 5173 compile: - pnpm run build + yarn run build preview: - pnpm run preview + yarn run preview -- --host 0.0.0.0 check: - pnpm run check + yarn run check test: - pnpm run test:unit + yarn run test:unit lint: - pnpm run lint + yarn run lint format: - pnpm run format + yarn run format adapter-aws: cp svelte.config.aws.js svelte.config.js @@ -33,4 +34,4 @@ adapter-node: cp svelte.config.node.js svelte.config.js adapter-auto: - cp svelte.config.auto.js svelte.config.js \ No newline at end of file + cp svelte.config.auto.js svelte.config.js diff --git a/README.md b/README.md index 3b30d44..b482e19 100644 --- a/README.md +++ b/README.md @@ -1 +1,35 @@ -# Hearchco frontend repository built using SvelteKit & TailwindCSS +## SearxNG frontend built using SvelteKit & TailwindCSS +Adopted from [Hearchco/frontend](https://github.com/hearchco/frontend) + +## FAQ +POC POC POC + + +## Install +``` +cd /opt +git clone https://github.com/allendema/searxng-svelte.git +cd searxng-svelte +make install +``` + +## Setup + +## Edit `.env` file with your domain. +## Add HTTP Headers for your frontend domain to searxNG settings.yml and restart it. +In 'server' -> 'default\_http\_headers' section: +```yaml + Access-Control-Allow-Origin: "https://*.pi.local" + Access-Control-Allow-Methods: "GET, POST" + Access-Control-Allow-Headers: "Content-Type, Authorization" +``` + +`make dev` + +then visit your domain/webui to search! + +## TODO + - fix image previews + - copy search url + - systemd service + - use [bunJS](https://bun.sh/) instead of yarn/pnpm. diff --git a/src/lib/components/results/general/single.svelte b/src/lib/components/results/general/single.svelte index 5acb8b9..9e26c93 100644 --- a/src/lib/components/results/general/single.svelte +++ b/src/lib/components/results/general/single.svelte @@ -1,6 +1,9 @@ -
- -
+{#if !isSearxng} +
+ +
+{/if} + +{#if isSearxng} +
+ +
+{/if} diff --git a/src/lib/components/themetoggle/main.svelte b/src/lib/components/themetoggle/main.svelte index e65fda7..6fe1c90 100644 --- a/src/lib/components/themetoggle/main.svelte +++ b/src/lib/components/themetoggle/main.svelte @@ -1,5 +1,8 @@ diff --git a/src/lib/functions/api/fetchversion.js b/src/lib/functions/api/fetchversion.js index 6e6a76a..f9ac9e4 100644 --- a/src/lib/functions/api/fetchversion.js +++ b/src/lib/functions/api/fetchversion.js @@ -5,7 +5,7 @@ import { createApiUrl } from '$lib/functions/api/createurl.js'; * @param {typeof fetch} [fetcher] * @returns {Promise} */ -export async function fetchVersion(fetcher = fetch) { +export async function fetchVersionUpstream(fetcher = fetch) { /** @type {URL} */ let apiUrl; try { @@ -35,3 +35,9 @@ export async function fetchVersion(fetcher = fetch) { return version; } + +export async function fetchVersion(fetcher = fetch) { + const version = 'searxng'; + + return version; +} diff --git a/src/routes/search/+page.js b/src/routes/search/+page.js index e9df9f0..be25a57 100644 --- a/src/routes/search/+page.js +++ b/src/routes/search/+page.js @@ -1,6 +1,14 @@ +import { env as envPubSearxng } from '$env/dynamic/public'; import { browser } from '$app/environment'; import { error } from '@sveltejs/kit'; +const isSearxng = envPubSearxng.PUBLIC_SEARXNG === 'true'; + +//export const csr = isSearxng ? true : false; +export const csr = isSearxng ? false : undefined; // works with searxng + +//console.log("is csr: " + csr); + import { getCategoryFromQuery, getQueryWithoutCategory } from '$lib/functions/query/category'; import { concatSearchParams } from '$lib/functions/api/concatparams'; import { fetchResults } from '$lib/functions/api/fetchresults'; @@ -40,19 +48,57 @@ export async function load({ url, fetch }) { throw error(400, "Only category specified in 'q' parameter"); } - // Concatenate search params. - const newSearchParams = concatSearchParams([ - ['q', queryWithoutCategory], - ['category', category !== CategoryEnum.GENERAL ? category : ''], - ['start', currentPage !== 1 ? currentPage.toString() : ''], - ['pages', maxPages !== 1 ? maxPages.toString() : ''] - ]); + var newSearchParams = null; + // console.log("isSearxng: " + isSearxng); + // console.log(toCategoryType(category)); + + // newSearchParams if hearchco backend + if (!isSearxng) { + // Concatenate search params. + var newSearchParams = concatSearchParams([ + ['q', queryWithoutCategory], + ['category', category !== CategoryEnum.GENERAL ? category : ''], + ['start', currentPage !== 1 ? currentPage.toString() : ''], + ['pages', maxPages !== 1 ? maxPages.toString() : ''] + ]); + } + + // newSearchParams if isSearxng backend + if (isSearxng) { + // hearchco to searxng backend 'categories' conversions + const categoryParamsMap = { + [CategoryEnum.GENERAL]: () => [ + ['categories', 'general'], + ['format', 'json'] + ], + [CategoryEnum.IMAGES]: () => [ + ['categories', 'images'], + ['format', 'json'] + ], + [CategoryEnum.SCIENCE]: () => [ + ['categories', 'science'], + ['format', 'json'] + ], + [CategoryEnum.THOROUGH]: () => [ + ['categories', 'science,music,news,social_media,general'], + ['format', 'json'] + ] + }; + + // Concatenate searxng search params. + var newSearchParams = concatSearchParams([ + ['q', queryWithoutCategory], + ['pageno', currentPage.toString()], + ...categoryParamsMap[category]() + ]); + } + // console.log(newSearchParams); // Fetch results. const respP = fetchResults(newSearchParams, fetch); - // If not an exchange query, return results. - if (!exchangery(queryWithoutCategory)) { + // If category in CategoryEnum, return results. + if (typeof toCategoryType(category) !== 'undefined') { const resp = await respP; return { browser: browser, @@ -66,31 +112,33 @@ export async function load({ url, fetch }) { }; } - // Fetch exchange result. - const { from, to, amount } = extractExchangeQuery(queryWithoutCategory); - const currenciesP = fetchCurrencies(); - - // Wait for all promises to resolve. - const resp = await respP; - const currencies = await currenciesP; - - return { - browser: browser, - query: queryWithoutCategory, - currentPage: currentPage, - maxPages: maxPages, - category: category, - results: resp.results, - duration: resp.duration, - exchange: { - from: from, - to: to, - amount: amount, - currencies: new Map(Object.entries(currencies.currencies)) - } - }; -} + // exchange results + if (exchangery(queryWithoutCategory)) { + // Fetch exchange result. + const { from, to, amount } = extractExchangeQuery(queryWithoutCategory); + const currenciesP = fetchCurrencies(); + // Wait for all promises to resolve. + const resp = await respP; + const currencies = await currenciesP; + + return { + browser: browser, + query: queryWithoutCategory, + currentPage: currentPage, + maxPages: maxPages, + category: category, + results: resp.results, + duration: resp.duration, + exchange: { + from: from, + to: to, + amount: amount, + currencies: new Map(Object.entries(currencies.currencies)) + } + }; + } +} /** * Get category from URL or query. * @param {string} query - Query from URL. @@ -101,7 +149,7 @@ export async function load({ url, fetch }) { function getCategory(query, params) { const categoryFromQuery = getCategoryFromQuery(query); const categoryParam = params.get('category') ?? ''; - const category = + var category = categoryFromQuery !== '' ? toCategoryType(categoryFromQuery) : categoryParam !== '' @@ -110,9 +158,12 @@ function getCategory(query, params) { // Check if category is valid. if (!category) { - // Bad Request. - throw error(400, "Invalid 'category' parameter in URL or query"); + if (isSearxng) { + category = CategoryEnum.GENERAL; + } else { + // Bad Request. + throw error(400, "Invalid 'category' parameter in URL or query"); + } } - return category; }