This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import type { ImageMetadata } from "astro";
|
import type { ImageMetadata } from "astro";
|
||||||
import { Picture as AstroImage } from "astro:assets";
|
import { Picture as AstroImage } from "astro:assets";
|
||||||
import { inferRemoteSize } from "astro/assets/utils";
|
import { inferRemoteSize } from "astro/assets/utils";
|
||||||
import { generateThumbHash, getImageBuffer, getExifData } from "@helpers/image";
|
import { getProcessedImage } from "@helpers/image";
|
||||||
interface Props {
|
interface Props {
|
||||||
src: ImageMetadata & { fsPath?: string; src?: string };
|
src: ImageMetadata & { fsPath?: string; src?: string };
|
||||||
alt: string;
|
alt: string;
|
||||||
@@ -45,12 +45,11 @@ const {
|
|||||||
thumbnail = false,
|
thumbnail = false,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const imageOk = await checkImage(image);
|
const imageOk = await checkImage(image);
|
||||||
const imageBuffer = imageOk && (await getImageBuffer(image));
|
|
||||||
let thumbhash = imageBuffer && (await generateThumbHash(imageBuffer));
|
const { thumbhash, exif } = imageOk
|
||||||
let exif = imageBuffer && (await getExifData(imageBuffer));
|
? await getProcessedImage(image)
|
||||||
|
: { thumbhash: undefined, exif: undefined };
|
||||||
|
|
||||||
const definedSizes = [
|
const definedSizes = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const instructions = resource?.content?.recipeInstructions || [];
|
|||||||
<h2 class="text-2xl">Ingredients</h2>
|
<h2 class="text-2xl">Ingredients</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
ingredients.map((ingredient) => (
|
ingredients.map((ingredient: string) => (
|
||||||
<li set:html={markdownToHtml(ingredient)}/>
|
<li set:html={markdownToHtml(ingredient)}/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ const instructions = resource?.content?.recipeInstructions || [];
|
|||||||
<h2 class="text-2xl">Steps</h2>
|
<h2 class="text-2xl">Steps</h2>
|
||||||
<ol>
|
<ol>
|
||||||
{
|
{
|
||||||
instructions.map((ingredient) => (
|
instructions.map((ingredient: string) => (
|
||||||
<li set:html={markdownToHtml(ingredient)}/>
|
<li set:html={markdownToHtml(ingredient)}/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import ExifReader from "exifreader";
|
|||||||
import type { ImageMetadata } from "astro";
|
import type { ImageMetadata } from "astro";
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
|
import { createHash } from "node:crypto";
|
||||||
|
import { promises as fs } from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
export async function generateThumbHash(
|
export async function generateThumbHash(
|
||||||
buffer: ArrayBuffer,
|
buffer: ArrayBuffer,
|
||||||
@@ -81,3 +84,36 @@ export async function getExifData(buffer: ArrayBuffer) {
|
|||||||
|
|
||||||
return hasExif ? out : undefined;
|
return hasExif ? out : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CACHE_DIR = path.join(process.cwd(), 'node_modules', '.astro', 'image-cache');
|
||||||
|
|
||||||
|
export async function getProcessedImage(image: ImageMetadata) {
|
||||||
|
const buffer = await getImageBuffer(image);
|
||||||
|
if (!buffer) {
|
||||||
|
return { thumbhash: undefined, exif: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = createHash('sha256').update(new Uint8Array(buffer)).digest('hex');
|
||||||
|
const cacheFile = path.join(CACHE_DIR, `${hash}.json`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cachedData = await fs.readFile(cacheFile, 'utf-8');
|
||||||
|
return JSON.parse(cachedData);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'ENOENT') {
|
||||||
|
console.error("Failed to read from image cache:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const thumbhash = await generateThumbHash(buffer);
|
||||||
|
const exif = await getExifData(buffer);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.mkdir(CACHE_DIR, { recursive: true });
|
||||||
|
await fs.writeFile(cacheFile, JSON.stringify({ thumbhash, exif }), 'utf-8');
|
||||||
|
} catch (writeError) {
|
||||||
|
console.error("Failed to write to image cache:", writeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { thumbhash, exif };
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export async function listResource(
|
|||||||
if (json.type == "dir") {
|
if (json.type == "dir") {
|
||||||
return {
|
return {
|
||||||
...json,
|
...json,
|
||||||
content: json.content.filter((res) =>
|
content: json.content.filter((res: MemoriumEntry) =>
|
||||||
res.mime === "application/markdown"
|
res.mime === "application/markdown"
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export async function getStaticPaths() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidResource(res) {
|
function isValidResource(res: any) {
|
||||||
return !!res?.content?._type;
|
return !!res?.content?._type;
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
@@ -39,7 +39,7 @@ function isValidResource(res) {
|
|||||||
<p>{t(`${resourceType as "articles"}.description`)}</p>
|
<p>{t(`${resourceType as "articles"}.description`)}</p>
|
||||||
{
|
{
|
||||||
resources.content
|
resources.content
|
||||||
.filter((res) => isValidResource(res))
|
.filter((res: any) => isValidResource(res))
|
||||||
.map((resource: any) => (
|
.map((resource: any) => (
|
||||||
<HeroCard
|
<HeroCard
|
||||||
post={{
|
post={{
|
||||||
|
|||||||
Reference in New Issue
Block a user