97 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { resources } from "@lib/resources.ts";
 | |
| import fuzzysort from "npm:fuzzysort";
 | |
| import { GenericResource } from "@lib/types.ts";
 | |
| import { extractHashTags } from "@lib/string.ts";
 | |
| import { Movie } from "@lib/resource/movies.ts";
 | |
| import { Article } from "@lib/resource/articles.ts";
 | |
| import { Recipe } from "@lib/resource/recipes.ts";
 | |
| import { Series } from "@lib/resource/series.ts";
 | |
| import { fetchResource } from "./resources.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 (!query) {
 | |
|       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: Movie | Series | Article | Recipe | boolean,
 | |
| ): item is Movie | Series | Article | Recipe => {
 | |
|   return !!item;
 | |
| };
 | |
| 
 | |
| export async function searchResource(
 | |
|   { q, tags = [], types, rating }: SearchParams,
 | |
| ): Promise<GenericResource[]> {
 | |
|   const resources = (await Promise.all([
 | |
|     (!types || types.includes("movie")) && fetchResource("movies"),
 | |
|     (!types || types.includes("series")) && fetchResource("series"),
 | |
|     (!types || types.includes("article")) && fetchResource("articles"),
 | |
|     (!types || types.includes("recipe")) && fetchResource("recipes"),
 | |
|   ])).flat().filter(isResource);
 | |
| 
 | |
|   const results: Record<string, GenericResource> = {};
 | |
| 
 | |
|   for (const resource of resources) {
 | |
|     if (
 | |
|       !(resource.id in results) &&
 | |
|       tags?.length && resource.tags.length &&
 | |
|       tags.every((t) => resource.tags.includes(t))
 | |
|     ) {
 | |
|       results[resource.id] = resource;
 | |
|     }
 | |
| 
 | |
|     if (
 | |
|       !(resource.id in results) &&
 | |
|       rating && resource?.meta?.rating && resource.meta.rating >= rating
 | |
|     ) {
 | |
|       results[resource.id] = resource;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (q.length && q !== "*") {
 | |
|     const fuzzyResult = fuzzysort.go(q, resources, {
 | |
|       keys: ["content", "name", "description", "meta.author"],
 | |
|       threshold: 0.3,
 | |
|     });
 | |
|     for (const result of fuzzyResult) {
 | |
|       results[result.obj.id] = result.obj;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Object.values(results);
 | |
| }
 |