mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 10:37:13 -04:00 
			
		
		
		
	Handle image in jsonb
This commit is contained in:
		
							parent
							
								
									6e642db7db
								
							
						
					
					
						commit
						71b57c50e7
					
				| @ -1,13 +1,12 @@ | |||||||
| import { mkdir, writeFile } from "node:fs/promises"; | import { mkdir, writeFile } from "node:fs/promises"; | ||||||
| import path from "node:path"; | import path from "node:path"; | ||||||
| import { encode } from "blurhash"; | import { encode } from "blurhash"; | ||||||
| import { eq, sql } from "drizzle-orm"; | import { type SQLWrapper, eq, sql } from "drizzle-orm"; | ||||||
| import type { PgColumn } from "drizzle-orm/pg-core"; | import type { PgColumn, PgTable } from "drizzle-orm/pg-core"; | ||||||
| import { version } from "package.json"; | import { version } from "package.json"; | ||||||
| import type { PoolClient } from "pg"; | import type { PoolClient } from "pg"; | ||||||
| import sharp from "sharp"; | import sharp from "sharp"; | ||||||
| import { type Transaction, db } from "~/db"; | import { type Transaction, db } from "~/db"; | ||||||
| import * as schema from "~/db/schema"; |  | ||||||
| import { mqueue } from "~/db/schema/queue"; | import { mqueue } from "~/db/schema/queue"; | ||||||
| import type { Image } from "~/models/utils"; | import type { Image } from "~/models/utils"; | ||||||
| 
 | 
 | ||||||
| @ -21,30 +20,38 @@ type ImageTask = { | |||||||
| 	column: string; | 	column: string; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| type ImageTaskC = { |  | ||||||
| 	url: string; |  | ||||||
| 	column: PgColumn; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // this will only push a task to the image downloader service and not download it instantly.
 | // this will only push a task to the image downloader service and not download it instantly.
 | ||||||
| // this is both done to prevent to many requests to be sent at once and to make sure POST
 | // this is both done to prevent to many requests to be sent at once and to make sure POST
 | ||||||
| // requests are not blocked by image downloading or blurhash calculation
 | // requests are not blocked by image downloading or blurhash calculation
 | ||||||
| export const enqueueImage = async ( | export const enqueueOptImage = async ( | ||||||
| 	tx: Transaction, | 	tx: Transaction, | ||||||
| 	img: ImageTaskC, | 	img: | ||||||
| ): Promise<Image> => { | 		| { url: string | null; column: PgColumn } | ||||||
|  | 		| { url: string | null; table: PgTable; column: SQLWrapper }, | ||||||
|  | ): Promise<Image | null> => { | ||||||
|  | 	if (!img.url) return null; | ||||||
|  | 
 | ||||||
| 	const hasher = new Bun.CryptoHasher("sha256"); | 	const hasher = new Bun.CryptoHasher("sha256"); | ||||||
| 	hasher.update(img.url); | 	hasher.update(img.url); | ||||||
| 	const id = hasher.digest().toString("hex"); | 	const id = hasher.digest().toString("hex"); | ||||||
| 
 | 
 | ||||||
| 	await tx.insert(mqueue).values({ | 	const message: ImageTask = | ||||||
| 		kind: "image", | 		"table" in img | ||||||
| 		message: { | 			? { | ||||||
|  | 					id, | ||||||
|  | 					url: img.url, | ||||||
|  | 					table: img.table._.name, | ||||||
|  | 					column: img.column.getSQL().sql, | ||||||
|  | 				} | ||||||
|  | 			: { | ||||||
| 					id, | 					id, | ||||||
| 					url: img.url, | 					url: img.url, | ||||||
| 					table: img.column.table._.name, | 					table: img.column.table._.name, | ||||||
| 			column: img.column.name, | 					column: img.column, | ||||||
| 		} satisfies ImageTask, | 				}; | ||||||
|  | 	await tx.insert(mqueue).values({ | ||||||
|  | 		kind: "image", | ||||||
|  | 		message, | ||||||
| 	}); | 	}); | ||||||
| 	await tx.execute(sql`notify image`); | 	await tx.execute(sql`notify image`); | ||||||
| 
 | 
 | ||||||
| @ -55,14 +62,6 @@ export const enqueueImage = async ( | |||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const enqueueOptImage = async ( |  | ||||||
| 	tx: Transaction, |  | ||||||
| 	img: { url: string | null; column: PgColumn }, |  | ||||||
| ): Promise<Image | null> => { |  | ||||||
| 	if (!img.url) return null; |  | ||||||
| 	return await enqueueImage(tx, { url: img.url, column: img.column }); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export const processImages = async () => { | export const processImages = async () => { | ||||||
| 	async function processOne() { | 	async function processOne() { | ||||||
| 		return await db.transaction(async (tx) => { | 		return await db.transaction(async (tx) => { | ||||||
| @ -78,19 +77,14 @@ export const processImages = async () => { | |||||||
| 
 | 
 | ||||||
| 			const img = item.message as ImageTask; | 			const img = item.message as ImageTask; | ||||||
| 			const blurhash = await downloadImage(img.id, img.url); | 			const blurhash = await downloadImage(img.id, img.url); | ||||||
|  | 			const ret: Image = { id: img.id, source: img.url, blurhash }; | ||||||
| 
 | 
 | ||||||
| 			const table = schema[img.table as keyof typeof schema] as any; | 			const table = sql.raw(img.table); | ||||||
|  | 			const column = sql.raw(img.column); | ||||||
| 
 | 
 | ||||||
| 			await tx | 			await tx.execute(sql` | ||||||
| 				.update(table) | 				update ${table} set ${column} = ${ret} where ${column}->'id' = '${item.id}' | ||||||
| 				.set({ | 			`);
 | ||||||
| 					[img.column]: { |  | ||||||
| 						id: img.id, |  | ||||||
| 						source: img.url, |  | ||||||
| 						blurhash, |  | ||||||
| 					} satisfies Image, |  | ||||||
| 				}) |  | ||||||
| 				.where(eq(sql`${table[img.column]}->'id'`, img.id)); |  | ||||||
| 
 | 
 | ||||||
| 			await tx.delete(mqueue).where(eq(mqueue.id, item.id)); | 			await tx.delete(mqueue).where(eq(mqueue.id, item.id)); | ||||||
| 			return true; | 			return true; | ||||||
|  | |||||||
| @ -30,19 +30,23 @@ export const insertShow = async ( | |||||||
| 			...original, | 			...original, | ||||||
| 			poster: await enqueueOptImage(tx, { | 			poster: await enqueueOptImage(tx, { | ||||||
| 				url: original.poster, | 				url: original.poster, | ||||||
| 				column: shows.original.poster, | 				table: shows, | ||||||
|  | 				column: sql`${shows.original}['poster']`, | ||||||
| 			}), | 			}), | ||||||
| 			thumbnail: await enqueueOptImage(tx, { | 			thumbnail: await enqueueOptImage(tx, { | ||||||
| 				url: original.thumbnail, | 				url: original.thumbnail, | ||||||
| 				column: shows.original.thumbnail, | 				table: shows, | ||||||
|  | 				column: sql`${shows.original}['thumbnail']`, | ||||||
| 			}), | 			}), | ||||||
| 			banner: await enqueueOptImage(tx, { | 			banner: await enqueueOptImage(tx, { | ||||||
| 				url: original.banner, | 				url: original.banner, | ||||||
| 				column: shows.original.banner, | 				table: shows, | ||||||
|  | 				column: sql`${shows.original}['banner']`, | ||||||
| 			}), | 			}), | ||||||
| 			logo: await enqueueOptImage(tx, { | 			logo: await enqueueOptImage(tx, { | ||||||
| 				url: original.logo, | 				url: original.logo, | ||||||
| 				column: shows.original.logo, | 				table: shows, | ||||||
|  | 				column: sql`${shows.original}['logo']`, | ||||||
| 			}), | 			}), | ||||||
| 		}; | 		}; | ||||||
| 		const ret = await insertBaseShow(tx, { ...show, original: orig }); | 		const ret = await insertBaseShow(tx, { ...show, original: orig }); | ||||||
|  | |||||||
| @ -40,7 +40,8 @@ export const insertStaff = async ( | |||||||
| 					...x.character, | 					...x.character, | ||||||
| 					image: await enqueueOptImage(tx, { | 					image: await enqueueOptImage(tx, { | ||||||
| 						url: x.character.image, | 						url: x.character.image, | ||||||
| 						column: roles.character.image, | 						table: roles, | ||||||
|  | 						column: `${roles.character}['image']`, | ||||||
| 					}), | 					}), | ||||||
| 				}, | 				}, | ||||||
| 			})), | 			})), | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user