import { createDocument, getDocument, getDocuments, transformDocument, } from "@lib/documents.ts"; import { Root } from "https://esm.sh/remark-frontmatter@4.0.1"; import { getThumbhash } from "@lib/cache/image.ts"; import { GenericResource } from "@lib/types.ts"; import { parseRating } from "@lib/helpers.ts"; export async function addThumbnailToResource( res: T, ): Promise { const imageUrl = res?.meta?.image; if (!imageUrl) return res; const [thumbhash, average] = await getThumbhash({ url: imageUrl }); if (!thumbhash) return res; return { ...res, meta: { ...res?.meta, average: average, thumbnail: thumbhash, }, }; } type SortType = "rating" | "date" | "name" | "author"; function sortFunction(sortType: SortType) { return (a: T, b: T) => { switch (sortType) { case "rating": return parseRating(a.meta?.rating || 0) > parseRating(b.meta?.rating || 0) ? -1 : 1; case "date": return (a.meta?.date || 0) > (b.meta?.date || 0) ? -1 : 1; case "name": return a.name.localeCompare(b.name); case "author": return a.meta?.author?.localeCompare(b.meta?.author || ""); } }; } export function createCrud( { prefix, parse, render, hasThumbnails = false }: { prefix: string; hasThumbnails?: boolean; render?: (doc: T) => string; parse: (doc: string, id: string) => T; }, ) { function pathFromId(id: string) { return `${prefix}${id.replaceAll(":", "")}.md`; } async function read(id: string) { const path = pathFromId(id); const content = await getDocument(path); const res = parse(content, id); if (hasThumbnails) { return addThumbnailToResource(res); } return res; } function create(id: string, content: string | ArrayBuffer | T) { const path = pathFromId(id); if ( typeof content === "string" || content instanceof ArrayBuffer ) { return createDocument(path, content); } if (render) { return createDocument(path, render(content)); } throw new Error("No renderer defined for " + prefix + " CRUD"); } async function update(id: string, updater: (r: Root) => Root) { const path = pathFromId(id); const content = await getDocument(path); const newDoc = transformDocument(content, updater); await createDocument(path, newDoc); } async function readAll({ sort = "rating" }: { sort?: SortType } = {}) { const allDocuments = await getDocuments(); return (await Promise.all( allDocuments.filter((d) => { return d.name.startsWith(prefix) && d.contentType === "text/markdown" && !d.name.endsWith("index.md"); }).map((doc) => { const id = doc.name.replace(prefix, "").replace(/\.md$/, ""); return read(id); }), )).sort(sortFunction(sort)); } return { read, readAll, create, update, }; }