168 lines
6.5 KiB
TypeScript
168 lines
6.5 KiB
TypeScript
/**
|
||
* 诊断视频转码问题
|
||
* 检查指定素材的转码状态和可能的问题
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client'
|
||
import { existsSync } from 'fs'
|
||
import { join } from 'path'
|
||
import { access, constants } from 'fs/promises'
|
||
|
||
const prisma = new PrismaClient()
|
||
|
||
async function diagnoseMaterial(materialId: string) {
|
||
console.log(`\n==== 诊断素材转码问题: ${materialId} ====\n`)
|
||
|
||
try {
|
||
// 查询素材信息
|
||
const material = await prisma.material.findUnique({
|
||
where: { id: materialId },
|
||
}) as any
|
||
|
||
if (!material) {
|
||
console.error('❌ 素材不存在')
|
||
return
|
||
}
|
||
|
||
console.log('📋 素材信息:')
|
||
console.log(` 素材ID: ${material?.id || 'null'}`)
|
||
console.log(` 素材类型: ${material?.materialType || 'null'}`)
|
||
console.log(` 创建时间: ${material?.createdAt || 'null'}`)
|
||
console.log(` 转码状态: ${material?.videoProcessingStatus || 'null'}`)
|
||
console.log(` 转码尝试次数: ${material?.transcodeAttempts || 0}`)
|
||
console.log(` 最后错误: ${material?.transcodeLastError || '无'}`)
|
||
console.log(` videoSourceUrl: ${material?.videoSourceUrl || 'null'}`)
|
||
console.log(` zipFileName: ${material?.zipFileName || 'null'}`)
|
||
console.log(` zipFilePath: ${material?.zipFilePath || 'null'}`)
|
||
|
||
// 检查是否为视频类型
|
||
const videoTypes = ['主图视频', '安装视频', '种草视频', '视频', 'VIDEO']
|
||
const materialType = String(material?.materialType || '')
|
||
if (!videoTypes.includes(materialType)) {
|
||
console.log('\n⚠️ 此素材不是视频类型,不需要转码')
|
||
return
|
||
}
|
||
|
||
// 检查 videoSourceUrl
|
||
if (!material?.videoSourceUrl) {
|
||
console.log('\n❌ 问题:videoSourceUrl 为空')
|
||
console.log(' 可能原因:上传时未正确设置 videoSourceUrl')
|
||
return
|
||
}
|
||
|
||
console.log(`\n📁 检查视频文件:`)
|
||
const videoSourceUrl = String(material.videoSourceUrl || '')
|
||
|
||
// 检查文件是否存在
|
||
let fileExists = false
|
||
let filePath = ''
|
||
|
||
if (videoSourceUrl.startsWith('http://') || videoSourceUrl.startsWith('https://')) {
|
||
console.log(` ✅ 视频文件是 HTTP URL: ${videoSourceUrl}`)
|
||
console.log(` ⚠️ 注意:转码需要下载远程文件,可能较慢`)
|
||
fileExists = true
|
||
} else {
|
||
// 本地路径
|
||
if (videoSourceUrl.startsWith('/uploads/')) {
|
||
const uploadDir = process.env.UPLOAD_DIR || './uploads'
|
||
const absoluteUploadDir = uploadDir.startsWith('/') ? uploadDir : join(process.cwd(), uploadDir)
|
||
filePath = join(absoluteUploadDir, videoSourceUrl.replace('/uploads/', ''))
|
||
} else {
|
||
filePath = videoSourceUrl.startsWith('/') ? videoSourceUrl : join(process.cwd(), videoSourceUrl)
|
||
}
|
||
|
||
console.log(` 检查路径: ${filePath}`)
|
||
|
||
try {
|
||
await access(filePath, constants.F_OK)
|
||
fileExists = true
|
||
console.log(` ✅ 视频文件存在`)
|
||
} catch (error) {
|
||
console.log(` ❌ 视频文件不存在`)
|
||
console.log(` 错误: ${error}`)
|
||
}
|
||
}
|
||
|
||
// 检查转码状态
|
||
console.log(`\n🔄 转码状态分析:`)
|
||
const status = String(material?.videoProcessingStatus || '')
|
||
|
||
if (!status || status === 'null') {
|
||
console.log(` ❌ 问题:videoProcessingStatus 为 null`)
|
||
console.log(` 可能原因:上传时未正确设置转码状态`)
|
||
console.log(` 建议:手动触发转码`)
|
||
} else if (status === 'pending') {
|
||
console.log(` ⚠️ 状态:pending(等待转码)`)
|
||
if (!fileExists) {
|
||
console.log(` ❌ 问题:视频文件不存在,无法转码`)
|
||
} else {
|
||
console.log(` ✅ 文件存在,可以触发转码`)
|
||
console.log(` 建议:调用 /api/materials/transcode POST 接口触发转码`)
|
||
}
|
||
} else if (status === 'processing') {
|
||
console.log(` ⚠️ 状态:processing(转码中)`)
|
||
console.log(` 可能原因:`)
|
||
console.log(` 1. 转码任务正在执行`)
|
||
console.log(` 2. 上次转码中断,状态未重置`)
|
||
console.log(` 建议:检查服务器日志,或重置状态为 pending 后重试`)
|
||
} else if (status === 'done') {
|
||
console.log(` ✅ 状态:done(转码完成)`)
|
||
console.log(` 预览视频: ${material?.videoPreview540Url || '无'}`)
|
||
console.log(` 预览片段: ${material?.videoPreviewClipUrl || '无'}`)
|
||
console.log(` 封面图: ${material?.videoCoverUrl || '无'}`)
|
||
} else if (status === 'failed') {
|
||
console.log(` ❌ 状态:failed(转码失败)`)
|
||
console.log(` 错误信息: ${material?.transcodeLastError || '无'}`)
|
||
console.log(` 建议:检查错误信息,修复问题后重试`)
|
||
}
|
||
|
||
// 检查转码产物
|
||
console.log(`\n📦 转码产物:`)
|
||
console.log(` 540P预览视频: ${material?.videoPreview540Url || '无'}`)
|
||
console.log(` 10秒预览片段: ${material?.videoPreviewClipUrl || '无'}`)
|
||
console.log(` 封面图: ${material?.videoCoverUrl || '无'}`)
|
||
|
||
// 总结
|
||
console.log(`\n📊 诊断总结:`)
|
||
if (!fileExists && !videoSourceUrl.startsWith('http')) {
|
||
console.log(` ❌ 主要问题:视频文件不存在`)
|
||
console.log(` 解决方案:检查文件路径或重新上传`)
|
||
} else if (!status || status === 'null') {
|
||
console.log(` ❌ 主要问题:转码状态未设置`)
|
||
console.log(` 解决方案:手动触发转码`)
|
||
} else if (status === 'pending' && fileExists) {
|
||
console.log(` ⚠️ 问题:转码任务未触发`)
|
||
console.log(` 解决方案:调用转码 API 触发转码`)
|
||
} else if (status === 'processing') {
|
||
console.log(` ⚠️ 问题:转码状态卡在 processing`)
|
||
console.log(` 解决方案:检查服务器日志,或重置状态后重试`)
|
||
} else if (status === 'failed') {
|
||
console.log(` ❌ 问题:转码失败`)
|
||
console.log(` 解决方案:查看错误信息,修复后重试`)
|
||
} else {
|
||
console.log(` ✅ 状态正常`)
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('诊断过程出错:', error)
|
||
} finally {
|
||
await prisma.$disconnect()
|
||
}
|
||
}
|
||
|
||
// 主函数
|
||
async function main() {
|
||
const materialId = process.argv[2]
|
||
|
||
if (!materialId) {
|
||
console.error('用法: tsx scripts/diagnose-video-transcode.ts <materialId>')
|
||
console.error('示例: tsx scripts/diagnose-video-transcode.ts 0895f84d-8837-465e-be50-4db57b5eab9e')
|
||
process.exit(1)
|
||
}
|
||
|
||
await diagnoseMaterial(materialId)
|
||
}
|
||
|
||
main().catch(console.error)
|
||
|