v0.2.7: 修复Redis连接 + 启动管理后台

- 修复Redis认证 (配置密码)
- 启动Python管理后台 (端口9531, 15个功能开关)
- 统一版本号 0.2.7
- 更新docker-compose.yml (镜像版本/Redis URL/Admin服务)
This commit is contained in:
2026-05-17 02:22:18 +08:00
commit 83cbfaf03f
164 changed files with 25195 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
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;