1379 lines
41 KiB
JavaScript
1379 lines
41 KiB
JavaScript
import Spotlight from '@enact/spotlight';
|
||
|
||
import { URLS } from '../api/apiConfig';
|
||
import { TAxios } from '../api/TAxios';
|
||
import { panel_names } from '../utils/Config';
|
||
import { types } from './actionTypes';
|
||
import { popPanel, pushPanel, updatePanel } from './panelActions';
|
||
import { createDebugHelpers } from '../utils/debug';
|
||
|
||
// 디버그 헬퍼 설정
|
||
const DEBUG_MODE = false;
|
||
const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE);
|
||
|
||
// 🔽 [251116] 새로운 비디오 상태 관리 시스템 - 재생 상태
|
||
export const PLAYBACK_STATUS = {
|
||
LOADING: 'loading',
|
||
LOAD_SUCCESS: 'load_success',
|
||
LOAD_ERROR: 'load_error',
|
||
PLAYING: 'playing',
|
||
NOT_PLAYING: 'not_playing',
|
||
BUFFERING: 'buffering',
|
||
};
|
||
|
||
// 🔽 [251116] 새로운 비디오 상태 관리 시스템 - 화면 상태
|
||
export const DISPLAY_STATUS = {
|
||
HIDDEN: 'hidden',
|
||
VISIBLE: 'visible',
|
||
MINIMIZED: 'minimized',
|
||
FULLSCREEN: 'fullscreen',
|
||
};
|
||
|
||
//yhcho
|
||
/*
|
||
dispatch(startVideoPreview({
|
||
patnrId: randomData.patnrId,
|
||
showId: randomData.showId,
|
||
shptmBanrTpNm: randomData.shptmBanrTpNm,
|
||
lgCatCd: randomData.lgCatCd,
|
||
modal: true,
|
||
modalContainerRef: videoModalContainerRef.current, //to calc width, height, left, top
|
||
modalClassName:css.videoModal
|
||
}));
|
||
|
||
modalClassName: modal more class info and checking it's launched from preview mode
|
||
*/
|
||
let startVideoTimer = null;
|
||
//start modal mode
|
||
//start Full -> modal mode
|
||
let startVideoFocusTimer = null;
|
||
|
||
// 🔽 전역 타이머 정리 함수 - 메모리 누수 방지
|
||
export const clearAllVideoTimers = () => {
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
dlog('[playActions] startVideoFocusTimer cleared');
|
||
}
|
||
if (startVideoTimer) {
|
||
clearTimeout(startVideoTimer);
|
||
startVideoTimer = null;
|
||
dlog('[playActions] startVideoTimer cleared');
|
||
}
|
||
};
|
||
export const startVideoPlayer =
|
||
({
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
spotlightDisable,
|
||
useNewPlayer,
|
||
videoId,
|
||
showUrl,
|
||
...rest
|
||
}) =>
|
||
(dispatch, getState) => {
|
||
const caller = new Error().stack?.split('\n')[2]?.trim();
|
||
console.log('[PTRACE-SP] startVideoPlayer call', {
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
videoId,
|
||
showUrl,
|
||
caller,
|
||
});
|
||
|
||
dlog(
|
||
'[startVideoPlayer] ✅ START - videoId:',
|
||
videoId,
|
||
', showUrl:',
|
||
showUrl,
|
||
', modal:',
|
||
modal
|
||
);
|
||
|
||
// 🔽 [251116] 즉시 로딩 상태 설정
|
||
const videoIdentifier = videoId || showUrl;
|
||
if (videoIdentifier) {
|
||
const displayMode = modal ? DISPLAY_STATUS.VISIBLE : DISPLAY_STATUS.FULLSCREEN;
|
||
dlog(
|
||
'[startVideoPlayer] 📌 Setting playback loading - identifier:',
|
||
videoIdentifier,
|
||
', displayMode:',
|
||
displayMode
|
||
);
|
||
dispatch(setPlaybackLoading(videoIdentifier, displayMode));
|
||
} else {
|
||
dlog(
|
||
'[startVideoPlayer] ⚠️ No videoIdentifier provided (videoId and showUrl are both missing)'
|
||
);
|
||
}
|
||
|
||
const panels = getState().panels.panels;
|
||
const existingPlayerPanel = panels.find((p) => p.name === panel_names.PLAYER_PANEL);
|
||
let panelWorkingAction = pushPanel;
|
||
|
||
// 기존 PlayerPanel이 어디든 있으면 완전히 초기화: 타이머 정리 후 pop → 새로 push
|
||
if (existingPlayerPanel) {
|
||
console.log('[PTRACE-SP] startVideoPlayer: popping existing player before push', {
|
||
stack: panels.map((p) => p.name),
|
||
});
|
||
dlog('[startVideoPlayer] 🔄 Resetting existing PLAYER_PANEL before start');
|
||
clearAllVideoTimers();
|
||
dispatch(popPanel(panel_names.PLAYER_PANEL));
|
||
} else {
|
||
dlog(
|
||
'[startVideoPlayer] 📊 No existing PLAYER_PANEL - panelsCount:',
|
||
panels.length
|
||
);
|
||
}
|
||
|
||
dispatch(
|
||
panelWorkingAction(
|
||
{
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
videoId, // videoId 추가하여 PlayerPanel에서 사용 가능
|
||
showUrl, // showUrl 추가하여 PlayerPanel에서 사용 가능
|
||
...rest,
|
||
},
|
||
},
|
||
true
|
||
)
|
||
);
|
||
dlog('[startVideoPlayer] ✨ Panel action dispatched');
|
||
|
||
// [COMMENTED OUT] 비디오 재생 시 강제 포커스 이동 비활성화
|
||
// if (modal && modalContainerId && !spotlightDisable) {
|
||
// console.log('[startVideoPlayer] 🎯 Setting Spotlight focus - containerId:', modalContainerId);
|
||
// Spotlight.setPointerMode(false);
|
||
// startVideoFocusTimer = setTimeout(() => {
|
||
// console.log('[startVideoPlayer] 🔍 Spotlight.focus called');
|
||
// Spotlight.focus(modalContainerId);
|
||
// }, 0);
|
||
// } else {
|
||
// console.log('[startVideoPlayer] ⏭️ Spotlight focus skipped - modal:', modal, ', modalContainerId:', !!modalContainerId, ', spotlightDisable:', spotlightDisable);
|
||
// }
|
||
|
||
dlog('[startVideoPlayer] ✅ END');
|
||
};
|
||
|
||
// 중복 재생 방지: 정말 동일한 요청인지 확인
|
||
// 같은 배너 + 같은 modal 상태 + 같은 위치 = 정말 동일한 요청이므로 skip
|
||
const shouldSkipVideoPlayback = (
|
||
currentPanelInfo,
|
||
newModalState,
|
||
newModalContainerId,
|
||
newBannerId
|
||
) => {
|
||
if (!currentPanelInfo) return false;
|
||
|
||
const currentBannerId = currentPanelInfo.playerState?.currentBannerId;
|
||
const currentModal = currentPanelInfo.modal;
|
||
const currentModalContainerId = currentPanelInfo.modalContainerId;
|
||
|
||
return (
|
||
currentBannerId === newBannerId &&
|
||
currentModal === newModalState &&
|
||
currentModalContainerId === newModalContainerId
|
||
);
|
||
};
|
||
|
||
export const startVideoPlayerNew =
|
||
({
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
spotlightDisable,
|
||
useNewPlayer,
|
||
bannerId,
|
||
videoId,
|
||
showUrl,
|
||
...rest
|
||
}) =>
|
||
(dispatch, getState) => {
|
||
const caller = new Error().stack?.split('\n')[2]?.trim();
|
||
console.log('[PTRACE-SPN] startVideoPlayerNew call', {
|
||
bannerId,
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
videoId,
|
||
showUrl,
|
||
caller,
|
||
});
|
||
|
||
dlog(
|
||
'[startVideoPlayerNew] *** ✅ START - bannerId:',
|
||
bannerId,
|
||
', videoId:',
|
||
videoId,
|
||
', showUrl:',
|
||
showUrl,
|
||
', modal:',
|
||
modal
|
||
);
|
||
|
||
// 🔽 [251116] 즉시 로딩 상태 설정
|
||
const videoIdentifier = videoId || showUrl || bannerId;
|
||
if (videoIdentifier) {
|
||
const displayMode = modal ? DISPLAY_STATUS.VISIBLE : DISPLAY_STATUS.FULLSCREEN;
|
||
dlog(
|
||
'[startVideoPlayerNew] *** 📌 Setting playback loading - identifier:',
|
||
videoIdentifier,
|
||
', displayMode:',
|
||
displayMode
|
||
);
|
||
dispatch(setPlaybackLoading(videoIdentifier, displayMode));
|
||
} else {
|
||
dlog('[startVideoPlayerNew] *** ⚠️ No videoIdentifier provided');
|
||
}
|
||
|
||
const panels = getState().panels.panels;
|
||
const existingPlayerPanel = panels.find((p) => p.name === panel_names.PLAYER_PANEL);
|
||
let panelWorkingAction = pushPanel;
|
||
let shouldCheckDuplicate = true;
|
||
|
||
// 기존 PlayerPanel이 있으면 완전히 초기화: 타이머 정리 후 pop → 새로 push
|
||
if (existingPlayerPanel) {
|
||
console.log('[PTRACE-SPN] popping existing player before push', {
|
||
stack: panels.map((p) => p.name),
|
||
});
|
||
dlog('[startVideoPlayerNew] *** 🔄 Resetting existing PLAYER_PANEL before start');
|
||
clearAllVideoTimers();
|
||
dispatch(popPanel(panel_names.PLAYER_PANEL));
|
||
shouldCheckDuplicate = false;
|
||
}
|
||
|
||
const topPanel = panels[panels.length - 1];
|
||
dlog(
|
||
'[startVideoPlayerNew] *** 📊 Panel state - panelsCount:',
|
||
panels.length,
|
||
', topPanelName:',
|
||
topPanel?.name
|
||
);
|
||
|
||
let currentPanelInfo = topPanel?.panelInfo || {};
|
||
let currentPlayerState = currentPanelInfo.playerState || {};
|
||
|
||
if (!existingPlayerPanel && topPanel && topPanel.name === panel_names.PLAYER_PANEL) {
|
||
panelWorkingAction = updatePanel;
|
||
dlog('[startVideoPlayerNew] *** 📋 Current PLAYER_PANEL panelInfo:', topPanel.panelInfo);
|
||
}
|
||
|
||
// 중복 실행 방지: 같은 배너 + 같은 modal 상태/컨테이너 + 같은 URL이면 skip
|
||
if (shouldCheckDuplicate) {
|
||
const isSameBanner = currentPlayerState.currentBannerId === bannerId;
|
||
const isSameModalType = currentPanelInfo.modal === modal;
|
||
const isSameContainer = currentPanelInfo.modalContainerId === modalContainerId;
|
||
const isSameShowUrl = currentPanelInfo.showUrl === showUrl;
|
||
const isSameVideoId = currentPanelInfo.videoId === videoId;
|
||
|
||
dlog(
|
||
'[startVideoPlayerNew] *** 🔍 Duplicate check - isSameBanner:',
|
||
isSameBanner,
|
||
', isSameModalType:',
|
||
isSameModalType,
|
||
', isSameContainer:',
|
||
isSameContainer,
|
||
', isSameShowUrl:',
|
||
isSameShowUrl,
|
||
', isSameVideoId:',
|
||
isSameVideoId
|
||
);
|
||
|
||
if (isSameBanner && isSameModalType && isSameContainer && isSameShowUrl && isSameVideoId) {
|
||
dlog('[startVideoPlayerNew] *** ⏭️ SKIPPED - 동일한 요청', {
|
||
bannerId,
|
||
modal,
|
||
modalContainerId,
|
||
showUrl,
|
||
videoId,
|
||
});
|
||
return;
|
||
}
|
||
} else {
|
||
// pop으로 초기화한 경우 중복 체크 스킵
|
||
currentPanelInfo = {};
|
||
currentPlayerState = {};
|
||
}
|
||
|
||
const newPlayerState = {
|
||
...currentPlayerState,
|
||
currentBannerId: bannerId,
|
||
};
|
||
dlog('[startVideoPlayerNew] *** 🔄 Player state updated - currentBannerId:', bannerId);
|
||
|
||
dispatch(
|
||
panelWorkingAction(
|
||
{
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
playerState: newPlayerState,
|
||
videoId, // videoId 추가
|
||
showUrl, // showUrl 추가
|
||
bannerId, // bannerId 추가
|
||
...rest,
|
||
},
|
||
},
|
||
true
|
||
)
|
||
);
|
||
dlog(
|
||
'[startVideoPlayerNew] *** ✨ Panel action dispatched - action:',
|
||
panelWorkingAction === updatePanel ? 'updatePanel' : 'pushPanel'
|
||
);
|
||
|
||
// [COMMENTED OUT] 비디오 재생 시 강제 포커스 이동 비활성화
|
||
// if (modal && modalContainerId && !spotlightDisable) {
|
||
// console.log('[startVideoPlayerNew] *** 🎯 Setting Spotlight focus - containerId:', modalContainerId);
|
||
// Spotlight.setPointerMode(false);
|
||
// startVideoFocusTimer = setTimeout(() => {
|
||
// console.log('[startVideoPlayerNew] *** 🔍 Spotlight.focus called');
|
||
// Spotlight.focus(modalContainerId);
|
||
// }, 0);
|
||
// } else {
|
||
// console.log('[startVideoPlayerNew] *** ⏭️ Spotlight focus skipped - modal:', modal, ', modalContainerId:', !!modalContainerId, ', spotlightDisable:', spotlightDisable);
|
||
// }
|
||
|
||
dlog('[startVideoPlayerNew] *** ✅ END');
|
||
};
|
||
|
||
export const finishVideoPreview = () => (dispatch, getState) => {
|
||
if (DEBUG_MODE === true) {
|
||
dlog('###-finishVideoPreview');
|
||
}
|
||
const panels = getState().panels.panels;
|
||
const topPanel = panels[panels.length - 1];
|
||
if (topPanel && topPanel.name === panel_names.PLAYER_PANEL && topPanel.panelInfo.modal) {
|
||
console.log('[PANEL-TRACE] finishVideoPreview: popping modal player', {
|
||
topPanelName: topPanel.name,
|
||
modal: topPanel.panelInfo.modal,
|
||
stack: panels.map((p) => p.name),
|
||
panelInfo: topPanel.panelInfo,
|
||
});
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
dispatch(popPanel());
|
||
}
|
||
};
|
||
|
||
export const finishModalVideoForce = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
if (DEBUG_MODE === true) {
|
||
dlog('###-finishModalVideoForce');
|
||
}
|
||
// modal PlayerPanel이 존재하는지 확인 (스택 어디에 있든)
|
||
const hasModalPlayerPanel = panels.some(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
|
||
);
|
||
|
||
if (hasModalPlayerPanel) {
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
// panelName을 지정하면 스택 어디에 있든 해당 패널을 제거
|
||
dispatch(popPanel(panel_names.PLAYER_PANEL));
|
||
}
|
||
};
|
||
|
||
// 모든 PlayerPanel을 강제 제거 (modal과 fullscreen 모두)
|
||
export const finishAllVideoForce = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
if (DEBUG_MODE === true) {
|
||
dlog('###-finishAllVideoForce');
|
||
}
|
||
// 모든 PlayerPanel이 존재하는지 확인 (스택 어디에 있든)
|
||
const hasPlayerPanel = panels.some((panel) => panel.name === panel_names.PLAYER_PANEL);
|
||
|
||
if (hasPlayerPanel) {
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
// panelName을 지정하면 스택 어디에 있든 해당 패널을 제거
|
||
dispatch(popPanel(panel_names.PLAYER_PANEL));
|
||
}
|
||
};
|
||
|
||
// 모달 비디오를 일시정지 (패널은 유지)
|
||
export const pauseModalVideo = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
if (DEBUG_MODE === true) {
|
||
dlog('###-pauseModalVideo');
|
||
}
|
||
|
||
// modal PlayerPanel 찾기
|
||
const modalPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
|
||
);
|
||
|
||
console.log('[Detail-BG] ⏸️ pauseModalVideo - Pausing modal video', {
|
||
found: !!modalPlayerPanel,
|
||
playerPanelModal: modalPlayerPanel?.panelInfo?.modal,
|
||
currentIsPaused: modalPlayerPanel?.panelInfo?.isPaused,
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
if (modalPlayerPanel) {
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[pauseModalVideo] Pausing modal video');
|
||
}
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...modalPlayerPanel.panelInfo,
|
||
isPaused: true, // 일시정지 플래그 추가
|
||
},
|
||
})
|
||
);
|
||
|
||
console.log('[Detail-BG] ✅ pauseModalVideo - Modal video paused successfully', {
|
||
timestamp: Date.now(),
|
||
});
|
||
} else {
|
||
console.log('[Detail-BG] ⚠️ pauseModalVideo - No modal PlayerPanel found', {
|
||
timestamp: Date.now(),
|
||
});
|
||
}
|
||
};
|
||
|
||
// 모달 비디오를 재생 (일시정지 해제)
|
||
export const resumeModalVideo = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// modal PlayerPanel 찾기
|
||
const modalPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
|
||
);
|
||
|
||
console.log('[Detail-BG] ▶️ resumeModalVideo - Resuming modal video', {
|
||
found: !!modalPlayerPanel,
|
||
playerPanelModal: modalPlayerPanel?.panelInfo?.modal,
|
||
currentIsPaused: modalPlayerPanel?.panelInfo?.isPaused,
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
if (modalPlayerPanel && modalPlayerPanel.panelInfo?.isPaused) {
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[resumeModalVideo] Resuming modal video');
|
||
}
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...modalPlayerPanel.panelInfo,
|
||
isPaused: false, // 일시정지 해제
|
||
},
|
||
})
|
||
);
|
||
|
||
console.log('[Detail-BG] ✅ resumeModalVideo - Modal video resumed successfully', {
|
||
timestamp: Date.now(),
|
||
});
|
||
} else {
|
||
console.log('[Detail-BG] ⚠️ resumeModalVideo - Modal video not paused or panel not found', {
|
||
found: !!modalPlayerPanel,
|
||
isPaused: modalPlayerPanel?.panelInfo?.isPaused,
|
||
timestamp: Date.now(),
|
||
});
|
||
}
|
||
};
|
||
|
||
// 전체화면 비디오를 일시정지 (패널은 유지)
|
||
export const pauseFullscreenVideo = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// 전체화면 PlayerPanel 찾기 (modal이 false인 패널)
|
||
const fullscreenPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
|
||
);
|
||
|
||
console.log('[Detail-BG] ⏸️ pauseFullscreenVideo - Pausing fullscreen video', {
|
||
found: !!fullscreenPlayerPanel,
|
||
playerPanelModal: fullscreenPlayerPanel?.panelInfo?.modal,
|
||
currentIsPaused: fullscreenPlayerPanel?.panelInfo?.isPaused,
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
if (fullscreenPlayerPanel) {
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...fullscreenPlayerPanel.panelInfo,
|
||
isPaused: true, // 일시정지 플래그 추가
|
||
},
|
||
})
|
||
);
|
||
|
||
console.log('[Detail-BG] ✅ pauseFullscreenVideo - Fullscreen video paused successfully', {
|
||
timestamp: Date.now(),
|
||
});
|
||
} else {
|
||
console.log('[Detail-BG] ⚠️ pauseFullscreenVideo - No fullscreen PlayerPanel found', {
|
||
timestamp: Date.now(),
|
||
});
|
||
}
|
||
};
|
||
|
||
// 전체화면 비디오를 재생 (일시정지 해제)
|
||
export const resumeFullscreenVideo = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// 전체화면 PlayerPanel 찾기 (modal이 false인 패널)
|
||
const fullscreenPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
|
||
);
|
||
|
||
console.log('[Detail-BG] ▶️ resumeFullscreenVideo - Resuming fullscreen video', {
|
||
found: !!fullscreenPlayerPanel,
|
||
playerPanelModal: fullscreenPlayerPanel?.panelInfo?.modal,
|
||
currentIsPaused: fullscreenPlayerPanel?.panelInfo?.isPaused,
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
if (fullscreenPlayerPanel && fullscreenPlayerPanel.panelInfo?.isPaused) {
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...fullscreenPlayerPanel.panelInfo,
|
||
isPaused: false, // 일시정지 해제
|
||
},
|
||
})
|
||
);
|
||
|
||
console.log('[Detail-BG] ✅ resumeFullscreenVideo - Fullscreen video resumed successfully', {
|
||
timestamp: Date.now(),
|
||
});
|
||
} else {
|
||
console.log('[Detail-BG] ⚠️ resumeFullscreenVideo - Fullscreen video not paused or panel not found', {
|
||
found: !!fullscreenPlayerPanel,
|
||
isPaused: fullscreenPlayerPanel?.panelInfo?.isPaused,
|
||
timestamp: Date.now(),
|
||
});
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[BgVideo] resumeFullscreenVideo - Not resuming (not found or not paused)');
|
||
}
|
||
}
|
||
};
|
||
|
||
// 모달 비디오를 1px로 축소 (배너 정보 저장)
|
||
export const hideModalVideo = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// modal PlayerPanel 찾기
|
||
const modalPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
|
||
);
|
||
|
||
if (modalPlayerPanel) {
|
||
const panelInfo = modalPlayerPanel.panelInfo;
|
||
|
||
// 축소 전 배너 정보를 playerState에 저장
|
||
const updatedPlayerState = {
|
||
...(panelInfo.playerState || {}),
|
||
shrinkInfo: {
|
||
// 복구 시 필요한 정보
|
||
modalContainerId: panelInfo.modalContainerId,
|
||
modalClassName: panelInfo.modalClassName,
|
||
modalStyle: panelInfo.modalStyle,
|
||
modalScale: panelInfo.modalScale,
|
||
// top, left는 따로 저장 (복구 시 재계산하지 않기 위함)
|
||
top: panelInfo.modalStyle?.top,
|
||
left: panelInfo.modalStyle?.left,
|
||
currentBannerId: panelInfo.playerState?.currentBannerId,
|
||
patnrId: panelInfo.patnrId,
|
||
showId: panelInfo.showId,
|
||
shptmBanrTpNm: panelInfo.shptmBanrTpNm,
|
||
lgCatCd: panelInfo.lgCatCd,
|
||
},
|
||
};
|
||
|
||
// console.log('[HomePanel] hideModalVideo: saving shrinkInfo', {
|
||
// shrinkInfo: updatedPlayerState.shrinkInfo,
|
||
// modalStyle: panelInfo.modalStyle,
|
||
// });
|
||
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...panelInfo,
|
||
shouldShrinkTo1px: true, // 축소 플래그 설정
|
||
playerState: updatedPlayerState,
|
||
},
|
||
})
|
||
);
|
||
} else {
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[HomePanel] hideModalVideo: No modal PlayerPanel found', {
|
||
panels: panels.map((p) => ({
|
||
name: p.name,
|
||
modal: p.panelInfo?.modal,
|
||
shouldShrinkTo1px: p.panelInfo?.shouldShrinkTo1px,
|
||
})),
|
||
});
|
||
}
|
||
}
|
||
};
|
||
|
||
// 축소된 모달 비디오를 원래 크기로 복구
|
||
export const showModalVideo = () => (dispatch, getState) => {
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[showModalVideo] *** ✅ START');
|
||
}
|
||
const panels = getState().panels.panels;
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[showModalVideo] *** 📊 Total panels count:', panels.length);
|
||
}
|
||
|
||
// 축소된 modal PlayerPanel 찾기
|
||
const shrunkModalPlayerPanel = panels.find(
|
||
(panel) =>
|
||
panel.name === panel_names.PLAYER_PANEL &&
|
||
panel.panelInfo?.modal &&
|
||
panel.panelInfo?.shouldShrinkTo1px
|
||
);
|
||
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[showModalVideo] *** 🔍 Shrunk modal PlayerPanel found:', !!shrunkModalPlayerPanel);
|
||
}
|
||
|
||
if (shrunkModalPlayerPanel) {
|
||
const panelInfo = shrunkModalPlayerPanel.panelInfo;
|
||
const shrinkInfo = panelInfo.playerState?.shrinkInfo;
|
||
|
||
if (DEBUG_MODE === true) {
|
||
dlog('[showModalVideo] *** 📋 ShrinkInfo available:', !!shrinkInfo);
|
||
}
|
||
dlog('[showModalVideo] *** 📋 Current panelInfo state:', {
|
||
shouldShrinkTo1px: panelInfo.shouldShrinkTo1px,
|
||
modal: panelInfo.modal,
|
||
modalContainerId: panelInfo.modalContainerId,
|
||
hasModalStyle: !!panelInfo.modalStyle,
|
||
});
|
||
|
||
const updatedPanelInfo = {
|
||
...panelInfo,
|
||
shouldShrinkTo1px: false, // 축소 플래그 해제
|
||
// 저장된 정보로 복구 (하지만 DOM 재계산은 허용)
|
||
...(shrinkInfo && {
|
||
modalContainerId: shrinkInfo.modalContainerId,
|
||
modalClassName: shrinkInfo.modalClassName,
|
||
modalStyle: shrinkInfo.modalStyle,
|
||
modalScale: shrinkInfo.modalScale,
|
||
}),
|
||
skipModalStyleRecalculation: false, // 위치 변경 시 DOM 기준으로 다시 계산하도록 허용
|
||
};
|
||
|
||
dlog(
|
||
'[showModalVideo] *** 🔄 Updated panelInfo - shouldShrinkTo1px:',
|
||
updatedPanelInfo.shouldShrinkTo1px
|
||
);
|
||
dlog('[showModalVideo] *** 📍 Restored modalStyle:', updatedPanelInfo.modalStyle);
|
||
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: updatedPanelInfo,
|
||
})
|
||
);
|
||
dlog('[showModalVideo] *** ✨ updatePanel dispatched');
|
||
} else {
|
||
dlog('[showModalVideo] *** ⚠️ No shrunk modal PlayerPanel found', {
|
||
panels: panels.map((p) => ({
|
||
name: p.name,
|
||
modal: p.panelInfo?.modal,
|
||
shouldShrinkTo1px: p.panelInfo?.shouldShrinkTo1px,
|
||
})),
|
||
});
|
||
}
|
||
|
||
dlog('[showModalVideo] *** ✅ END');
|
||
};
|
||
|
||
// 🔽 패널은 유지하고 비디오만 중지하는 함수들
|
||
|
||
/**
|
||
* 패널을 닫지 않고(popPanel 하지 않고) 비디오만 중지합니다.
|
||
* 모달 비디오의 재생을 중지하고 숨김 상태로 만듭니다.
|
||
*/
|
||
export const stopModalVideoWithoutClosingPanel = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// modal PlayerPanel 찾기
|
||
const modalPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
|
||
);
|
||
|
||
if (modalPlayerPanel) {
|
||
dlog('[stopModalVideoWithoutClosingPanel] Stopping modal video playback');
|
||
|
||
// 타이머 정리
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
|
||
// 패널은 유지하되, 비디오 중지 상태로 업데이트
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...modalPlayerPanel.panelInfo,
|
||
shouldStop: true, // 비디오 중지 플래그
|
||
isPaused: true, // 일시정지 상태
|
||
isHidden: true, // 화면에서 숨김
|
||
},
|
||
})
|
||
);
|
||
|
||
// Redux 상태도 중지로 업데이트
|
||
dispatch(setVideoStopped());
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 패널을 닫지 않고 전체화면 비디오만 중지합니다.
|
||
*/
|
||
export const stopFullscreenVideoWithoutClosingPanel = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// 전체화면 PlayerPanel 찾기
|
||
const fullscreenPlayerPanel = panels.find(
|
||
(panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
|
||
);
|
||
|
||
if (fullscreenPlayerPanel) {
|
||
dlog('[stopFullscreenVideoWithoutClosingPanel] Stopping fullscreen video playback');
|
||
|
||
// 타이머 정리
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
|
||
// 패널은 유지하되, 비디오 중지 상태로 업데이트
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...fullscreenPlayerPanel.panelInfo,
|
||
shouldStop: true, // 비디오 중지 플래그
|
||
isPaused: true,
|
||
isHidden: true,
|
||
},
|
||
})
|
||
);
|
||
|
||
// Redux 상태도 중지로 업데이트
|
||
dispatch(setVideoStopped());
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 모든 비디오(모달+전체화면)를 패널 닫지 않고 중지합니다.
|
||
*/
|
||
export const stopAllVideosWithoutClosingPanel = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// 모든 PlayerPanel 찾기
|
||
const playerPanels = panels.filter((panel) => panel.name === panel_names.PLAYER_PANEL);
|
||
|
||
if (playerPanels.length > 0) {
|
||
dlog('[stopAllVideosWithoutClosingPanel] Stopping all video playback');
|
||
|
||
// 타이머 정리
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
|
||
// 모든 PlayerPanel을 중지 상태로 업데이트
|
||
playerPanels.forEach((playerPanel) => {
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...playerPanel.panelInfo,
|
||
shouldStop: true,
|
||
isPaused: true,
|
||
isHidden: true,
|
||
},
|
||
})
|
||
);
|
||
});
|
||
|
||
// Redux 상태도 중지로 업데이트
|
||
dispatch(setVideoStopped());
|
||
}
|
||
};
|
||
|
||
// 채팅 로그 가져오기 IF-LGSP-371
|
||
export const getChatLog =
|
||
({ patnrId, showId }) =>
|
||
(dispatch, getState) => {
|
||
const onSuccess = (response) => {
|
||
dlog('getChatLog onSuccess', response.data);
|
||
|
||
dispatch({
|
||
type: types.GET_CHAT_LOG,
|
||
payload: response.data.data,
|
||
});
|
||
};
|
||
|
||
const onFail = (error) => {
|
||
derror('getChatLog onFail', error);
|
||
};
|
||
|
||
TAxios(dispatch, getState, 'get', URLS.CHAT_LOG, { patnrId, showId }, {}, onSuccess, onFail);
|
||
};
|
||
|
||
// VOD 자막 가져오기 IF-LGSP-072
|
||
export const getSubTitle =
|
||
({ showSubtitleUrl }) =>
|
||
(dispatch, getState) => {
|
||
const onSuccess = (response) => {
|
||
dlog('getSubTitle onSuccess', response.data);
|
||
|
||
dispatch({
|
||
type: types.GET_SUBTITLE,
|
||
payload: { url: showSubtitleUrl, data: response.data.data },
|
||
});
|
||
};
|
||
|
||
const onFail = (error) => {
|
||
derror('getSubTitle onFail', error);
|
||
dispatch({
|
||
type: types.GET_SUBTITLE,
|
||
payload: { url: showSubtitleUrl, data: 'Error' },
|
||
});
|
||
};
|
||
|
||
if (!getState().play.subTitleBlobs[showSubtitleUrl]) {
|
||
TAxios(dispatch, getState, 'get', URLS.SUBTITLE, { showSubtitleUrl }, {}, onSuccess, onFail);
|
||
} else {
|
||
dlog("playActions getSubTitle no Nothing it's exist", showSubtitleUrl);
|
||
}
|
||
};
|
||
|
||
export const CLEAR_PLAYER_INFO = () => ({
|
||
type: types.CLEAR_PLAYER_INFO,
|
||
});
|
||
|
||
// 특정 자막 Blob URL을 해제하는 액션 생성자
|
||
export const clearSubtitleBlob = (subtitleUrl) => (dispatch, getState) => {
|
||
const currentBlobs = getState().play.subTitleBlobs;
|
||
const blobUrl = currentBlobs[subtitleUrl];
|
||
|
||
// Blob URL 해제
|
||
if (blobUrl && blobUrl.startsWith('blob:')) {
|
||
try {
|
||
URL.revokeObjectURL(blobUrl);
|
||
dlog('[clearSubtitleBlob] Revoked Blob URL:', subtitleUrl);
|
||
} catch (error) {
|
||
derror('[clearSubtitleBlob] Failed to revoke Blob URL:', error);
|
||
}
|
||
}
|
||
|
||
// Redux 상태에서 제거
|
||
dispatch({
|
||
type: types.CLEAR_SUBTITLE_BLOB,
|
||
payload: { subtitleUrl }
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 비디오 재생 상태를 Redux에 업데이트합니다.
|
||
* @param {Object} playState - 업데이트할 재생 상태
|
||
* @param {boolean} playState.isPlaying - 재생 중인지 여부
|
||
* @param {boolean} playState.isPaused - 일시정지 상태인지 여부
|
||
* @param {number} playState.currentTime - 현재 재생 시간(초)
|
||
* @param {number} playState.duration - 전체 비디오 길이(초)
|
||
* @param {number} playState.playbackRate - 재생 속도
|
||
*/
|
||
export const updateVideoPlayState = (playState) => (dispatch, getState) => {
|
||
const currentState = getState().play.videoPlayState;
|
||
|
||
// 상태 변화 감지
|
||
const hasChanges = Object.keys(playState).some((key) => {
|
||
return currentState[key] !== playState[key];
|
||
});
|
||
|
||
if (hasChanges) {
|
||
dlog('🔄 [PlayerPanel] updateVideoPlayState action created', {
|
||
...playState,
|
||
timestamp: new Date().toISOString(),
|
||
caller: new Error().stack?.split('\n')[2]?.trim() || 'unknown',
|
||
});
|
||
}
|
||
|
||
dispatch({
|
||
type: types.UPDATE_VIDEO_PLAY_STATE,
|
||
payload: playState,
|
||
});
|
||
};
|
||
|
||
/* 🔽 [추가] 새로운 '플레이 제어 매니저' 액션들 */
|
||
|
||
/**
|
||
* 비디오 재생 제어권을 요청합니다.
|
||
* 컴포넌트는 이 액션을 통해 중앙 매니저에게 재생을 '요청'합니다.
|
||
* @param {string} ownerId - 제어권을 요청하는 컴포넌트의 고유 ID (예: 'banner0_persistent')
|
||
* @param {object} videoInfo - 재생할 비디오 정보 (url, id 등)
|
||
*/
|
||
export const requestPlayControl = (ownerId, videoInfo) => (dispatch, getState) => {
|
||
const { playerControl } = getState().home;
|
||
const currentOwnerId = playerControl.ownerId;
|
||
|
||
if (currentOwnerId === ownerId) return; // 이미 제어권 소유
|
||
|
||
if (currentOwnerId) {
|
||
// 현재 제어중인 컴포넌트가 영구재생 배너이면 '일시정지'
|
||
if (currentOwnerId === 'banner0_persistent') {
|
||
dispatch(pausePlayerControl());
|
||
} else {
|
||
// 다른 미리보기라면 완전히 숨김
|
||
dispatch(releasePlayControl(currentOwnerId, true));
|
||
}
|
||
}
|
||
|
||
// 1. 매니저 상태 업데이트
|
||
dispatch({ type: types.SET_PLAYER_CONTROL, payload: { ownerId } });
|
||
|
||
// 2. 공유 PlayerPanel의 상태 업데이트
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
isHidden: false,
|
||
modal: true,
|
||
...videoInfo,
|
||
},
|
||
})
|
||
);
|
||
};
|
||
|
||
/**
|
||
* 비디오 재생 제어권을 해제하고, 필요시 영구재생 비디오를 복원합니다.
|
||
* @param {string} ownerId - 제어권을 해제하는 컴포넌트의 고유 ID
|
||
* @param {boolean} fromPreemption - 다른 요청에 의해 강제로 중단되었는지 여부
|
||
*/
|
||
export const releasePlayControl =
|
||
(ownerId, fromPreemption = false) =>
|
||
(dispatch, getState) => {
|
||
const { playerControl } = getState().home;
|
||
|
||
if (fromPreemption || playerControl.ownerId === ownerId) {
|
||
// 1. 공유 PlayerPanel을 다시 숨김
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
isHidden: true,
|
||
},
|
||
})
|
||
);
|
||
|
||
// 2. 매니저 상태 업데이트 (현재 소유주 없음)
|
||
dispatch({ type: types.CLEAR_PLAYER_CONTROL });
|
||
|
||
// 3. 만약 '일시정지'된 영구재생 비디오가 있었다면, 제어권을 되돌려주고 다시 재생
|
||
if (playerControl.isPaused && playerControl.ownerId === 'banner0_persistent') {
|
||
const persistentVideoInfo = {
|
||
/* 영구 비디오 정보를 가져오는 로직 (필요시) */
|
||
};
|
||
dispatch(requestPlayControl('banner0_persistent', persistentVideoInfo));
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 현재 재생 중인 비디오를 '일시정지' 상태로 변경하는 액션.
|
||
* 이 함수는 플레이어 패널을 닫지 않고, 단순히 비디오 재생을 멈추는 신호를 보냅니다.
|
||
*
|
||
* @param {string} ownerId - 비디오 제어권을 가진 컴포넌트의 고유 ID.
|
||
*/
|
||
// export const pausePlayerControl = (ownerId) => (dispatch, getState) => {
|
||
// const { playerControl } = getState().home;
|
||
|
||
// // 제어권을 가진 컴포넌트가 자신일 경우에만 일시정지
|
||
// if (playerControl.ownerId === ownerId) {
|
||
// dispatch({
|
||
// type: types.PAUSE_PLAYER_CONTROL,
|
||
// });
|
||
// }
|
||
// };
|
||
|
||
/**
|
||
* '일시정지' 상태의 비디오를 다시 재생하는 액션.
|
||
*
|
||
* @param {string} ownerId - 비디오 제어권을 가진 컴포넌트의 고유 ID.
|
||
*/
|
||
export const resumePlayerControl = (ownerId) => (dispatch, getState) => {
|
||
const { playerControl } = getState().home;
|
||
|
||
// 제어권을 가진 컴포넌트가 자신이고, 일시정지 상태일 때만 재개
|
||
if (playerControl.ownerId === ownerId && playerControl.isPaused) {
|
||
dispatch({
|
||
type: types.RESUME_PLAYER_CONTROL,
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 공유 PlayerPanel을 전체화면 모드로 전환합니다.
|
||
* 이 액션은 어떤 배너에서든 클릭 시 호출됩니다.
|
||
*/
|
||
export const goToFullScreen = () => (dispatch, getState) => {
|
||
console.log('[Detail-BG] 🎬 goToFullScreen - Setting PlayerPanel to fullscreen mode', {
|
||
targetModal: false,
|
||
action: 'updatePanel',
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
// 공유 PlayerPanel의 'modal' 상태를 false로 변경하여 전체화면으로 전환
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
modal: false,
|
||
isHidden: false, // 혹시 숨겨져 있었다면 보이도록
|
||
},
|
||
})
|
||
);
|
||
|
||
console.log('[Detail-BG] ✅ goToFullScreen - PlayerPanel modal set to false (fullscreen)', {
|
||
timestamp: Date.now(),
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 영구재생 비디오를 일시정지 상태로 만듭니다. (내부 사용)
|
||
*/
|
||
export const pausePlayerControl = () => ({
|
||
type: types.PAUSE_PLAYER_CONTROL,
|
||
});
|
||
|
||
/**
|
||
* 전체화면 플레이어에서 미리보기 상태로 복귀할 때 호출됩니다.
|
||
* 중앙 'playerControl' 상태를 확인하여 올바른 위치와 비디오로 복원합니다.
|
||
*/
|
||
export const returnToPreview = () => (dispatch, getState) => {
|
||
const { playerControl } = getState().home;
|
||
|
||
let targetOwnerId;
|
||
let targetVideoInfo;
|
||
|
||
// 만약 '일시정지'된 영구재생 비디오가 있다면, 무조건 그 비디오로 복귀하는 것이 최우선
|
||
if (playerControl.isPaused) {
|
||
targetOwnerId = 'banner0_persistent';
|
||
// targetVideoInfo = ... (0번 배너의 비디오 정보를 가져오는 로직)
|
||
} else {
|
||
// 그렇지 않다면, 전체화면으로 가기 직전의 소유주(ownerId)에게로 복귀
|
||
targetOwnerId = playerControl.ownerId;
|
||
// targetVideoInfo = ... (해당 ownerId의 비디오 정보를 가져오는 로직)
|
||
}
|
||
|
||
// 매니저에게 해당 타겟으로 재생을 다시 요청
|
||
if (targetOwnerId) {
|
||
dispatch(requestPlayControl(targetOwnerId, targetVideoInfo));
|
||
} else {
|
||
// 돌아갈 곳이 없으면 그냥 플레이어를 닫음
|
||
dispatch(finishVideoPreview());
|
||
}
|
||
};
|
||
|
||
/* 🔽 [251116] 새로운 비디오 상태 관리 시스템 - 액션 함수들 */
|
||
|
||
/**
|
||
* 비디오 로딩 시작 상태로 설정
|
||
* @param {string} videoId - 비디오 ID
|
||
* @param {string} displayMode - 화면 모드 ('visible', 'fullscreen', 'minimized')
|
||
*/
|
||
export const setPlaybackLoading = (videoId, displayMode = DISPLAY_STATUS.VISIBLE) => ({
|
||
type: types.SET_VIDEO_LOADING,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.LOADING,
|
||
display: displayMode,
|
||
videoId,
|
||
loadingProgress: 0,
|
||
loadingError: null,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 비디오 로딩 성공 상태로 설정
|
||
* @param {string} videoId - 비디오 ID
|
||
* @param {string} displayMode - 화면 모드
|
||
*/
|
||
export const setPlaybackSuccess = (videoId, displayMode = DISPLAY_STATUS.VISIBLE) => ({
|
||
type: types.SET_PLAYBACK_SUCCESS,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.LOAD_SUCCESS,
|
||
display: displayMode,
|
||
videoId,
|
||
loadingProgress: 100,
|
||
loadingError: null,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 비디오 로딩 에러 상태로 설정
|
||
* @param {string} videoId - 비디오 ID
|
||
* @param {object} error - 에러 정보
|
||
*/
|
||
export const setPlaybackError = (videoId, error) => ({
|
||
type: types.SET_VIDEO_ERROR,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.LOAD_ERROR,
|
||
display: DISPLAY_STATUS.VISIBLE,
|
||
videoId,
|
||
loadingProgress: 0,
|
||
loadingError: error,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 비디오 재생 상태로 설정
|
||
* @param {string} videoId - 비디오 ID
|
||
* @param {string} displayMode - 화면 모드
|
||
*/
|
||
export const setPlaybackPlaying = (videoId, displayMode = DISPLAY_STATUS.FULLSCREEN) => ({
|
||
type: types.SET_VIDEO_PLAYING,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.PLAYING,
|
||
display: displayMode,
|
||
videoId,
|
||
loadingProgress: 100,
|
||
loadingError: null,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 비디오 정지 상태로 설정
|
||
*/
|
||
export const setVideoStopped = () => ({
|
||
type: types.SET_VIDEO_STOPPED,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.NOT_PLAYING,
|
||
display: DISPLAY_STATUS.HIDDEN,
|
||
videoId: null,
|
||
loadingProgress: 0,
|
||
loadingError: null,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 비디오 버퍼링 상태로 설정
|
||
* @param {string} videoId - 비디오 ID
|
||
*/
|
||
export const setPlaybackBuffering = (videoId) => ({
|
||
type: types.SET_PLAYBACK_BUFFERING,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.BUFFERING,
|
||
videoId,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 최소화된 상태로 비디오 재생
|
||
* @param {string} videoId - 비디오 ID
|
||
*/
|
||
export const setVideoMinimizedPlaying = (videoId) => ({
|
||
type: types.SET_VIDEO_MINIMIZED_PLAYING,
|
||
payload: {
|
||
playback: PLAYBACK_STATUS.PLAYING,
|
||
display: DISPLAY_STATUS.MINIMIZED,
|
||
videoId,
|
||
loadingProgress: 100,
|
||
loadingError: null,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 화면 상태만 변경하는 액션들
|
||
*/
|
||
export const setDisplayHidden = () => ({
|
||
type: types.SET_DISPLAY_HIDDEN,
|
||
payload: {
|
||
display: DISPLAY_STATUS.HIDDEN,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
export const setDisplayVisible = () => ({
|
||
type: types.SET_DISPLAY_VISIBLE,
|
||
payload: {
|
||
display: DISPLAY_STATUS.VISIBLE,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
export const setDisplayMinimized = () => ({
|
||
type: types.SET_DISPLAY_MINIMIZED,
|
||
payload: {
|
||
display: DISPLAY_STATUS.MINIMIZED,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
export const setDisplayFullscreen = () => ({
|
||
type: types.SET_DISPLAY_FULLSCREEN,
|
||
payload: {
|
||
display: DISPLAY_STATUS.FULLSCREEN,
|
||
lastUpdate: Date.now(),
|
||
},
|
||
});
|
||
|
||
/**
|
||
* 배너 비디오를 시작합니다.
|
||
* @param {Object} videoInfo - 비디오 정보
|
||
* @param {string} videoInfo.bannerId - 배너 ID
|
||
* @param {string} videoInfo.videoId - 비디오 ID
|
||
* @param {string} videoInfo.showUrl - 비디오 URL
|
||
* @param {boolean} videoInfo.modal - 모달 여부
|
||
* @param {string} videoInfo.modalContainerId - 모달 컨테이너 ID
|
||
* @param {string} videoInfo.modalClassName - 모달 클래스 이름
|
||
*/
|
||
export const startBannerVideo = (videoInfo) => (dispatch, getState) => {
|
||
dlog('[startBannerVideo] ✅ START - videoInfo:', videoInfo);
|
||
|
||
const {
|
||
bannerId,
|
||
videoId,
|
||
showUrl,
|
||
modal = true,
|
||
modalContainerId,
|
||
modalClassName,
|
||
...rest
|
||
} = videoInfo;
|
||
|
||
console.log('[Detail-BG] 🎥 startBannerVideo - Starting banner video', {
|
||
modalStatus: modal,
|
||
bannerId,
|
||
displayMode: modal ? 'VISIBLE (modal=true)' : 'FULLSCREEN (modal=false)',
|
||
videoId,
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
// 비디오 식별자 생성
|
||
const videoIdentifier = videoId || showUrl || bannerId;
|
||
if (videoIdentifier) {
|
||
const displayMode = modal ? DISPLAY_STATUS.VISIBLE : DISPLAY_STATUS.FULLSCREEN;
|
||
dlog(
|
||
'[startBannerVideo] 📌 Setting playback loading - identifier:',
|
||
videoIdentifier,
|
||
', displayMode:',
|
||
displayMode
|
||
);
|
||
dispatch(setPlaybackLoading(videoIdentifier, displayMode));
|
||
}
|
||
|
||
const panels = getState().panels.panels;
|
||
const existingPlayerPanel = panels.find((p) => p.name === panel_names.PLAYER_PANEL);
|
||
|
||
// 기존 PlayerPanel이 있으면 초기화
|
||
if (existingPlayerPanel) {
|
||
dlog('[startBannerVideo] 🔄 Resetting existing PLAYER_PANEL before start');
|
||
console.log('[Detail-BG] 🔄 startBannerVideo - Clearing existing PlayerPanel', {
|
||
existingModalStatus: existingPlayerPanel.panelInfo?.modal,
|
||
timestamp: Date.now(),
|
||
});
|
||
clearAllVideoTimers();
|
||
dispatch(popPanel(panel_names.PLAYER_PANEL));
|
||
}
|
||
|
||
// 새로운 PlayerPanel push
|
||
console.log('[Detail-BG] ➕ startBannerVideo - Pushing new PlayerPanel with modal status', {
|
||
modal,
|
||
modalContainerId,
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
dispatch(
|
||
pushPanel(
|
||
{
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
modal,
|
||
modalContainerId,
|
||
modalClassName,
|
||
playerState: {
|
||
currentBannerId: bannerId,
|
||
},
|
||
videoId,
|
||
showUrl,
|
||
bannerId,
|
||
...rest,
|
||
},
|
||
},
|
||
true
|
||
)
|
||
);
|
||
|
||
console.log('[Detail-BG] ✅ startBannerVideo - PlayerPanel pushed with modal=' + modal, {
|
||
timestamp: Date.now(),
|
||
});
|
||
|
||
dlog('[startBannerVideo] ✨ Panel action dispatched');
|
||
};
|
||
|
||
/**
|
||
* 비디오를 중지하고 화면에서 숨깁니다.
|
||
* 패널을 닫지 않고 비디오 재생만 중지합니다.
|
||
*/
|
||
export const stopAndHideVideo = () => (dispatch, getState) => {
|
||
const panels = getState().panels.panels;
|
||
|
||
// 모든 PlayerPanel 찾기
|
||
const playerPanels = panels.filter((panel) => panel.name === panel_names.PLAYER_PANEL);
|
||
|
||
if (playerPanels.length > 0) {
|
||
dlog('[stopAndHideVideo] Stopping all video playback and hiding');
|
||
|
||
// 타이머 정리
|
||
if (startVideoFocusTimer) {
|
||
clearTimeout(startVideoFocusTimer);
|
||
startVideoFocusTimer = null;
|
||
}
|
||
|
||
// 모든 PlayerPanel을 중지 및 숨김 상태로 업데이트
|
||
playerPanels.forEach((playerPanel) => {
|
||
dispatch(
|
||
updatePanel({
|
||
name: panel_names.PLAYER_PANEL,
|
||
panelInfo: {
|
||
...playerPanel.panelInfo,
|
||
shouldStop: true,
|
||
isPaused: true,
|
||
isHidden: true,
|
||
},
|
||
})
|
||
);
|
||
});
|
||
|
||
// Redux 상태도 중지로 업데이트
|
||
dispatch(setVideoStopped());
|
||
}
|
||
};
|