#!/usr/bin/env node
/**
* Clean Old Media Script
*
* ลบ posts (และ media ที่เกี่ยวข้อง) ที่โพสต์ไปแล้วเกิน 7 วัน
*/
import { PostizClient } from './postizClient.js';
import { config } from './config.js';
const DAYS_TO_KEEP = 7;
interface CleanupOptions {
daysOld?: number;
dryRun?: boolean;
limit?: number;
}
async function cleanOldMedia(options: CleanupOptions = {}) {
const { daysOld = DAYS_TO_KEEP, dryRun = true, limit } = options;
console.log('╔════════════════════════════════════════════════════════╗');
console.log('║ Postiz Media Cleanup - ลบ Media เก่า ║');
console.log('╚════════════════════════════════════════════════════════╝\n');
console.log(`⚙️ Configuration:`);
console.log(` - ลบโพสต์เก่ากว่า: ${daysOld} วัน`);
console.log(` - Dry Run: ${dryRun ? 'ใช่ (ไม่ลบจริง)' : 'ไม่ (ลบจริง!)'}`);
console.log(` - Limit: ${limit || 'ไม่จำกัด'}`);
console.log(` - API URL: ${config.postizBaseUrl}\n`);
const client = new PostizClient();
try {
// คำนวณวันที่ cutoff (7 วันที่แล้ว)
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - daysOld);
cutoffDate.setHours(0, 0, 0, 0); // เริ่มต้นวัน
console.log(`📅 Cutoff Date: ${cutoffDate.toISOString().split('T')[0]}`);
console.log(` (ลบโพสต์ที่โพสต์ก่อนวันที่นี้)\n`);
// ดึง posts ทั้งหมด
console.log('🔍 กำลังดึงรายการโพสต์...');
console.log(' (Postiz API มี rate limit 30 requests/hour)\n');
const allPosts = await client.listPosts({});
console.log(` พบโพสต์ทั้งหมด: ${allPosts.length}\n`);
// กรองเฉพาะ posts ที่:
// 1. สถานะเป็น PUBLISHED (โพสต์ไปแล้ว)
// 2. publishDate เก่ากว่า cutoff date
const oldPublishedPosts = allPosts.filter((post) => {
// ต้องเป็น PUBLISHED
if (post.state !== 'PUBLISHED') {
return false;
}
// ต้องมี publishDate
if (!post.publishDate) {
return false;
}
// เช็คว่าเก่ากว่า cutoff date หรือไม่
const publishDate = new Date(post.publishDate);
return publishDate < cutoffDate;
});
console.log(`✅ พบโพสต์ที่ตรงเงื่อนไข: ${oldPublishedPosts.length}`);
if (oldPublishedPosts.length === 0) {
console.log('\n✨ ไม่มีโพสต์ที่ต้องลบ!\n');
return {
totalCandidates: 0,
deleted: 0,
failed: 0,
skipped: 0,
};
}
// แสดงตัวอย่างโพสต์ที่จะลบ
console.log('\n📋 ตัวอย่างโพสต์ที่จะลบ (5 รายการแรก):');
oldPublishedPosts.slice(0, 5).forEach((post, index) => {
const publishDate = new Date(post.publishDate!).toLocaleString('th-TH');
const content = post.content?.substring(0, 50) || 'ไม่มีเนื้อหา';
console.log(` ${index + 1}. [${post.id}] ${publishDate}`);
console.log(` "${content}${content.length >= 50 ? '...' : ''}"`);
console.log(` Channel: ${post.integration?.name || 'N/A'}\n`);
});
// Apply limit ถ้ามี
let postsToDelete = oldPublishedPosts;
if (limit && limit > 0) {
postsToDelete = oldPublishedPosts.slice(0, limit);
console.log(`⚠️ จำกัดการลบไว้ที่: ${limit} โพสต์\n`);
}
if (dryRun) {
console.log('🔔 DRY RUN MODE - ไม่ได้ลบจริง!');
console.log(` จะลบ ${postsToDelete.length} โพสต์ถ้ารันจริง\n`);
return {
totalCandidates: postsToDelete.length,
deleted: 0,
failed: 0,
skipped: postsToDelete.length,
};
}
// ลบจริง
console.log(`🗑️ กำลังลบ ${postsToDelete.length} โพสต์...\n`);
let deleted = 0;
let failed = 0;
const failedPosts: Array<{ id: string; reason: string }> = [];
for (let i = 0; i < postsToDelete.length; i++) {
const post = postsToDelete[i];
try {
await client.deletePost(post.id);
deleted++;
const publishDate = new Date(post.publishDate!).toLocaleDateString('th-TH');
console.log(` ✅ ลบสำเร็จ [${deleted}/${postsToDelete.length}] ${publishDate}`);
// เพิ่ม delay เพื่อไม่ให้เกิน rate limit (2 วินาที/request)
if (i < postsToDelete.length - 1) {
await new Promise(resolve => setTimeout(resolve, 2000));
}
} catch (error) {
failed++;
const reason = (error as Error).message;
failedPosts.push({ id: post.id, reason });
console.log(` ❌ ลบล้มเหลว [${post.id}] - ${reason}`);
// ถ้าเป็น rate limit error ให้หยุด
if (reason.includes('429') || reason.includes('Too Many Requests')) {
console.log('\n⚠️ เกิน rate limit! กรุณารอ 1 ชั่วโมงแล้วลองใหม่\n');
break;
}
}
}
console.log('\n╔════════════════════════════════════════════════════════╗');
console.log('║ สรุปผลการลบ ║');
console.log('╚════════════════════════════════════════════════════════╝');
console.log(` โพสต์ที่ตรงเงื่อนไข: ${oldPublishedPosts.length}`);
console.log(` ลบสำเร็จ: ${deleted}`);
console.log(` ลบล้มเหลว: ${failed}`);
if (failedPosts.length > 0) {
console.log('\n❌ รายการที่ลบล้มเหลว:');
failedPosts.forEach(({ id, reason }) => {
console.log(` - ${id}: ${reason}`);
});
}
console.log('');
return {
totalCandidates: postsToDelete.length,
deleted,
failed,
skipped: 0,
};
} catch (error) {
console.error('\n❌ เกิดข้อผิดพลาด:', (error as Error).message);
throw error;
}
}
// Run script
const args = process.argv.slice(2);
const dryRun = !args.includes('--delete'); // default เป็น dry-run
const daysOld = parseInt(args.find(arg => arg.startsWith('--days='))?.split('=')[1] || '7');
const limit = parseInt(args.find(arg => arg.startsWith('--limit='))?.split('=')[1] || '0');
console.log('\n⚡ Starting cleanup script...\n');
if (dryRun) {
console.log('⚠️ DRY RUN MODE: จะแสดงผลว่าจะลบอะไร โดยไม่ลบจริง');
console.log(' ถ้าต้องการลบจริง ให้เพิ่ม flag: --delete\n');
}
cleanOldMedia({ daysOld, dryRun, limit })
.then((result) => {
console.log('✅ เสร็จสิ้น!\n');
process.exit(0);
})
.catch((error) => {
console.error('❌ Script ล้มเหลว\n');
process.exit(1);
});