Files
BYW-VoiceHub/server/services/durationValidationService.ts
T

75 lines
2.5 KiB
TypeScript

import { db } from '~/drizzle/db'
import { songs } from '~/drizzle/schema'
import { eq } from 'drizzle-orm'
import { fetchSongDuration } from '~~/server/utils/songDurationFetcher'
import {
decideDurationOutcome,
type SongDurationDecision
} from '~~/server/utils/song-duration-policy'
/** 后台批量补齐的并发数 */
const BACKFILL_BATCH_SIZE = 5
/**
* 投稿后处理时长:缺失则按音源补齐,已有则校验一致性
* 仅返回决策,写库由调用方负责
*/
export async function reconcileSongDurationOnSubmit(
songId: number,
platform: string | null,
musicId: string | null,
storedDurationSeconds: number | null
): Promise<SongDurationDecision> {
if (!platform || !musicId) {
return { outcome: 'nocheck', durationSeconds: storedDurationSeconds }
}
try {
const actualDuration = await fetchSongDuration(platform, musicId)
const decision = decideDurationOutcome(storedDurationSeconds, actualDuration)
if (decision.outcome === 'clear') {
console.log(
`[投稿时长] #${songId} 时长不符 (提交: ${storedDurationSeconds}s, API: ${actualDuration}s),清除durationSeconds`
)
}
return decision
} catch (error) {
// 外部接口异常时保留原值,不因为后台问题影响用户投稿
console.error(`[投稿时长] #${songId} 处理失败:`, error)
return { outcome: 'nocheck', durationSeconds: storedDurationSeconds }
}
}
export interface SongDurationBackfillRow {
id: number
musicPlatform: string | null
musicId: string | null
}
type BackfillableRow = SongDurationBackfillRow & { musicPlatform: string; musicId: string }
/** 批量补齐缺失时长,单条失败不影响其余 */
export async function backfillMissingSongDurations(rows: SongDurationBackfillRow[], label: string): Promise<void> {
const targets = rows.filter(
(row): row is BackfillableRow => Boolean(row.musicPlatform) && Boolean(row.musicId)
)
for (let i = 0; i < targets.length; i += BACKFILL_BATCH_SIZE) {
const batch = targets.slice(i, i + BACKFILL_BATCH_SIZE)
await Promise.all(
batch.map(async (row) => {
try {
const duration = await fetchSongDuration(row.musicPlatform, row.musicId)
if (duration === null) {
console.warn(`[${label}] 歌曲 #${row.id} 未获取到有效时长`)
return
}
await db.update(songs).set({ durationSeconds: duration }).where(eq(songs.id, row.id))
} catch (error) {
console.warn(`[${label}] 歌曲 #${row.id} 时长补齐失败:`, error)
}
})
)
}
}