115 lines
3.1 KiB
TypeScript
115 lines
3.1 KiB
TypeScript
import { resources } from "@lib/resources.ts";
|
|
import fuzzysort from "fuzzysort";
|
|
import { extractHashTags } from "@lib/string.ts";
|
|
import { listResources } from "./marka/index.ts";
|
|
import { GenericResource } from "./marka/schema.ts";
|
|
import { parseRating } from "./helpers.ts";
|
|
|
|
type ResourceType = keyof typeof resources;
|
|
|
|
type SearchParams = {
|
|
q: string;
|
|
types?: string[];
|
|
tags?: string[];
|
|
rating?: number;
|
|
authors?: string[];
|
|
};
|
|
|
|
export function parseResourceUrl(_url: string | URL): SearchParams | undefined {
|
|
try {
|
|
const url = typeof _url === "string" ? new URL(_url) : _url;
|
|
let query = url.searchParams.get("q") || "*";
|
|
if (!(typeof query === "string")) {
|
|
return undefined;
|
|
}
|
|
query = decodeURIComponent(query);
|
|
|
|
const hashTags = extractHashTags(query);
|
|
|
|
for (const tag of hashTags) {
|
|
query = query.replace("#" + tag, "");
|
|
}
|
|
|
|
return {
|
|
q: query,
|
|
types: url.searchParams.get("type")?.split(",") as ResourceType[] ||
|
|
undefined,
|
|
tags: hashTags,
|
|
rating: url.searchParams.has("rating")
|
|
? parseInt(url.searchParams.get("rating")!)
|
|
: undefined,
|
|
};
|
|
} catch (_err) {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
const isResource = (
|
|
item: GenericResource | boolean | undefined,
|
|
): item is GenericResource => {
|
|
return !!item;
|
|
};
|
|
|
|
export async function searchResource(
|
|
{ q, tags = [], types, rating }: SearchParams,
|
|
): Promise<GenericResource[]> {
|
|
const resources = (await Promise.all([
|
|
(!types || types.includes("movies")) && listResources("movies"),
|
|
(!types || types.includes("series")) && listResources("series"),
|
|
(!types || types.includes("articles")) && listResources("articles"),
|
|
(!types || types.includes("recipes")) && listResources("recipes"),
|
|
])).flat().filter(isResource);
|
|
|
|
console.log({ types, rating, tags, q, resourceLength: resources.length });
|
|
|
|
const results: Record<string, GenericResource> = {};
|
|
|
|
for (const resource of resources) {
|
|
if (
|
|
!(resource.name in results) &&
|
|
tags?.length && resource.content.keywords?.length &&
|
|
tags.every((t) => resource.content.keywords?.includes(t))
|
|
) {
|
|
results[resource.name] = resource;
|
|
}
|
|
|
|
// Select not-rated resources
|
|
if (
|
|
rating === 0 &&
|
|
resource.content?.reviewRating?.ratingValue === undefined
|
|
) {
|
|
results[resource.name] = resource;
|
|
}
|
|
|
|
if (
|
|
typeof rating === "number" &&
|
|
rating !== 0 &&
|
|
resource.content.reviewRating?.ratingValue &&
|
|
parseRating(resource.content.reviewRating.ratingValue) >= rating
|
|
) {
|
|
results[resource.name] = resource;
|
|
}
|
|
}
|
|
|
|
if (q.length && q !== "*") {
|
|
q = decodeURIComponent(q);
|
|
const fuzzyResult = fuzzysort.go(q, resources, {
|
|
keys: [
|
|
"name",
|
|
"content.articleBody",
|
|
"content.reviewBody",
|
|
"content.name",
|
|
"content.description",
|
|
"content.author.name",
|
|
],
|
|
threshold: 0.3,
|
|
});
|
|
console.log({ fuzzyResult });
|
|
for (const result of fuzzyResult) {
|
|
results[result.obj.name] = result.obj;
|
|
}
|
|
}
|
|
|
|
return Object.values(results);
|
|
}
|