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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 217x 217x 217x 6x 6x 1x 1x 55x 55x 1x 1x 10x 10x 1x 1x 15x 12x 15x 15x 1x 1x 3x 3x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 1x 1x 2x 2x | import { parseSongPlan } from '@/lib/song-share/songPlan'
import type { SongRow } from './queries'
export const ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/
export const VERSION_PATTERN = /^[a-f0-9]{64}$/
// Spelled as a code-unit scan rather than a regex character class: a class over
// C0/C1 is what lint/suspicious/noControlCharactersInRegex exists to catch, and
// suppressing that rule would hide the next one someone writes by accident.
function hasControlCharacter(value: string): boolean {
for (let index = 0; index < value.length; index += 1) {
const code = value.charCodeAt(index)
if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) return true
}
return false
}
export function isValidId(value: unknown): value is string {
return typeof value === 'string' && ID_PATTERN.test(value)
}
export function isValidAudioVersion(value: unknown): value is string {
return typeof value === 'string' && VERSION_PATTERN.test(value)
}
export function isValidTitle(value: unknown): value is string {
if (typeof value !== 'string') return false
const title = value.trim()
return title.length >= 1 && title.length <= 120 && !hasControlCharacter(title)
}
export function toIso(value: Date | number | string): string {
return (value instanceof Date ? value : new Date(value)).toISOString()
}
export function toNullableIso(value: Date | number | string | null): string | null {
return value == null ? null : toIso(value)
}
export interface EligibleSongCandidate extends SongRow {
title: string
}
export function toEligibleSongCandidate(row: SongRow): EligibleSongCandidate | null {
if (row.status !== 'completed' || row.contentReviewStatus === 'flagged') return null
const rawTitle = parseSongPlan(row.llmOutput).title
if (!isValidTitle(rawTitle)) return null
return { ...row, title: rawTitle.trim() }
}
export function audioUrlFor(playerId: string, songId: string, version: string): string {
return `/api/integrations/kid-songs/${playerId}/audio?songId=${songId}&v=${version}`
}
|