mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add support for storing images in S3 (#896)
This commit is contained in:
parent
1d1ea295c0
commit
099d893da9
@ -1,5 +1,5 @@
|
||||
import { stat } from "node:fs/promises";
|
||||
import type { BunFile } from "bun";
|
||||
import type { Stats } from "node:fs";
|
||||
import type { BunFile, S3File, S3Stats } from "bun";
|
||||
import { type SQL, and, eq, sql } from "drizzle-orm";
|
||||
import Elysia, { type Context, t } from "elysia";
|
||||
import { prefix } from "~/base";
|
||||
@ -15,6 +15,7 @@ import { sqlarr } from "~/db/utils";
|
||||
import { KError } from "~/models/error";
|
||||
import { bubble } from "~/models/examples";
|
||||
import { AcceptLanguage, isUuid, processLanguages } from "~/models/utils";
|
||||
import { getFile } from "~/utils";
|
||||
import { imageDir } from "./seed/images";
|
||||
|
||||
function getRedirectToImageHandler({
|
||||
@ -98,7 +99,7 @@ export const imagesH = new Elysia({ tags: ["images"] })
|
||||
"/images/:id",
|
||||
async ({ params: { id }, query: { quality }, headers: reqHeaders }) => {
|
||||
const path = `${imageDir}/${id}.${quality}.jpg`;
|
||||
const file = Bun.file(path);
|
||||
const file = getFile(path);
|
||||
|
||||
const etag = await generateETag(file);
|
||||
if (await isCached(reqHeaders, etag, path))
|
||||
@ -366,8 +367,13 @@ export async function isCached(
|
||||
if (headers["if-modified-since"]) {
|
||||
const ifModifiedSince = headers["if-modified-since"];
|
||||
let lastModified: Date | undefined;
|
||||
const stat = await getFile(filePath).stat();
|
||||
try {
|
||||
lastModified = (await stat(filePath)).mtime;
|
||||
if ((stat as S3Stats).lastModified) {
|
||||
lastModified = (stat as S3Stats).lastModified;
|
||||
} else if ((stat as Stats).mtime) {
|
||||
lastModified = (stat as Stats).mtime;
|
||||
}
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
@ -382,7 +388,7 @@ export async function isCached(
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function generateETag(file: BunFile) {
|
||||
export async function generateETag(file: BunFile | S3File) {
|
||||
const hash = new Bun.CryptoHasher("md5");
|
||||
hash.update(await file.arrayBuffer());
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { encode } from "blurhash";
|
||||
import { type SQL, and, eq, is, lt, sql } from "drizzle-orm";
|
||||
@ -9,10 +8,9 @@ import sharp from "sharp";
|
||||
import { type Transaction, db } from "~/db";
|
||||
import { mqueue } from "~/db/schema/mqueue";
|
||||
import type { Image } from "~/models/utils";
|
||||
import { getFile } from "~/utils";
|
||||
|
||||
export const imageDir = process.env.IMAGES_PATH ?? "./images";
|
||||
await mkdir(imageDir, { recursive: true });
|
||||
|
||||
export const defaultBlurhash = "000000";
|
||||
|
||||
type ImageTask = {
|
||||
@ -164,7 +162,9 @@ async function downloadImage(id: string, url: string): Promise<string> {
|
||||
await Promise.all(
|
||||
Object.entries(resolutions).map(async ([resolution, dimensions]) => {
|
||||
const buffer = await image.clone().resize(dimensions.width).toBuffer();
|
||||
await writeFile(path.join(imageDir, `${id}.${resolution}.jpg`), buffer);
|
||||
const file = getFile(path.join(imageDir, `${id}.${resolution}.jpg`));
|
||||
|
||||
await Bun.write(file, buffer, { mode: 0o660 });
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import type { BunFile, S3File } from "bun";
|
||||
|
||||
// remove indent in multi-line comments
|
||||
export const comment = (str: TemplateStringsArray, ...values: any[]) =>
|
||||
str
|
||||
@ -14,3 +16,15 @@ export function getYear(date: string) {
|
||||
export type Prettify<T> = {
|
||||
[K in keyof T]: Prettify<T[K]>;
|
||||
} & {};
|
||||
|
||||
// Returns either a filesystem-backed file, or a S3-backed file,
|
||||
// depending on whether or not S3 environment variables are set.
|
||||
export function getFile(path: string): BunFile | S3File {
|
||||
if ("S3_BUCKET" in process.env || "AWS_BUCKET" in process.env) {
|
||||
// This will use a S3 client configured via environment variables.
|
||||
// See https://bun.sh/docs/api/s3#credentials for more details.
|
||||
return Bun.s3.file(path);
|
||||
}
|
||||
|
||||
return Bun.file(path);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user