From ec76d2cfc9d6db8e634b67cd1f830bcd47780035 Mon Sep 17 00:00:00 2001 From: optrader Date: Wed, 17 Dec 2025 16:09:01 +0900 Subject: [PATCH] =?UTF-8?q?[251217]=20fix:=20VOD=20=EA=B2=BD=EA=B3=BC?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ• 컀밋 μ‹œκ°„: 2025. 12. 17. 16:09:01 πŸ“Š λ³€κ²½ 톡계: β€’ 총 파일: 2개 β€’ μΆ”κ°€: +18쀄 β€’ μ‚­μ œ: -205쀄 πŸ“ μˆ˜μ •λœ 파일: ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js πŸ”§ μ£Όμš” λ³€κ²½ λ‚΄μš©: β€’ UI μ»΄ν¬λ„ŒνŠΈ μ•„ν‚€ν…μ²˜ κ°œμ„  β€’ μ½”λ“œ 정리 및 μ΅œμ ν™” Performance: μ½”λ“œ μ΅œμ ν™”λ‘œ μ„±λŠ₯ κ°œμ„  κΈ°λŒ€ --- .../components/VideoPlayer/MediaPlayer.jsx | 15 +- .../src/components/VideoPlayer/VideoPlayer.js | 208 +----------------- 2 files changed, 18 insertions(+), 205 deletions(-) diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx index f794669f..32c500b9 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx @@ -840,9 +840,11 @@ const VideoPlayerBase = class extends React.Component { this.state.mediaSliderVisible === nextState.mediaSliderVisible && this.state.loading === nextState.loading && this.props.loading === nextProps.loading && - (this.state.currentTime !== nextState.currentTime || - this.state.proportionPlayed !== nextState.proportionPlayed || - this.state.sliderTooltipTime !== nextState.sliderTooltipTime) + this.state.currentTime === nextState.currentTime && + this.state.proportionPlayed === nextState.proportionPlayed && + this.state.sliderTooltipTime === nextState.sliderTooltipTime && + this.state.mediaControlsVisible === nextState.mediaControlsVisible && + this.state.bottomControlsRendered === nextState.bottomControlsRendered ) { return false; } @@ -1279,14 +1281,11 @@ const VideoPlayerBase = class extends React.Component { sourceUnavailable: true, proportionPlayed: 0, proportionLoaded: 0, + bottomControlsRendered: true, }); if (!this.props.noAutoShowMediaControls) { - if (!this.state.bottomControlsRendered) { - this.renderBottomControl.idle(); - } else { - this.showControls(); - } + this.showControls(); } }; diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js index a4a71b88..9ba71f11 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js +++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js @@ -855,9 +855,11 @@ const VideoPlayerBase = class extends React.Component { this.state.mediaSliderVisible === nextState.mediaSliderVisible && this.state.loading === nextState.loading && this.props.loading === nextProps.loading && - (this.state.currentTime !== nextState.currentTime || - this.state.proportionPlayed !== nextState.proportionPlayed || - this.state.sliderTooltipTime !== nextState.sliderTooltipTime) + this.state.currentTime === nextState.currentTime && + this.state.proportionPlayed === nextState.proportionPlayed && + this.state.sliderTooltipTime === nextState.sliderTooltipTime && + this.state.mediaControlsVisible === nextState.mediaControlsVisible && + this.state.bottomControlsRendered === nextState.bottomControlsRendered ) { return false; } @@ -1423,14 +1425,11 @@ const VideoPlayerBase = class extends React.Component { sourceUnavailable: true, proportionPlayed: 0, proportionLoaded: 0, + bottomControlsRendered: true, }); if (!this.props.noAutoShowMediaControls) { - if (!this.state.bottomControlsRendered) { - this.renderBottomControl.idle(); - } else { - this.showControls(); - } + this.showControls(); } }; @@ -1636,103 +1635,6 @@ const VideoPlayerBase = class extends React.Component { updatedState.thumbnailUrl = null; } this.setState(updatedState); - - // Redux에 λΉ„λ””μ˜€ μž¬μƒ μƒνƒœ μ—…λ°μ΄νŠΈ (κΈ°μ‘΄ 둜직 μœ μ§€) - if (this.props.dispatch) { - // πŸ”₯ onProgress μ΄λ²€νŠΈλŠ” Redux μ—…λ°μ΄νŠΈν•˜μ§€ μ•ŠμŒ (λΉˆλ²ˆν•œ 이벀트) - const shouldUpdateRedux = !['onProgress'].includes(ev.type); - - if (shouldUpdateRedux) { - const updateState = { - isPlaying: !updatedState.paused, - isPaused: updatedState.paused, - currentTime: updatedState.currentTime, - duration: updatedState.duration, - playbackRate: updatedState.playbackRate, - }; - - // κ°€μž₯ μ€‘μš”ν•œ 이벀트만 둜그 - const shouldLogEvent = ['play', 'pause', 'ended'].includes(ev.type); - if (shouldLogEvent) { - dlog('πŸ”„ [PlayerPanel][VideoPlayer] Event-driven Redux update', { - eventType: ev.type, - videoState: updatedState, - updateState, - timestamp: new Date().toISOString(), - }); - } - - // πŸ” Redux dispatch 확인 - dlog('πŸ“€ [PlayerPanel][VideoPlayer] Dispatching Redux update', { - eventType: ev.type, - updateState, - hasDispatch: !!this.props.dispatch, - propsVideoPlayState: this.props.videoPlayState, - }); - - this.props.dispatch(updateVideoPlayState(updateState)); - } - } else { - derror('❌ [PlayerPanel][VideoPlayer] No dispatch prop available', { - props: Object.keys(this.props), - hasDispatch: !!this.props.dispatch, - hasVideoPlayState: !!this.props.videoPlayState, - }); - } - - // πŸ”Ή [κ°•ν™”] λ‚΄λΆ€ μƒνƒœμ™€ Redux μƒνƒœ 동기화 - // Redux μƒνƒœλ₯Ό μš°μ„ μ μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ λ‚΄λΆ€ μƒνƒœ 일관성 확보 - if (this.props.videoPlayState && typeof this.props.videoPlayState === 'object') { - // Redux μƒνƒœ 디버깅 (μ΅œμ†Œν•œμ˜ μ€‘μš” 이벀트만) - if (ev.type === 'play' || ev.type === 'pause') { - dlog('πŸ” [PlayerPanel][VideoPlayer] Redux state debug', { - videoPlayState: this.props.videoPlayState, - isPaused: this.props.videoPlayState?.isPaused, - isPlaying: this.props.videoPlayState?.isPlaying, - currentTime: this.props.videoPlayState?.currentTime, - eventType: ev.type, - timestamp: new Date().toISOString(), - }); - } - const { currentTime, paused, playbackRate } = this.props.videoPlayState; - - // Redux μƒνƒœμ™€ ν˜„μž¬ λ‚΄λΆ€ μƒνƒœκ°€ 크게 λ‹€λ₯Ό 경우 λ‚΄λΆ€ μƒνƒœ μ—…λ°μ΄νŠΈ - const timeDiff = Math.abs(currentTime - this.state.currentTime); - const shouldUpdateTime = timeDiff > 0.5; // 0.5초 이상 차이 μ‹œ μ—…λ°μ΄νŠΈ - - // λΉˆλ²ˆν•œ μ΄λ²€νŠΈλŠ” λ‘œκ·Έμ—μ„œ μ œμ™Έ - const isFrequentEvent = [ - 'onProgress', - 'onBuffer', - 'onBufferEnd', - 'onReady', - 'onDuration', - 'onStart', - ].includes(ev.type); - const hasSignificantChange = - shouldUpdateTime || (paused !== this.state.paused && !isFrequentEvent); - - // μ€‘μš”ν•œ μƒνƒœ λ³€ν™”κ°€ 있고 λΉˆλ²ˆν•œ μ΄λ²€νŠΈκ°€ 아닐 λ•Œλ§Œ 둜그 - if (hasSignificantChange && !isFrequentEvent) { - dlog('πŸ”„ [PlayerPanel][VideoPlayer] Syncing internal state with Redux', { - timeDiff, - shouldUpdateTime, - pausedDiff: paused !== this.state.paused, - reduxPaused: paused, - internalPaused: this.state.paused, - eventType: ev.type, - timestamp: new Date().toISOString(), - }); - } - - if (hasSignificantChange) { - this.setState({ - currentTime: shouldUpdateTime ? currentTime : this.state.currentTime, - paused: paused !== undefined ? paused : this.state.paused, - playbackRate: playbackRate !== undefined ? playbackRate : this.state.playbackRate, - }); - } - } }; renderBottomControl = new Job(() => { @@ -1744,7 +1646,6 @@ const VideoPlayerBase = class extends React.Component { /** * Returns an object with the current state of the media including `currentTime`, `duration`, * `paused`, `playbackRate`, `proportionLoaded`, and `proportionPlayed`. - * Redux μƒνƒœμ™€ λ‚΄λΆ€ μƒνƒœλ₯Ό μš°μ„ μ μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ 일관성 보μž₯ * * @function * @memberof sandstone/VideoPlayer.VideoPlayerBase.prototype @@ -1752,19 +1653,13 @@ const VideoPlayerBase = class extends React.Component { * @public */ getMediaState = () => { - // Redux μƒνƒœλ₯Ό μš°μ„ μ μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ 일관성 보μž₯ - // Redux μƒνƒœκ°€ μ—†μœΌλ©΄ λ‚΄λΆ€ μƒνƒœ μ‚¬μš© (fallback) - const reduxState = this.props.videoPlayState; - return { - currentTime: reduxState?.currentTime ?? this.state.currentTime, - duration: reduxState?.duration ?? this.state.duration, - paused: reduxState?.isPaused ?? this.state.paused, - playbackRate: reduxState?.playbackRate ?? this.video?.playbackRate ?? this.state.playbackRate, + currentTime: this.state.currentTime, + duration: this.state.duration, + paused: this.state.paused, + playbackRate: this.video?.playbackRate, proportionLoaded: this.state.proportionLoaded, proportionPlayed: this.state.proportionPlayed, - // Redux μƒνƒœ 정보도 포함 - isPlaying: reduxState?.isPlaying ?? !this.state.paused, }; }; @@ -1793,16 +1688,7 @@ const VideoPlayerBase = class extends React.Component { * @public */ play = () => { - dlog('🟒 [PlayerPanel][VideoPlayer] play() called', { - currentTime: this.state.currentTime, - duration: this.state.duration, - paused: this.state.paused, - sourceUnavailable: this.state.sourceUnavailable, - prevCommand: this.prevCommand, - }); - if (this.state.sourceUnavailable) { - dwarn('⚠️ [PlayerPanel][VideoPlayer] play() aborted - source unavailable'); return; } @@ -1814,19 +1700,6 @@ const VideoPlayerBase = class extends React.Component { this.send('play'); this.announce($L('Play')); this.startDelayedMiniFeedbackHide(5000); - - // Redux μƒνƒœ μ—…λ°μ΄νŠΈ - μž¬μƒ μƒνƒœλ‘œ λ³€κ²½ - if (this.props.dispatch) { - this.props.dispatch( - updateVideoPlayState({ - isPlaying: true, - isPaused: false, - currentTime: this.state.currentTime, - duration: this.state.duration, - playbackRate: 1, - }) - ); - } }; /** @@ -1837,16 +1710,7 @@ const VideoPlayerBase = class extends React.Component { * @public */ pause = () => { - dlog('πŸ”΄ [VideoPlayer] pause() called', { - currentTime: this.state.currentTime, - duration: this.state.duration, - paused: this.state.paused, - sourceUnavailable: this.state.sourceUnavailable, - prevCommand: this.prevCommand, - }); - if (this.state.sourceUnavailable) { - dwarn('⚠️ [VideoPlayer] pause() aborted - source unavailable'); return; } @@ -1858,22 +1722,6 @@ const VideoPlayerBase = class extends React.Component { this.send('pause'); this.announce($L('Pause')); this.stopDelayedMiniFeedbackHide(); - - // Redux μƒνƒœ μ—…λ°μ΄νŠΈ - μΌμ‹œμ •μ§€ μƒνƒœλ‘œ λ³€κ²½ - if (this.props.dispatch) { - const pauseState = { - isPlaying: false, - isPaused: true, - currentTime: this.state.currentTime, - duration: this.state.duration, - playbackRate: 1, - }; - - dlog('πŸ“€ [VideoPlayer] Dispatching pause state', pauseState); - this.props.dispatch(updateVideoPlayState(pauseState)); - } else { - dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated'); - } }; /** @@ -1885,15 +1733,6 @@ const VideoPlayerBase = class extends React.Component { * @public */ seek = (timeIndex) => { - dlog('⏩ [VideoPlayer] seek() called', { - timeIndex, - currentTime: this.state.currentTime, - duration: this.state.duration, - videoDuration: this.video?.duration, - seekDisabled: this.props.seekDisabled, - sourceUnavailable: this.state.sourceUnavailable, - }); - if (this.video) { if ( !this.props.seekDisabled && @@ -1904,34 +1743,9 @@ const VideoPlayerBase = class extends React.Component { const actualSeekTime = timeIndex >= this.video.duration ? this.video.duration - 1 : timeIndex; this.video.currentTime = actualSeekTime; - - dlog('⏩ [VideoPlayer] Video seek completed', { - requestedTime: timeIndex, - actualTime: actualSeekTime, - videoDuration: this.video.duration, - }); - - // Redux μƒνƒœ μ—…λ°μ΄νŠΈ - μ‹œκ°„ 이동 μƒνƒœ 반영 - if (this.props.dispatch) { - const seekState = { - isPlaying: !this.state.paused, - isPaused: this.state.paused, - currentTime: actualSeekTime, - duration: this.state.duration, - playbackRate: this.state.playbackRate, - }; - - dlog('πŸ“€ [VideoPlayer] Dispatching seek state', seekState); - this.props.dispatch(updateVideoPlayState(seekState)); - } else { - dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated'); - } } else { - derror('❌ [VideoPlayer] seek failed - disabled or source unavailable'); forward('onSeekFailed', {}, this.props); } - } else { - derror('❌ [VideoPlayer] seek failed - no video element'); } };