113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
/**
|
||
* 视频归档定时任务触发API
|
||
* 用于 Cron Job 定时调用,执行视频归档任务
|
||
*
|
||
* 使用方法:
|
||
* 1. 配置环境变量 CRON_SECRET
|
||
* 2. 在 Vercel Cron 或外部 Cron 服务中配置定时触发
|
||
* 3. 每小时执行一次:0 * * * *
|
||
*/
|
||
|
||
import { NextResponse } from "next/server";
|
||
import { runVideoArchiveJob } from "@/lib/jobs/video-archive-job";
|
||
import { getVideosToArchive } from "@/lib/jobs/video-archive-job";
|
||
|
||
/**
|
||
* 验证请求授权(防止未授权调用)
|
||
*/
|
||
function verifyAuthToken(request: Request): boolean {
|
||
const authHeader = request.headers.get("authorization");
|
||
const token = authHeader?.replace("Bearer ", "");
|
||
|
||
// 与环境变量中的密钥比对
|
||
const cronSecret = process.env.CRON_SECRET;
|
||
|
||
// 如果未配置 CRON_SECRET,则允许所有请求(开发环境)
|
||
if (!cronSecret) {
|
||
console.warn("[VideoArchiveAPI] ⚠️ CRON_SECRET 未配置,允许所有请求");
|
||
return true;
|
||
}
|
||
|
||
return token === cronSecret;
|
||
}
|
||
|
||
/**
|
||
* POST /api/jobs/archive-videos
|
||
* 执行视频归档任务
|
||
*/
|
||
export async function POST(request: Request) {
|
||
try {
|
||
// 1. 验证授权
|
||
if (!verifyAuthToken(request)) {
|
||
return NextResponse.json(
|
||
{ error: "Unauthorized" },
|
||
{ status: 401 }
|
||
);
|
||
}
|
||
|
||
// 2. 执行归档任务
|
||
const result = await runVideoArchiveJob();
|
||
|
||
// 3. 返回成功响应
|
||
return NextResponse.json({
|
||
success: result.success,
|
||
message: result.message,
|
||
stats: {
|
||
total: result.total,
|
||
succeeded: result.succeeded,
|
||
failed: result.failed,
|
||
},
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
} catch (error: any) {
|
||
console.error("[VideoArchiveAPI] ❌ Job execution failed:", error);
|
||
|
||
return NextResponse.json(
|
||
{
|
||
success: false,
|
||
error: error.message,
|
||
timestamp: new Date().toISOString(),
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* GET /api/jobs/archive-videos
|
||
* 查询待归档视频统计
|
||
*/
|
||
export async function GET(request: Request) {
|
||
try {
|
||
// 验证授权
|
||
if (!verifyAuthToken(request)) {
|
||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||
}
|
||
|
||
// 查询待归档视频
|
||
const videos = await getVideosToArchive();
|
||
|
||
return NextResponse.json({
|
||
pendingCount: videos.length,
|
||
videos: videos.map((v) => ({
|
||
id: v.id,
|
||
createdAt: v.createdAt,
|
||
temporaryVideoUrl: v.temporaryVideoUrl,
|
||
})),
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
} catch (error: any) {
|
||
console.error("[VideoArchiveAPI] ❌ Query failed:", error);
|
||
|
||
return NextResponse.json(
|
||
{
|
||
success: false,
|
||
error: error.message,
|
||
timestamp: new Date().toISOString(),
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|
||
|