Files
Trey t 1c61b80731 workout generator audit: rules engine, structure rules, split patterns, injury UX, metadata cleanup
- Add rules_engine.py with quantitative rules for all 8 workout types
- Add quality gate retry loop in generate_single_workout()
- Expand calibrate_structure_rules to all 120 combinations (8 types × 5 goals × 3 sections)
- Wire WeeklySplitPattern DB records into _pick_weekly_split()
- Enforce movement patterns from WorkoutStructureRule in exercise selection
- Add straight-set strength support (single main lift, 4-6 rounds)
- Add modality consistency check for duration-dominant workout types
- Add InjuryStep component to onboarding and preferences
- Add sibling exercise exclusion in regenerate and preview_day endpoints
- Display generator warnings on dashboard
- Expand fix_rep_durations, fix_exercise_flags, fix_movement_pattern_typo
- Add audit_exercise_data and check_rules_drift management commands
- Add Next.js frontend with dashboard, onboarding, preferences, history pages
- Add generator app with ML-powered workout generation pipeline
- 96 new tests across 7 test modules

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 20:07:40 -06:00

53 lines
1.1 KiB
TypeScript

"use client";
import { useEffect, useRef } from "react";
import Hls from "hls.js";
interface VideoPlayerProps {
src: string;
poster?: string;
}
export function VideoPlayer({ src, poster }: VideoPlayerProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const hlsRef = useRef<Hls | null>(null);
useEffect(() => {
const video = videoRef.current;
if (!video) return;
const isHLS = src.endsWith(".m3u8");
if (isHLS) {
if (Hls.isSupported()) {
const hls = new Hls();
hlsRef.current = hls;
hls.loadSource(src);
hls.attachMedia(video);
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
// Native HLS support (Safari)
video.src = src;
}
} else {
video.src = src;
}
return () => {
if (hlsRef.current) {
hlsRef.current.destroy();
hlsRef.current = null;
}
};
}, [src]);
return (
<video
ref={videoRef}
poster={poster}
controls
playsInline
className="w-full rounded-lg bg-zinc-900"
/>
);
}