2023-08-07 14:44:04 +02:00
|
|
|
import { parseDocument } from "@lib/documents.ts";
|
|
|
|
import { parse, stringify } from "yaml";
|
|
|
|
import { createCrud } from "@lib/crud.ts";
|
|
|
|
import { extractHashTags, formatDate } from "@lib/string.ts";
|
|
|
|
import { fixRenderedMarkdown } from "@lib/helpers.ts";
|
2023-08-11 16:13:20 +02:00
|
|
|
import { getThumbhash } from "@lib/cache/image.ts";
|
2023-08-07 14:44:04 +02:00
|
|
|
|
|
|
|
export type Series = {
|
|
|
|
id: string;
|
|
|
|
name: string;
|
|
|
|
description: string;
|
|
|
|
type: "series";
|
|
|
|
tags: string[];
|
|
|
|
meta: {
|
|
|
|
date: Date;
|
|
|
|
image: string;
|
|
|
|
author: string;
|
|
|
|
rating: number;
|
2023-08-11 16:13:20 +02:00
|
|
|
thumbnail?: string;
|
2023-08-07 14:44:04 +02:00
|
|
|
status: "not-seen" | "watch-again" | "finished";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
function renderSeries(movie: Series) {
|
|
|
|
const meta = movie.meta;
|
|
|
|
if ("date" in meta) {
|
|
|
|
meta.date = formatDate(meta.date);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fixRenderedMarkdown(`${
|
|
|
|
meta
|
|
|
|
? `---
|
|
|
|
${stringify(meta)}
|
|
|
|
---`
|
|
|
|
: `---
|
|
|
|
---`
|
|
|
|
}
|
|
|
|
# ${movie.name}
|
|
|
|
${movie.meta.image ? `` : ""}
|
|
|
|
${movie.tags.map((t) => `#${t}`).join(" ")}
|
|
|
|
${movie.description}
|
|
|
|
`);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function parseSeries(original: string, id: string): Series {
|
|
|
|
const doc = parseDocument(original);
|
|
|
|
|
|
|
|
let meta = {} as Series["meta"];
|
|
|
|
let name = "";
|
|
|
|
|
|
|
|
const range = [Infinity, -Infinity];
|
|
|
|
|
|
|
|
for (const child of doc.children) {
|
|
|
|
if (child.type === "yaml") {
|
|
|
|
try {
|
|
|
|
meta = (parse(child.value) || {}) as Series["meta"];
|
|
|
|
} catch (_) {
|
|
|
|
// ignore here
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meta["rating"] && typeof meta["rating"] === "string") {
|
|
|
|
meta.rating = [...meta.rating?.matchAll("⭐")].length;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
child.type === "heading" && child.depth === 1 && !name &&
|
|
|
|
child.children.length === 1 && child.children[0].type === "text"
|
|
|
|
) {
|
|
|
|
name = child.children[0].value;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
const start = child.position?.start.offset || Infinity;
|
|
|
|
const end = child.position?.end.offset || -Infinity;
|
|
|
|
if (start < range[0]) range[0] = start;
|
|
|
|
if (end > range[1]) range[1] = end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let description = original.slice(range[0], range[1]);
|
|
|
|
const tags = extractHashTags(description);
|
|
|
|
for (const tag of tags) {
|
|
|
|
description = description.replace("#" + tag, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
type: "series",
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
tags,
|
|
|
|
description,
|
|
|
|
meta,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const crud = createCrud<Series>({
|
|
|
|
prefix: "Media/series/",
|
|
|
|
parse: parseSeries,
|
2023-08-11 16:13:20 +02:00
|
|
|
hasThumbnails: true,
|
2023-08-07 14:44:04 +02:00
|
|
|
});
|
|
|
|
|
2023-08-11 16:13:20 +02:00
|
|
|
export const getSeries = (id: string) =>
|
|
|
|
crud.read(id).then(async (serie) => {
|
|
|
|
const imageUrl = serie.meta?.image;
|
|
|
|
if (!imageUrl) return serie;
|
|
|
|
const thumbhash = await getThumbhash({ url: imageUrl });
|
|
|
|
if (!thumbhash) return serie;
|
|
|
|
return {
|
|
|
|
...serie,
|
|
|
|
meta: {
|
|
|
|
...serie.meta,
|
|
|
|
thumbnail: btoa(String.fromCharCode(...thumbhash)),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
});
|
2023-08-07 14:44:04 +02:00
|
|
|
export const getAllSeries = crud.readAll;
|
|
|
|
export const createSeries = (series: Series) => {
|
|
|
|
const content = renderSeries(series);
|
|
|
|
return crud.create(series.id, content);
|
|
|
|
};
|