import { RawExercise, Exercise, ExerciseSummary, ExerciseType, } from '../exercises.interface'; import { BODY_PART_LABELS, EQUIPMENT_LABELS, MUSCLE_LABELS, labelOf, } from '../data/labels'; const MEDIA_BASE_URL = ( process.env.MEDIA_BASE_URL || 'https://cdn.jsdelivr.net/gh/hasaneyldrm/exercises-dataset@main' ).replace(/\/$/, ''); function toMediaUrl(path: string): string { if (!path) return ''; if (/^https?:\/\//.test(path)) return path; return `${MEDIA_BASE_URL}/${path}`; } function deriveType(raw: RawExercise): ExerciseType { if (raw.body_part === 'cardio') return 'cardio'; const hay = `${raw.name} ${raw.equipment} ${raw.category || ''}`.toLowerCase(); const flexKeywords = ['stretch', 'yoga', 'mobility', 'pilates', 'flexibility', 'foam roll']; if (flexKeywords.some((k) => hay.includes(k))) return 'flexibility'; return 'strength'; } const TYPE_LABELS: Record = { strength: '力量', cardio: '有氧', flexibility: '柔韧', }; export function normalize(raw: RawExercise): Exercise { const type = deriveType(raw); const zh = raw.instructions?.zh || ''; const en = raw.instructions?.en || ''; const zhSteps = raw.instruction_steps?.zh || []; const enSteps = raw.instruction_steps?.en || []; return { id: raw.id, name: raw.name, bodyPart: raw.body_part, bodyPartLabel: labelOf(BODY_PART_LABELS, raw.body_part), equipment: raw.equipment, equipmentLabel: labelOf(EQUIPMENT_LABELS, raw.equipment), target: raw.target, targetLabel: labelOf(MUSCLE_LABELS, raw.target), muscleGroup: raw.muscle_group, muscleGroupLabel: labelOf(MUSCLE_LABELS, raw.muscle_group), secondaryMuscles: raw.secondary_muscles || [], secondaryMusclesLabels: (raw.secondary_muscles || []).map( (m) => labelOf(MUSCLE_LABELS, m), ), type, typeLabel: TYPE_LABELS[type], image: toMediaUrl(raw.image), gifUrl: toMediaUrl(raw.gif_url), instructions: { zh, en }, instructionSteps: { zh: zhSteps, en: enSteps }, attribution: raw.attribution, mediaId: raw.media_id, }; } export function toSummary(ex: Exercise): ExerciseSummary { return { id: ex.id, name: ex.name, bodyPart: ex.bodyPart, bodyPartLabel: ex.bodyPartLabel, equipment: ex.equipment, equipmentLabel: ex.equipmentLabel, target: ex.target, targetLabel: ex.targetLabel, type: ex.type, typeLabel: ex.typeLabel, image: ex.image, gifUrl: ex.gifUrl, }; }