feat: use better names for md files

This commit is contained in:
Max Richter
2025-11-04 13:26:49 +01:00
parent 3103ed19fb
commit 56a104c8b9
6 changed files with 37 additions and 21 deletions

View File

@@ -12,21 +12,25 @@ export function formatDate(date?: string | Date): string {
return new Intl.DateTimeFormat("en-US", options).format(date); return new Intl.DateTimeFormat("en-US", options).format(date);
} }
export function safeFileName(inputString: string): string { export function safeFileName(input: string): string {
let fileName = inputString.toLowerCase(); return input
fileName = fileName.replace(/ /g, "_"); .normalize("NFKD")
fileName = fileName.replace(/[^\w.-]/g, ""); .replace(/[\u0300-\u036f]/g, "")
fileName = fileName.replaceAll(":", ""); .replace(/[\s-]+/g, "_")
return fileName; .replace(/[^A-Za-z0-9._]+/g, "")
.replace(/_+/g, "_")
// Trim underscores/dots from ends and prevent leading dots
.replace(/^[_\.]+|[_\.]+$/g, "").replace(/^\.+/, "")
.toLowerCase();
} }
export function toUrlSafeString(input: string): string { export function toUrlSafeString(input: string): string {
return input return input
.trim() // Remove leading and trailing whitespace .normalize("NFKD")
.toLowerCase() // Convert to lowercase .replace(/[\u0300-\u036f]/g, "")
.replace(/[^a-z0-9\s-]/g, "") // Remove non-alphanumeric characters except spaces and hyphens .replace(/[^A-Za-z0-9 _-]+/g, "")
.replace(/\s+/g, "-") // Replace spaces with hyphens .replace(/\s+/g, " ")
.replace(/-+/g, "-"); // Remove consecutive hyphens .trim();
} }
export function extractHashTags(inputString: string) { export function extractHashTags(inputString: string) {

View File

@@ -9,6 +9,7 @@ import {
formatDate, formatDate,
isYoutubeLink, isYoutubeLink,
safeFileName, safeFileName,
toUrlSafeString,
} from "@lib/string.ts"; } from "@lib/string.ts";
import { createLogger } from "@lib/log/index.ts"; import { createLogger } from "@lib/log/index.ts";
import { createResource } from "@lib/marka/index.ts"; import { createResource } from "@lib/marka/index.ts";
@@ -86,7 +87,7 @@ async function processCreateArticle(
streamResponse.enqueue("writing to disk"); streamResponse.enqueue("writing to disk");
await createResource(`articles/${title}.md`, newArticle); await createResource(`articles/${toUrlSafeString(title)}.md`, newArticle);
streamResponse.enqueue("id: " + title); streamResponse.enqueue("id: " + title);
} }

View File

@@ -2,7 +2,12 @@ import { Handlers } from "$fresh/server.ts";
import { json } from "@lib/helpers.ts"; import { json } from "@lib/helpers.ts";
import * as tmdb from "@lib/tmdb.ts"; import * as tmdb from "@lib/tmdb.ts";
import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts"; import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts";
import { formatDate, isString, safeFileName } from "@lib/string.ts"; import {
formatDate,
isString,
safeFileName,
toUrlSafeString,
} from "@lib/string.ts";
import { AccessDeniedError, BadRequestError } from "@lib/errors.ts"; import { AccessDeniedError, BadRequestError } from "@lib/errors.ts";
import { createResource, fetchResource } from "@lib/marka/index.ts"; import { createResource, fetchResource } from "@lib/marka/index.ts";
import { ReviewResource } from "@lib/marka/schema.ts"; import { ReviewResource } from "@lib/marka/schema.ts";
@@ -59,9 +64,9 @@ export const handler: Handlers = {
keywords, keywords,
}; };
const fileName = `${safeFileName(name)}.md`; const fileName = toUrlSafeString(name);
await createResource(`movies/${fileName}`, movie); await createResource(`movies/${fileName}.md`, movie);
return json({ name: fileName }); return json({ name: fileName });
}, },

View File

@@ -1,7 +1,12 @@
import { FreshContext, Handlers } from "$fresh/server.ts"; import { FreshContext, Handlers } from "$fresh/server.ts";
import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts"; import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts";
import * as tmdb from "@lib/tmdb.ts"; import * as tmdb from "@lib/tmdb.ts";
import { formatDate, isString, safeFileName } from "@lib/string.ts"; import {
formatDate,
isString,
safeFileName,
toUrlSafeString,
} from "@lib/string.ts";
import { json } from "@lib/helpers.ts"; import { json } from "@lib/helpers.ts";
import { import {
AccessDeniedError, AccessDeniedError,
@@ -78,7 +83,7 @@ const POST = async (
movie.content.image = finalPath; movie.content.image = finalPath;
} }
await createResource(`movies/${safeFileName(movie.name)}.md`, movie); await createResource(`movies/${toUrlSafeString(movie.name)}.md`, movie);
createRecommendationResource(movie, movieDetails.overview); createRecommendationResource(movie, movieDetails.overview);

View File

@@ -5,7 +5,7 @@ import * as openai from "@lib/openai.ts";
import { createLogger } from "@lib/log/index.ts"; import { createLogger } from "@lib/log/index.ts";
import recipeSchema from "@lib/recipeSchema.ts"; import recipeSchema from "@lib/recipeSchema.ts";
import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts"; import { fileExtension } from "https://deno.land/x/file_extension@v2.1.0/mod.ts";
import { safeFileName } from "@lib/string.ts"; import { safeFileName, toUrlSafeString } from "@lib/string.ts";
import { parseJsonLdToRecipeSchema } from "./parseJsonLd.ts"; import { parseJsonLdToRecipeSchema } from "./parseJsonLd.ts";
import z from "zod"; import z from "zod";
import { createResource } from "@lib/marka/index.ts"; import { createResource } from "@lib/marka/index.ts";
@@ -58,7 +58,7 @@ async function processCreateRecipeFromUrl(
recipe = res; recipe = res;
} }
const id = safeFileName(recipe?.name || ""); const id = toUrlSafeString(recipe?.name || "");
if (!recipe) { if (!recipe) {
streamResponse.enqueue("failed to parse recipe"); streamResponse.enqueue("failed to parse recipe");

View File

@@ -6,6 +6,7 @@ import { formatDate, isString, safeFileName } from "@lib/string.ts";
import { AccessDeniedError, BadRequestError } from "@lib/errors.ts"; import { AccessDeniedError, BadRequestError } from "@lib/errors.ts";
import { createResource, fetchResource } from "@lib/marka/index.ts"; import { createResource, fetchResource } from "@lib/marka/index.ts";
import { ReviewResource } from "@lib/marka/schema.ts"; import { ReviewResource } from "@lib/marka/schema.ts";
import { toUrlSafeString } from "@lib/string.ts";
function pickDirector( function pickDirector(
credits: Awaited<ReturnType<typeof tmdb.getSeriesCredits>>, credits: Awaited<ReturnType<typeof tmdb.getSeriesCredits>>,
@@ -71,9 +72,9 @@ export const handler: Handlers = {
keywords: keywords, keywords: keywords,
}; };
const fileName = `${safeFileName(name)}.md`; const fileName = toUrlSafeString(name);
await createResource(`series/${fileName}`, series); await createResource(`series/${fileName}.md`, series);
return json({ name: fileName }); return json({ name: fileName });
}, },