2025-12-17 20:15:18 +08:00

113 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 视频归档定时任务触发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 }
);
}
}