203 lines
6.6 KiB
PowerShell
203 lines
6.6 KiB
PowerShell
# 批量转码所有视频素材脚本
|
||
# 用途:一次性任务,将所有视频素材重新转码为新标准(720P + H.265)
|
||
# 注意:转码完成后,旧的预览文件会自动清理
|
||
|
||
param(
|
||
[Parameter(Mandatory=$false)]
|
||
[switch]$DryRun = $false,
|
||
|
||
[Parameter(Mandatory=$false)]
|
||
[int]$BatchSize = 1000, # 每批处理数量(最大1000)
|
||
|
||
[Parameter(Mandatory=$false)]
|
||
[string]$BaseUrl = "http://localhost:3000" # API 基础URL
|
||
)
|
||
|
||
# 颜色输出函数
|
||
function Write-ColorOutput($ForegroundColor) {
|
||
$fc = $host.UI.RawUI.ForegroundColor
|
||
$host.UI.RawUI.ForegroundColor = $ForegroundColor
|
||
if ($args) {
|
||
Write-Output $args
|
||
}
|
||
$host.UI.RawUI.ForegroundColor = $fc
|
||
}
|
||
|
||
function Write-Info { Write-ColorOutput Cyan $args }
|
||
function Write-Success { Write-ColorOutput Green $args }
|
||
function Write-Warning { Write-ColorOutput Yellow $args }
|
||
function Write-Error { Write-ColorOutput Red $args }
|
||
|
||
Write-Info "=========================================="
|
||
Write-Info "批量转码所有视频素材"
|
||
Write-Info "=========================================="
|
||
if ($DryRun) {
|
||
Write-Info "模式: 试运行 (Dry Run)"
|
||
} else {
|
||
Write-Info "模式: 实际执行"
|
||
}
|
||
Write-Info "批次大小: $BatchSize"
|
||
Write-Info "API URL: $BaseUrl"
|
||
Write-Info ""
|
||
|
||
# 检查是否需要管理员认证
|
||
# 注意:实际使用时需要提供管理员 session cookie 或 API key
|
||
# 这里假设通过环境变量或配置文件提供认证信息
|
||
|
||
$headers = @{
|
||
"Content-Type" = "application/json"
|
||
}
|
||
|
||
# 如果需要认证,可以添加:
|
||
# $headers["Cookie"] = "next-auth.session-token=YOUR_SESSION_TOKEN"
|
||
# 或者使用 API key(如果实现了)
|
||
|
||
# 第一步:统计需要转码的素材数量
|
||
Write-Info "📊 第一步:统计需要转码的素材数量..."
|
||
$dryRunBody = @{
|
||
limit = $BatchSize
|
||
status = "any" # 转码所有状态的视频(done、failed、null等)
|
||
dryRun = $true
|
||
} | ConvertTo-Json
|
||
|
||
try {
|
||
$response = Invoke-RestMethod -Uri "$BaseUrl/api/admin/video-retranscode" `
|
||
-Method POST `
|
||
-Headers $headers `
|
||
-Body $dryRunBody `
|
||
-ErrorAction Stop
|
||
|
||
$totalCount = $response.matched
|
||
Write-Success "✓ 找到 $totalCount 个视频素材需要转码"
|
||
|
||
if ($totalCount -eq 0) {
|
||
Write-Warning "没有找到需要转码的视频素材"
|
||
exit 0
|
||
}
|
||
|
||
Write-Info "前10个素材预览:"
|
||
if ($response.sample) {
|
||
$response.sample | ForEach-Object {
|
||
Write-Info " - ID: $($_.id), 产品: $($_.productModel), 状态: $($_.status)"
|
||
}
|
||
}
|
||
|
||
} catch {
|
||
Write-Error "❌ 统计失败: $($_.Exception.Message)"
|
||
if ($_.Exception.Response) {
|
||
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
|
||
$responseBody = $reader.ReadToEnd()
|
||
Write-Error "响应: $responseBody"
|
||
}
|
||
exit 1
|
||
}
|
||
|
||
if ($DryRun) {
|
||
Write-Info ""
|
||
Write-Warning "⚠️ 这是试运行模式,未执行实际转码"
|
||
Write-Info "如需执行实际转码,请运行:"
|
||
Write-Info " .\scripts\batch-retranscode-all-videos.ps1 -DryRun:`$false"
|
||
exit 0
|
||
}
|
||
|
||
# 第二步:确认执行
|
||
Write-Info ""
|
||
Write-Warning "⚠️ 警告:即将开始批量转码 $totalCount 个视频素材"
|
||
Write-Warning " 转码是异步执行的,会进入队列处理"
|
||
Write-Warning " 转码完成后,旧的预览文件会自动清理"
|
||
Write-Info ""
|
||
$confirm = Read-Host "确认继续?(yes/no)"
|
||
if ($confirm -ne "yes") {
|
||
Write-Info "已取消操作"
|
||
exit 0
|
||
}
|
||
|
||
# 第三步:分批执行转码
|
||
Write-Info ""
|
||
Write-Info "🚀 开始批量转码..."
|
||
$totalBatches = [Math]::Ceiling($totalCount / $BatchSize)
|
||
Write-Info "预计需要 $totalBatches 个批次"
|
||
|
||
$totalQueued = 0
|
||
$totalFailed = 0
|
||
|
||
for ($batch = 1; $batch -le $totalBatches; $batch++) {
|
||
Write-Info ""
|
||
Write-Info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
Write-Info "批次 $batch/$totalBatches"
|
||
Write-Info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
|
||
$body = @{
|
||
limit = $BatchSize
|
||
status = "any"
|
||
dryRun = $false
|
||
} | ConvertTo-Json
|
||
|
||
try {
|
||
$response = Invoke-RestMethod -Uri "$BaseUrl/api/admin/video-retranscode" `
|
||
-Method POST `
|
||
-Headers $headers `
|
||
-Body $body `
|
||
-ErrorAction Stop
|
||
|
||
$queued = $response.queued
|
||
$failed = $response.failed
|
||
$matched = $response.matched
|
||
|
||
$totalQueued += $queued
|
||
$totalFailed += $failed
|
||
|
||
Write-Success "✓ 批次 $batch 完成: 已排队 $queued 个,失败 $failed 个"
|
||
|
||
if ($response.details -and $response.details.Count -gt 0) {
|
||
$failedDetails = $response.details | Where-Object { -not $_.ok }
|
||
if ($failedDetails.Count -gt 0) {
|
||
Write-Warning "失败详情(前5个):"
|
||
$failedDetails | Select-Object -First 5 | ForEach-Object {
|
||
Write-Warning " - ID: $($_.id), 状态: $($_.status), 错误: $($_.message)"
|
||
}
|
||
}
|
||
}
|
||
|
||
# 如果这一批匹配的数量少于批次大小,说明已经处理完所有素材
|
||
if ($matched -lt $BatchSize) {
|
||
Write-Info "已处理完所有素材"
|
||
break
|
||
}
|
||
|
||
# 批次间稍作延迟,避免请求过快
|
||
if ($batch -lt $totalBatches) {
|
||
Write-Info "等待 2 秒后继续下一批次..."
|
||
Start-Sleep -Seconds 2
|
||
}
|
||
|
||
} catch {
|
||
Write-Error "❌ 批次 $batch 失败: $($_.Exception.Message)"
|
||
if ($_.Exception.Response) {
|
||
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
|
||
$responseBody = $reader.ReadToEnd()
|
||
Write-Error "响应: $responseBody"
|
||
}
|
||
# 继续处理下一批次
|
||
continue
|
||
}
|
||
}
|
||
|
||
# 总结
|
||
Write-Info ""
|
||
Write-Info "=========================================="
|
||
Write-Info "批量转码完成"
|
||
Write-Info "=========================================="
|
||
Write-Success "✓ 总计已排队: $totalQueued 个"
|
||
if ($totalFailed -gt 0) {
|
||
Write-Warning "⚠️ 总计失败: $totalFailed 个"
|
||
}
|
||
Write-Info ""
|
||
Write-Info "📝 说明:"
|
||
Write-Info " - 转码是异步执行的,会进入队列处理"
|
||
Write-Info " - 实际并发数由服务器配置控制(VIDEO_TRANSCODE_MAX_CONCURRENT)"
|
||
Write-Info " - 转码成功后,旧的预览文件会自动清理"
|
||
Write-Info " - 可以在管理员页面查看转码进度和状态"
|
||
Write-Info ""
|
||
|