- 修复Redis认证 (配置密码) - 启动Python管理后台 (端口9531, 15个功能开关) - 统一版本号 0.2.7 - 更新docker-compose.yml (镜像版本/Redis URL/Admin服务)
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
import { Router, Request, Response } from 'express';
|
|
import { runFullCleanup, emptyAllTrash } from '../cloud/cleanup.service';
|
|
|
|
const router = Router();
|
|
|
|
// ============ Cleanup & Storage Management ============
|
|
|
|
/**
|
|
* POST /api/admin/cleanup/run
|
|
* Manually trigger a cleanup cycle:
|
|
* - Trash old date folders from cloud drives
|
|
* - Delete old save_records
|
|
* - Empty recycle bin
|
|
*/
|
|
router.post('/admin/cleanup/run', async (_req: Request, res: Response) => {
|
|
try {
|
|
const stats = await runFullCleanup();
|
|
res.json({
|
|
success: stats.errors.length === 0,
|
|
files_trashed: stats.filesTrashed,
|
|
logs_deleted: stats.logsDeleted,
|
|
trash_emptied: stats.trashEmptied,
|
|
errors: stats.errors,
|
|
message: stats.errors.length === 0
|
|
? `✅ 清理完成:移入回收站 ${stats.filesTrashed} 个文件夹,删除 ${stats.logsDeleted} 条日志,清空回收站${stats.trashEmptied ? '✓' : '-'}`
|
|
: `清理完成,但有 ${stats.errors.length} 个错误`,
|
|
});
|
|
} catch (err: any) {
|
|
res.status(500).json({ success: false, error: err.message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/admin/cleanup/empty-trash
|
|
* Empty recycle bin for all cloud drives (permanently delete, frees space).
|
|
*/
|
|
router.post('/admin/cleanup/empty-trash', async (_req: Request, res: Response) => {
|
|
try {
|
|
const result = await emptyAllTrash();
|
|
res.json({
|
|
success: result.errors.length === 0,
|
|
emptied: result.emptied,
|
|
errors: result.errors,
|
|
message: result.emptied
|
|
? '✅ 回收站已清空,存储空间已释放'
|
|
: (result.errors.length > 0 ? `清空回收站部分失败:${result.errors.join('; ')}` : '没有可清空的网盘'),
|
|
});
|
|
} catch (err: any) {
|
|
res.status(500).json({ success: false, error: err.message });
|
|
}
|
|
});
|
|
|
|
|
|
/**
|
|
* Extract genre tags from search result titles.
|
|
*/
|
|
function extractTagsFromResults(results: any[], keyword: string): string[] {
|
|
const tags: string[] = [];
|
|
if (keyword) tags.push(keyword);
|
|
|
|
const genreKeywords: Record<string, string> = {
|
|
'动画': '动画', '动漫': '动画', '国漫': '国漫',
|
|
'剧场版': '剧场版', '年番': '年番',
|
|
'动作': '动作', '奇幻': '奇幻', '玄幻': '玄幻',
|
|
'仙侠': '仙侠', '古装': '古装', '爱情': '爱情',
|
|
'科幻': '科幻', '喜剧': '喜剧', '悬疑': '悬疑',
|
|
'恐怖': '恐怖', '惊悚': '惊悚', '剧情': '剧情',
|
|
'冒险': '冒险', '战争': '战争', '武侠': '武侠',
|
|
'纪录': '纪录片', '真人': '真人秀', '短片': '短片',
|
|
};
|
|
|
|
const seen = new Set<string>();
|
|
for (const r of results) {
|
|
const title = (r.title || r.note || '') as string;
|
|
for (const [key, val] of Object.entries(genreKeywords)) {
|
|
if (title.includes(key) && !seen.has(val)) {
|
|
seen.add(val);
|
|
tags.push(val);
|
|
}
|
|
}
|
|
}
|
|
|
|
return tags;
|
|
}
|
|
|
|
|
|
export default router; |