Files
Socialflow/server/services/media-purge.ts
T
MichaelandClaude Sonnet 4.6 7733acbc22 feat: Replace external storage with local file storage + auto cleanup
Media is now stored directly on the server disk (no external service).
Files are served via Express static middleware at /uploads/*.

Cleanup rules:
- Videos deleted immediately after successful publish to Facebook/Instagram
- Videos older than 7 days purged daily by cron job
- Images older than 30 days purged daily by cron job

Changes:
- server/services/minio.ts: replaced S3 client with local fs read/write
- server/index.ts: added static serving for /uploads/media, /logos, /stories
- server/services/media-purge.ts: new rules (images 30d, videos 7d)
- server/services/scheduler.ts: delete local videos after successful publish
- docker-compose.yml: add media_uploads, logos_uploads, stories_uploads volumes
- settings UI: removed credentials card, shows local storage info
- package.json: removed googleapis (unneeded)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 07:35:27 +01:00

59 lines
1.9 KiB
TypeScript

import { db } from '../db';
import { media } from '@shared/schema';
import { eq, lt, and } from 'drizzle-orm';
import { minioService as storageService } from './minio';
/**
* Purge old local media to save disk space:
* - Images older than 30 days
* - Videos older than 7 days
*/
export async function purgeOldMedia() {
console.log('[Media Purge] Starting automatic purge of old media...');
try {
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
const oldImages = await db.query.media.findMany({
where: (m, { and, lt, eq }) => and(eq(m.type, 'image'), lt(m.createdAt, thirtyDaysAgo))
});
const oldVideos = await db.query.media.findMany({
where: (m, { and, lt, eq }) => and(eq(m.type, 'video'), lt(m.createdAt, sevenDaysAgo))
});
const toDelete = [...oldImages, ...oldVideos];
if (toDelete.length === 0) {
console.log('[Media Purge] No old media found to purge.');
return;
}
console.log(`[Media Purge] Found ${oldImages.length} old images (>30 days) and ${oldVideos.length} old videos (>7 days) to purge.`);
let successCount = 0;
let errorCount = 0;
for (const item of toDelete) {
try {
if (item.cloudinaryPublicId) {
await storageService.deleteMedia(item.cloudinaryPublicId, item.userId, item.type === 'video' ? 'video' : 'image');
}
await db.delete(media).where(eq(media.id, item.id));
successCount++;
} catch (err) {
console.error(`[Media Purge] Failed to delete media ${item.id}:`, err);
errorCount++;
}
}
console.log(`[Media Purge] Purge completed. Deleted: ${successCount}, Failed: ${errorCount}.`);
} catch (error) {
console.error('[Media Purge] Fatal error during media purge process:', error);
}
}