Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 228x 228x 228x 1x 1x 1x 1x 1x 1x 1x 1x 199x 199x 199x 199x 199x 1x 1x 1x 1x 1x 1x 1x 13x 13x | import { fnv1a32 } from '@/lib/fnv1a'
import type { TtsSay } from './TtsAudioManager'
/**
* Resolve the canonical text from a say map.
* Priority: say['en-US'] > say['en'] > first value > ''
*
* This deterministic resolution means adding lower-priority translations
* (e.g. 'es', 'ja') does NOT change the canonical text.
*/
export function resolveCanonicalText(say: Record<string, string> | undefined | null): string {
if (!say) return ''
return say['en-US'] ?? say['en'] ?? Object.values(say)[0] ?? ''
}
/**
* Compute a deterministic clip ID from say text + tone.
* Returns 'h-' + 8 hex chars, e.g. 'h-a3f2b1c0'
*
* Hash input: resolveCanonicalText(say) + '\0' + tone
*/
export function computeClipHash(say: TtsSay, tone: string): string {
const canonical = resolveCanonicalText(say)
const hashInput = canonical + '\0' + tone
const hash = fnv1a32(hashInput)
return 'h-' + hash.toString(16).padStart(8, '0')
}
const HASH_CLIP_ID_RE = /^h-[0-9a-f]{8}$/
/**
* Returns true if clipId matches the hash-based format: 'h-' + 8 hex chars.
*/
export function isHashClipId(clipId: string): boolean {
return HASH_CLIP_ID_RE.test(clipId)
}
|