# MediaPlayer.v2 - 최적화된 비디오 플레이어 **위치**: `src/components/VideoPlayer/MediaPlayer.v2.jsx` --- ## 📊 개요 webOS 환경에 최적화된 경량 비디오 플레이어 컴포넌트입니다. 기존 MediaPlayer.jsx의 핵심 기능은 유지하면서 불필요한 복잡도를 제거했습니다. ### 주요 개선사항 | 항목 | 기존 | v2 | 개선율 | |------|------|-----|--------| | **코드 라인** | 2,595 | 388 | **85%↓** | | **상태 변수** | 20+ | 7 | **65%↓** | | **Props** | 70+ | 18 | **74%↓** | | **타이머/Job** | 8 | 1 | **87%↓** | | **필수 기능** | 100% | 100% | **✅ 유지** | --- ## ✨ 주요 기능 ### 1. Modal ↔ Fullscreen 전환 ```javascript // Modal 모드로 시작 dispatch(switchMediaToFullscreen())} style={modalStyle} // MediaPanel에서 계산 /> // 클릭 시 자동으로 Fullscreen으로 전환 ``` ### 2. 기본 재생 제어 ```javascript const playerRef = useRef(); // API 메서드 playerRef.current.play(); playerRef.current.pause(); playerRef.current.seek(30); playerRef.current.getMediaState(); playerRef.current.showControls(); playerRef.current.hideControls(); ``` ### 3. isPaused 동기화 ```javascript // Modal 모드에서 다른 패널이 위로 올라오면 자동 일시정지 ``` ### 4. webOS / 브라우저 자동 감지 ```javascript // webOS: Media 컴포넌트 // 브라우저: TReactPlayer // YouTube: TReactPlayer // 자동으로 적절한 컴포넌트 선택 ``` --- ## 📐 Props ### 필수 Props ```typescript interface MediaPlayerV2Props { // 비디오 소스 (필수) src: string; } ``` ### 선택 Props ```typescript interface MediaPlayerV2Props { // 비디오 설정 type?: string; // 기본: 'video/mp4' thumbnailUrl?: string; // 재생 제어 autoPlay?: boolean; // 기본: false loop?: boolean; // 기본: false muted?: boolean; // 기본: false // Modal 전환 disabled?: boolean; // Modal에서 true spotlightDisabled?: boolean; onClick?: () => void; // Modal 클릭 시 style?: CSSProperties; // Modal fixed position modalClassName?: string; modalScale?: number; // 패널 정보 panelInfo?: { modal?: boolean; modalContainerId?: string; isPaused?: boolean; }; // 콜백 onEnded?: (e: Event) => void; onError?: (e: Event) => void; onBackButton?: (e: Event) => void; onLoadStart?: (e: Event) => void; onTimeUpdate?: (e: Event) => void; onLoadedData?: (e: Event) => void; onLoadedMetadata?: (e: Event) => void; onDurationChange?: (e: Event) => void; // Spotlight spotlightId?: string; // 기본: 'mediaPlayerV2' // 비디오 컴포넌트 videoComponent?: React.ComponentType; // ReactPlayer 설정 reactPlayerConfig?: object; // 기타 children?: React.ReactNode; // , tags className?: string; } ``` --- ## 💻 사용 예제 ### 기본 사용 ```javascript import MediaPlayerV2 from '../components/VideoPlayer/MediaPlayer.v2'; function MyComponent() { return ( console.log('Video ended')} /> ); } ``` ### Modal 모드 (MediaPanel에서 사용) ```javascript import MediaPlayerV2 from '../components/VideoPlayer/MediaPlayer.v2'; function MediaPanel({ panelInfo }) { const [modalStyle, setModalStyle] = useState({}); useEffect(() => { if (panelInfo.modal && panelInfo.modalContainerId) { const node = document.querySelector( `[data-spotlight-id="${panelInfo.modalContainerId}"]` ); const rect = node.getBoundingClientRect(); setModalStyle({ position: 'fixed', top: rect.top + 'px', left: rect.left + 'px', width: rect.width + 'px', height: rect.height + 'px', }); } }, [panelInfo]); const handleVideoClick = () => { if (panelInfo.modal) { dispatch(switchMediaToFullscreen()); } }; return ( ); } ``` ### API 사용 ```javascript import { useRef } from 'react'; import MediaPlayerV2 from '../components/VideoPlayer/MediaPlayer.v2'; function MyComponent() { const playerRef = useRef(); const handlePlay = () => { playerRef.current?.play(); }; const handlePause = () => { playerRef.current?.pause(); }; const handleSeek = (time) => { playerRef.current?.seek(time); }; const getState = () => { const state = playerRef.current?.getMediaState(); console.log(state); // { // currentTime: 10.5, // duration: 120, // paused: false, // loading: false, // error: null, // playbackRate: 1, // proportionPlayed: 0.0875 // } }; return ( <> ); } ``` ### webOS 태그 사용 ```javascript ``` ### YouTube 재생 ```javascript ``` --- ## 🔧 API 메서드 ref를 통해 다음 메서드에 접근할 수 있습니다: ```typescript interface MediaPlayerV2API { // 재생 제어 play(): void; pause(): void; seek(timeIndex: number): void; // 상태 조회 getMediaState(): { currentTime: number; duration: number; paused: boolean; loading: boolean; error: Error | null; playbackRate: number; proportionPlayed: number; }; // Controls 제어 showControls(): void; hideControls(): void; toggleControls(): void; areControlsVisible(): boolean; // Video Node 접근 getVideoNode(): HTMLVideoElement | ReactPlayerInstance; } ``` --- ## 🎯 제거된 기능 다음 기능들은 MediaPanel 사용 케이스에 불필요하여 제거되었습니다: ``` ❌ MediaSlider (seek bar) ❌ jumpBy, fastForward, rewind ❌ playbackRate 조정 ❌ QR코드 오버레이 ❌ 전화번호 오버레이 ❌ 테마 인디케이터 ❌ 복잡한 피드백 시스템 (8개 Job → 1개 setTimeout) ❌ FloatingLayer ❌ Redux 통합 ❌ TabContainer 동기화 ❌ Announce/Accessibility 복잡계 ❌ MediaTitle, infoComponents ``` 필요하다면 기존 MediaPlayer.jsx를 사용하세요. --- ## 🚀 성능 ### 메모리 사용량 - **타이머**: 8개 Job → 1개 setTimeout - **이벤트 리스너**: 최소화 (video element events만) - **상태 변수**: 7개 (20+개에서 감소) ### 렌더링 성능 - **useMemo**: 계산 비용이 큰 값 캐싱 - **useCallback**: 함수 재생성 방지 - **조건부 렌더링**: 불필요한 DOM 요소 제거 --- ## 🔄 마이그레이션 가이드 ### 기존 MediaPlayer.jsx에서 마이그레이션 대부분의 props는 호환됩니다: ```javascript // 기존 import { VideoPlayer } from '../components/VideoPlayer/MediaPlayer'; // 새로운 import MediaPlayerV2 from '../components/VideoPlayer/MediaPlayer.v2'; ``` 제거된 props: - `jumpBy`, `initialJumpDelay`, `jumpDelay` - `playbackRateHash` - `onFastForward`, `onRewind`, `onJumpBackward`, `onJumpForward` - `feedbackHideDelay`, `miniFeedbackHideDelay` - `noMediaSliderFeedback`, `noMiniFeedback`, `noSlider` - `title`, `infoComponents` - 기타 PlayerPanel 전용 props --- ## 📝 Notes ### Modal 전환 작동 방식 1. **MediaPanel**이 `getBoundingClientRect()`로 스타일 계산 2. **MediaPlayerV2**는 받은 `style`을 그대로 적용 3. `modal` 플래그에 따라 controls/spotlight 활성화 제어 → **MediaPlayerV2는 전환 로직 구현 불필요** ### webOS 호환성 - `window.PalmSystem` 존재 시 `Media` 컴포넌트 사용 - 브라우저에서는 `TReactPlayer` 사용 - YouTube URL은 항상 `TReactPlayer` 사용 --- ## 🐛 알려진 제약사항 1. **Seek bar 없음**: 단순 재생만 지원 2. **빠르기 조정 없음**: 배속 재생 미지원 3. **간단한 Controls**: 재생/일시정지 버튼만 복잡한 컨트롤이 필요하다면 기존 `MediaPlayer.jsx` 사용을 권장합니다. --- ## 📚 관련 문서 - [비디오 플레이어 분석 문서](.docs/video-player-analysis-and-optimization-plan.md) - [Modal 전환 상세 분석](.docs/modal-transition-analysis.md)