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 = '安装视频' export const LIVE_CLIP_VIDEO_TYPE = '直播切片' const MATERIAL_TYPE_ALIASES: Record = { 主图视频: 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, LIVE_CLIP_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([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' ) }