Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
90 lines
2.9 KiB
TypeScript
90 lines
2.9 KiB
TypeScript
export const TAOXI_MAIN_VIDEO_TYPE = '淘系-主图视频'
|
|
export const TAOXI_GUANGGUANG_VIDEO_TYPE = '淘系-逛逛视频'
|
|
export const DOUYIN_QIANCHUAN_VIDEO_TYPE = '抖音-千川素材'
|
|
export const DOUYIN_ACCOUNT_MAINTENANCE_VIDEO_TYPE = '抖音-账号维护'
|
|
export const INSTALL_VIDEO_TYPE = '安装视频'
|
|
|
|
const MATERIAL_TYPE_ALIASES: Record<string, string> = {
|
|
主图视频: TAOXI_MAIN_VIDEO_TYPE,
|
|
种草视频: TAOXI_GUANGGUANG_VIDEO_TYPE,
|
|
}
|
|
|
|
export const CANONICAL_VIDEO_MATERIAL_TYPES = [
|
|
TAOXI_MAIN_VIDEO_TYPE,
|
|
INSTALL_VIDEO_TYPE,
|
|
TAOXI_GUANGGUANG_VIDEO_TYPE,
|
|
DOUYIN_QIANCHUAN_VIDEO_TYPE,
|
|
DOUYIN_ACCOUNT_MAINTENANCE_VIDEO_TYPE,
|
|
] as const
|
|
|
|
export const LEGACY_COMPATIBLE_VIDEO_MATERIAL_TYPES = [
|
|
'视频',
|
|
'VIDEO',
|
|
...CANONICAL_VIDEO_MATERIAL_TYPES,
|
|
...Object.keys(MATERIAL_TYPE_ALIASES),
|
|
] as const
|
|
|
|
export function normalizeVideoMaterialType(materialType?: string | null): string {
|
|
const trimmed = (materialType || '').trim()
|
|
if (!trimmed) {
|
|
return ''
|
|
}
|
|
|
|
return MATERIAL_TYPE_ALIASES[trimmed] || trimmed
|
|
}
|
|
|
|
export function getCompatibleVideoMaterialTypes(materialType?: string | null): string[] {
|
|
const trimmed = (materialType || '').trim()
|
|
if (!trimmed) {
|
|
return []
|
|
}
|
|
|
|
const normalized = normalizeVideoMaterialType(trimmed)
|
|
const candidates = new Set<string>([trimmed, normalized])
|
|
|
|
for (const [legacyType, canonicalType] of Object.entries(MATERIAL_TYPE_ALIASES)) {
|
|
if (canonicalType === normalized) {
|
|
candidates.add(legacyType)
|
|
}
|
|
}
|
|
|
|
return Array.from(candidates)
|
|
}
|
|
|
|
export function isVideoMaterialType(materialType?: string | null): boolean {
|
|
const normalized = normalizeVideoMaterialType(materialType)
|
|
return LEGACY_COMPATIBLE_VIDEO_MATERIAL_TYPES.includes(
|
|
normalized as (typeof LEGACY_COMPATIBLE_VIDEO_MATERIAL_TYPES)[number],
|
|
)
|
|
}
|
|
|
|
export function isVideoTranscodeInFlight(status?: string | null): boolean {
|
|
const normalized = String(status || '').trim().toLowerCase()
|
|
return normalized === 'pending' || normalized === 'processing'
|
|
}
|
|
|
|
/**
|
|
* 轮询只依赖可公开返回的素材类型和处理状态,不能依赖 videoSourceUrl。
|
|
* 15 天访问策略会有意隐藏源视频地址,但后台封面生成状态仍需正常刷新。
|
|
*/
|
|
export function shouldPollVideoTranscode(
|
|
materialType?: string | null,
|
|
status?: string | null,
|
|
): boolean {
|
|
return isVideoMaterialType(materialType) && isVideoTranscodeInFlight(status)
|
|
}
|
|
|
|
export function isBatchVideoMaterialType(materialType?: string | null): boolean {
|
|
return normalizeVideoMaterialType(materialType) === TAOXI_GUANGGUANG_VIDEO_TYPE
|
|
}
|
|
|
|
export function isSingleVideoUploadMaterialType(materialType?: string | null): boolean {
|
|
const normalized = normalizeVideoMaterialType(materialType)
|
|
return (
|
|
isVideoMaterialType(normalized) &&
|
|
normalized !== TAOXI_GUANGGUANG_VIDEO_TYPE &&
|
|
normalized !== '视频' &&
|
|
normalized !== 'VIDEO'
|
|
)
|
|
}
|