media-cleanup.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { eq } from 'drizzle-orm';
  2. import { db } from '../../src/db';
  3. import { media } from '../../src/db/schema/media';
  4. import { resources } from '../../src/db/schema/resource';
  5. import { mediaBucketName } from '../../src/lib/config';
  6. import minioClient from '../../src/lib/minio';
  7. type MediaMetadata = {
  8. hlsPath?: string;
  9. };
  10. async function removeObjectIfExists(objectName: string) {
  11. try {
  12. await minioClient.removeObject(mediaBucketName, objectName);
  13. } catch (error: any) {
  14. if (error?.code !== 'NoSuchKey' && error?.code !== 'NotFound') {
  15. throw error;
  16. }
  17. }
  18. }
  19. async function removePrefix(prefix: string) {
  20. const objectNames: string[] = [];
  21. const stream = minioClient.listObjectsV2(mediaBucketName, prefix, true);
  22. await new Promise<void>((resolve, reject) => {
  23. stream.on('data', (object) => {
  24. if (object.name) objectNames.push(object.name);
  25. });
  26. stream.on('error', reject);
  27. stream.on('end', resolve);
  28. });
  29. if (objectNames.length > 0) {
  30. await minioClient.removeObjects(mediaBucketName, objectNames);
  31. }
  32. }
  33. export async function cleanupMediaRecord(mediaId: string) {
  34. const [mediaRecord] = await db.select().from(media).where(eq(media.id, mediaId)).limit(1);
  35. if (!mediaRecord) {
  36. return;
  37. }
  38. const metadata = mediaRecord.metadata as MediaMetadata | null;
  39. const hlsPath = metadata?.hlsPath;
  40. const hlsPrefix = hlsPath?.includes('/') ? hlsPath.slice(0, hlsPath.lastIndexOf('/') + 1) : null;
  41. await removeObjectIfExists(mediaRecord.storageKey);
  42. if (hlsPrefix) {
  43. await removePrefix(hlsPrefix);
  44. }
  45. await db.transaction(async (tx) => {
  46. await tx.delete(media).where(eq(media.id, mediaId));
  47. if (mediaRecord.resourceId) {
  48. await tx.delete(resources).where(eq(resources.id, mediaRecord.resourceId));
  49. }
  50. });
  51. }