fix: HomeBanner 동영상기능 원복

This commit is contained in:
djaco
2025-06-23 09:49:13 +09:00
parent 556a0e8456
commit 2f1cfc7baa
5 changed files with 2356 additions and 2199 deletions

View File

@@ -201,9 +201,13 @@ export const types = {
* *
* SET_PLAYER_CONTROL: 특정 컴포넌트에게 비디오 재생 제어권을 부여합니다. * SET_PLAYER_CONTROL: 특정 컴포넌트에게 비디오 재생 제어권을 부여합니다.
* CLEAR_PLAYER_CONTROL: 컴포넌트로부터 비디오 재생 제어권을 회수합니다. * CLEAR_PLAYER_CONTROL: 컴포넌트로부터 비디오 재생 제어권을 회수합니다.
* PAUSE_PLAYER_CONTROL: 현재 제어권을 가진 비디오를 '일시정지' 상태로 변경합니다.
* RESUME_PLAYER_CONTROL: '일시정지' 상태의 비디오를 다시 재생합니다.
*/ */
SET_PLAYER_CONTROL: "SET_PLAYER_CONTROL", SET_PLAYER_CONTROL: "SET_PLAYER_CONTROL",
CLEAR_PLAYER_CONTROL: "CLEAR_PLAYER_CONTROL", CLEAR_PLAYER_CONTROL: "CLEAR_PLAYER_CONTROL",
PAUSE_PLAYER_CONTROL: "PAUSE_PLAYER_CONTROL",
RESUME_PLAYER_CONTROL: "RESUME_PLAYER_CONTROL",
// reset action // reset action
RESET_REDUX_STATE: "RESET_REDUX_STATE", RESET_REDUX_STATE: "RESET_REDUX_STATE",

View File

@@ -133,13 +133,25 @@ export const requestPlayControl =
(ownerId, videoInfo) => (dispatch, getState) => { (ownerId, videoInfo) => (dispatch, getState) => {
const { playerControl } = getState().home; const { playerControl } = getState().home;
const currentOwnerId = playerControl.ownerId; const currentOwnerId = playerControl.ownerId;
const isPersistentOwner = currentOwnerId === 'banner0_persistent';
// 이미 다른 컴포넌트가 제어권을 가지고 있다면, 먼저 해제한다. (선점) // 이미 같은 컴포넌트가 제어권을 가지고 있다면 아무것도 하지 않음
if (currentOwnerId && currentOwnerId !== ownerId) { if (currentOwnerId === ownerId) {
dispatch(releasePlayControl(currentOwnerId, true)); // fromPreemption = true return;
} }
// 새로운 제어권을 설정하고 비디오를 재생한다. // 다른 컴포넌트가 제어권을 가지고 있을 때의 처리 (선점 로직)
if (currentOwnerId && currentOwnerId !== ownerId) {
// 만약 현재 재생중인 비디오가 영구 재생 비디오라면, 종료하는 대신 '일시정지'
if (isPersistentOwner) {
dispatch(pausePlayerControl(currentOwnerId));
} else {
// 그 외의 경우는 기존처럼 완전히 종료
dispatch(releasePlayControl(currentOwnerId, true)); // fromPreemption = true
}
}
// 새로운 제어권을 설정하고 비디오를 재생
dispatch({ dispatch({
type: types.SET_PLAYER_CONTROL, type: types.SET_PLAYER_CONTROL,
payload: { ownerId }, payload: { ownerId },
@@ -158,6 +170,7 @@ export const requestPlayControl =
*/ */
export const releasePlayControl = (ownerId, fromPreemption = false) => (dispatch, getState) => { export const releasePlayControl = (ownerId, fromPreemption = false) => (dispatch, getState) => {
const { playerControl } = getState().home; const { playerControl } = getState().home;
const isPersistentOwner = playerControl.ownerId === 'banner0_persistent';
// 제어권을 가진 컴포넌트가 자신일 경우에만 해제 // 제어권을 가진 컴포넌트가 자신일 경우에만 해제
// 단, 선점 로직에 의해 호출된 경우는 소유권 확인 없이 즉시 실행 // 단, 선점 로직에 의해 호출된 경우는 소유권 확인 없이 즉시 실행
@@ -166,5 +179,43 @@ export const releasePlayControl = (ownerId, fromPreemption = false) => (dispatch
type: types.CLEAR_PLAYER_CONTROL, type: types.CLEAR_PLAYER_CONTROL,
}); });
dispatch(finishVideoPreview()); dispatch(finishVideoPreview());
// 제어권 해제 후, 만약 이전에 일시정지된 영구 비디오가 있었다면 다시 재생
if (isPersistentOwner && playerControl.isPaused) {
dispatch(resumePlayerControl('banner0_persistent'));
}
}
};
/**
* 현재 재생 중인 비디오를 '일시정지' 상태로 변경하는 액션.
* 이 함수는 플레이어 패널을 닫지 않고, 단순히 비디오 재생을 멈추는 신호를 보냅니다.
*
* @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,
});
} }
}; };

View File

@@ -23,6 +23,7 @@ const initialState = {
curationTitle: "", curationTitle: "",
playerControl: { playerControl: {
ownerId: null, ownerId: null,
isPaused: false,
}, },
}; };
@@ -198,6 +199,7 @@ export const homeReducer = (state = initialState, action) => {
playerControl: { playerControl: {
...state.playerControl, ...state.playerControl,
ownerId: action.payload.ownerId, ownerId: action.payload.ownerId,
isPaused: false,
}, },
}; };
} }
@@ -208,6 +210,27 @@ export const homeReducer = (state = initialState, action) => {
playerControl: { playerControl: {
...state.playerControl, ...state.playerControl,
ownerId: null, ownerId: null,
isPaused: false,
},
};
}
case types.PAUSE_PLAYER_CONTROL: {
return {
...state,
playerControl: {
...state.playerControl,
isPaused: true,
},
};
}
case types.RESUME_PLAYER_CONTROL: {
return {
...state,
playerControl: {
...state.playerControl,
isPaused: false,
}, },
}; };
} }

View File

@@ -266,27 +266,80 @@ export default function HomeBanner({
} }
}, [shouldShowOptionalTermsPopup, termsLoading]); }, [shouldShowOptionalTermsPopup, termsLoading]);
// const renderItem = useCallback(
// (index, isHorizontal) => {
// const data = bannerDataList?.[index] ?? {};
// if (index === 1) {
// return (
// <div className={!isHorizontal ? css.imgBox : undefined}>
// <RandomUnitNew
// bannerData={data}
// isHorizontal={isHorizontal}
// key={"banner" + index}
// spotlightId={"banner" + index}
// handleShelfFocus={_handleShelfFocus}
// onFocus={handleSecondBannerFocus}
// onBlur={handleSecondBannerBlur}
// randomNumber={data.randomIndex}
// />
// </div>
// );
// }
// return (
// <div className={!isHorizontal ? css.imgBox : undefined}>
// {data.shptmDspyTpNm === "Rolling" ? (
// <Rolling
// bannerData={data}
// isHorizontal={isHorizontal}
// key={"banner" + index}
// spotlightId={"banner" + index}
// handleShelfFocus={_handleShelfFocus}
// handleItemFocus={_handleItemFocus}
// />
// ) : data.shptmDspyTpNm === "Random" ? (
// <Random
// bannerData={data}
// isHorizontal={isHorizontal}
// key={"banner" + index}
// spotlightId={"banner" + index}
// handleShelfFocus={_handleShelfFocus}
// handleItemFocus={_handleItemFocus}
// randomNumber={data.randomIndex}
// />
// ) : (
// <SpottableComponent spotlightId={"banner" + index}>
// <CustomImage
// delay={0}
// src={
// isHorizontal
// ? homeTopDisplayInfo.wdthtpImgPath1
// : homeTopDisplayInfo.vtctpImgPath1
// }
// aria-label={
// isHorizontal
// ? homeTopDisplayInfo.wdthtpImgNm1
// : homeTopDisplayInfo.vtctpImgNm1
// }
// />
// </SpottableComponent>
// )}
// </div>
// );
// },
// [
// bannerDataList,
// _handleItemFocus,
// _handleShelfFocus,
// handleSecondBannerFocus,
// handleSecondBannerBlur,
// ],
// );
const renderItem = useCallback( const renderItem = useCallback(
(index, isHorizontal) => { (index, isHorizontal) => {
const data = bannerDataList?.[index] ?? {}; const data = bannerDataList?.[index] ?? {};
if (index === 1) {
return (
<div className={!isHorizontal ? css.imgBox : undefined}>
<RandomUnitNew
bannerData={data}
isHorizontal={isHorizontal}
key={"banner" + index}
spotlightId={"banner" + index}
handleShelfFocus={_handleShelfFocus}
onFocus={handleSecondBannerFocus}
onBlur={handleSecondBannerBlur}
randomNumber={data.randomIndex}
/>
</div>
);
}
return ( return (
<div className={!isHorizontal ? css.imgBox : undefined}> <div className={!isHorizontal ? css.imgBox : undefined}>
{data.shptmDspyTpNm === "Rolling" ? ( {data.shptmDspyTpNm === "Rolling" ? (
@@ -328,13 +381,7 @@ export default function HomeBanner({
</div> </div>
); );
}, },
[ [_handleItemFocus, _handleShelfFocus, bannerDataList]
bannerDataList,
_handleItemFocus,
_handleShelfFocus,
handleSecondBannerFocus,
handleSecondBannerBlur,
],
); );
const renderItemPersistentVideo = useCallback( const renderItemPersistentVideo = useCallback(

View File

@@ -4,70 +4,70 @@ import React, {
useLayoutEffect, useLayoutEffect,
useMemo, useMemo,
useRef, useRef,
} from "react"; } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { Job } from "@enact/core/util"; import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight"; import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; import { setContainerLastFocusedElement } from "@enact/spotlight/src/container";
import dummyVtt from "../../../assets/mock/video.vtt"; import dummyVtt from "../../../assets/mock/video.vtt";
import { import {
changeAppStatus, changeAppStatus,
changeLocalSettings, changeLocalSettings,
requestLiveSubtitle, requestLiveSubtitle,
sendBroadCast, sendBroadCast,
setHidePopup, setHidePopup,
} from "../../actions/commonActions"; } from "../../actions/commonActions";
import { import {
sendLogGNB, sendLogGNB,
sendLogLive, sendLogLive,
sendLogTotalRecommend, sendLogTotalRecommend,
sendLogVOD, sendLogVOD,
} from "../../actions/logActions"; } from "../../actions/logActions";
import { import {
clearShopNowInfo, clearShopNowInfo,
getHomeFullVideoInfo, getHomeFullVideoInfo,
getMainCategoryShowDetail, getMainCategoryShowDetail,
getMainLiveShow, getMainLiveShow,
getMainLiveShowNowProduct, getMainLiveShowNowProduct,
} from "../../actions/mainActions"; } from "../../actions/mainActions";
import * as PanelActions from "../../actions/panelActions"; import * as PanelActions from "../../actions/panelActions";
import { updatePanel } from "../../actions/panelActions"; import { updatePanel } from "../../actions/panelActions";
import { import {
CLEAR_PLAYER_INFO, CLEAR_PLAYER_INFO,
getChatLog, getChatLog,
getSubTitle, getSubTitle,
startVideoPlayer, startVideoPlayer,
} from "../../actions/playActions"; } from "../../actions/playActions";
import { convertUtcToLocal } from "../../components/MediaPlayer/util"; import { convertUtcToLocal } from "../../components/MediaPlayer/util";
import TPanel from "../../components/TPanel/TPanel"; import TPanel from "../../components/TPanel/TPanel";
import TPopUp from "../../components/TPopUp/TPopUp"; import TPopUp from "../../components/TPopUp/TPopUp";
import Media from "../../components/VideoPlayer/Media"; import Media from "../../components/VideoPlayer/Media";
import TReactPlayer from "../../components/VideoPlayer/TReactPlayer"; import TReactPlayer from "../../components/VideoPlayer/TReactPlayer";
import { VideoPlayer } from "../../components/VideoPlayer/VideoPlayer"; import { VideoPlayer } from "../../components/VideoPlayer/VideoPlayer";
import usePrevious from "../../hooks/usePrevious"; import usePrevious from "../../hooks/usePrevious";
import useWhyDidYouUpdate from "../../hooks/useWhyDidYouUpdate"; import useWhyDidYouUpdate from "../../hooks/useWhyDidYouUpdate";
import * as Config from "../../utils/Config"; import * as Config from "../../utils/Config";
import { ACTIVE_POPUP, panel_names } from "../../utils/Config"; import { ACTIVE_POPUP, panel_names } from "../../utils/Config";
import { $L, formatGMTString } from "../../utils/helperMethods"; import { $L, formatGMTString } from "../../utils/helperMethods";
import { SpotlightIds } from "../../utils/SpotlightIds"; import { SpotlightIds } from "../../utils/SpotlightIds";
import { removeDotAndColon } from "./PlayerItemCard/PlayerItemCard"; import { removeDotAndColon } from "./PlayerItemCard/PlayerItemCard";
import PlayerOverlayChat from "./PlayerOverlay/PlayerOverlayChat"; import PlayerOverlayChat from "./PlayerOverlay/PlayerOverlayChat";
import PlayerOverlayQRCode from "./PlayerOverlay/PlayerOverlayQRCode"; import PlayerOverlayQRCode from "./PlayerOverlay/PlayerOverlayQRCode";
import css from "./PlayerPanel.module.less"; import css from "./PlayerPanel.module.less";
import PlayerTabButton from "./PlayerTabContents/TabButton/PlayerTabButton"; import PlayerTabButton from "./PlayerTabContents/TabButton/PlayerTabButton";
import TabContainer from "./PlayerTabContents/TabContainer"; import TabContainer from "./PlayerTabContents/TabContainer";
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "default-element", preserveld: true }, { enterTo: "default-element", preserveld: true },
"div" "div",
); );
const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => { const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => {
try { try {
if (currentAttempts >= maxAttempts) { if (currentAttempts >= maxAttempts) {
throw new Error("selector not found"); throw new Error("selector not found");
@@ -83,9 +83,9 @@ import React, {
} catch (error) { } catch (error) {
// console.error(error.message); // console.error(error.message);
} }
}; };
const getLogTpNo = (type, nowMenu) => { const getLogTpNo = (type, nowMenu) => {
if (type === "LIVE") { if (type === "LIVE") {
switch (nowMenu) { switch (nowMenu) {
case Config.LOG_MENU.HOME_TOP: case Config.LOG_MENU.HOME_TOP:
@@ -130,9 +130,9 @@ import React, {
return; return;
} }
} }
}; };
const YOUTUBECONFIG = { const YOUTUBECONFIG = {
playerVars: { playerVars: {
controls: 0, // 플레이어 컨트롤 표시 controls: 0, // 플레이어 컨트롤 표시
autoplay: 1, autoplay: 1,
@@ -150,23 +150,23 @@ import React, {
cc_load_policy: 0, cc_load_policy: 0,
playsinline: 1, playsinline: 1,
}, },
}; };
const INITIAL_TIMEOUT = 30000; const INITIAL_TIMEOUT = 30000;
const REGULAR_TIMEOUT = 30000; const REGULAR_TIMEOUT = 30000;
const TAB_CONTAINER_SPOTLIGHT_ID = "tab-container-spotlight-id"; const TAB_CONTAINER_SPOTLIGHT_ID = "tab-container-spotlight-id";
const TARGET_EVENTS = ["mousemove", "keydown", "click"]; const TARGET_EVENTS = ["mousemove", "keydown", "click"];
// last time error // last time error
const VIDEO_END_ACTION_DELAY = 1500; const VIDEO_END_ACTION_DELAY = 1500;
const PlayerPanelNew = ({ const PlayerPanelNew = ({
isTabActivated, isTabActivated,
panelInfo, panelInfo,
isOnTop, isOnTop,
spotlightId, spotlightId,
...props ...props
}) => { }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { USE_STATE, USE_SELECTOR } = useWhyDidYouUpdate(spotlightId, { const { USE_STATE, USE_SELECTOR } = useWhyDidYouUpdate(spotlightId, {
isTabActivated, isTabActivated,
@@ -180,36 +180,36 @@ import React, {
const [shopNowInfo, setShopNowInfo] = USE_STATE("shopNowInfo"); const [shopNowInfo, setShopNowInfo] = USE_STATE("shopNowInfo");
const [backupInitialIndex, setBackupInitialIndex] = USE_STATE( const [backupInitialIndex, setBackupInitialIndex] = USE_STATE(
"backupInitialIndex", "backupInitialIndex",
0 0,
); );
const [modalStyle, setModalStyle] = USE_STATE("modalStyle", {}); const [modalStyle, setModalStyle] = USE_STATE("modalStyle", {});
const [modalScale, setModalScale] = USE_STATE("modalScale", 1); const [modalScale, setModalScale] = USE_STATE("modalScale", 1);
const [mediaId, setMediaId] = USE_STATE("mediaId", null); const [mediaId, setMediaId] = USE_STATE("mediaId", null);
const [currentLiveTimeSeconds, setCurrentLiveTimeSeconds] = USE_STATE( const [currentLiveTimeSeconds, setCurrentLiveTimeSeconds] = USE_STATE(
"currentLiveTimeSeconds", "currentLiveTimeSeconds",
1 1,
); );
const [prevChannelIndex, setPrevChannelIndex] = USE_STATE( const [prevChannelIndex, setPrevChannelIndex] = USE_STATE(
"prevChannelIndex", "prevChannelIndex",
0 0,
); );
const [sideContentsVisible, setSideContentsVisible] = USE_STATE( const [sideContentsVisible, setSideContentsVisible] = USE_STATE(
"sideContentsVisible", "sideContentsVisible",
true true,
); );
const [currentTime, setCurrentTime] = USE_STATE("currentTime", 0); const [currentTime, setCurrentTime] = USE_STATE("currentTime", 0);
const [isInitialFocusOccurred, setIsInitialFocusOccurred] = USE_STATE( const [isInitialFocusOccurred, setIsInitialFocusOccurred] = USE_STATE(
"isInitialFocusOccurred", "isInitialFocusOccurred",
false false,
); );
const [selectedIndex, setSelectedIndex] = USE_STATE( const [selectedIndex, setSelectedIndex] = USE_STATE(
"selectedIndex", "selectedIndex",
panelInfo.shptmBanrTpNm === "LIVE" ? null : 0 panelInfo.shptmBanrTpNm === "LIVE" ? null : 0,
); );
const [isUpdate, setIsUpdate] = USE_STATE("isUpdate", false); const [isUpdate, setIsUpdate] = USE_STATE("isUpdate", false);
const [isSubtitleActive, setIsSubtitleActive] = USE_STATE( const [isSubtitleActive, setIsSubtitleActive] = USE_STATE(
"isSubtitleActive", "isSubtitleActive",
true true,
); );
const [logStatus, setLogStatus] = USE_STATE("logStatus", { const [logStatus, setLogStatus] = USE_STATE("logStatus", {
isModalLiveLogReady: false, isModalLiveLogReady: false,
@@ -224,87 +224,91 @@ import React, {
}); });
const [isVODPaused, setIsVODPaused] = USE_STATE("isVODPaused", false); const [isVODPaused, setIsVODPaused] = USE_STATE("isVODPaused", false);
const playerControl = USE_SELECTOR(
"playerControl",
(state) => state.home.playerControl,
);
const panels = USE_SELECTOR("panels", (state) => state.panels.panels); const panels = USE_SELECTOR("panels", (state) => state.panels.panels);
const chatData = USE_SELECTOR("chatData", (state) => state.play.chatData); const chatData = USE_SELECTOR("chatData", (state) => state.play.chatData);
const popupVisible = USE_SELECTOR( const popupVisible = USE_SELECTOR(
"popupVisible", "popupVisible",
(state) => state.common.popup.popupVisible (state) => state.common.popup.popupVisible,
); );
const activePopup = USE_SELECTOR( const activePopup = USE_SELECTOR(
"activePopup", "activePopup",
(state) => state.common.popup.activePopup (state) => state.common.popup.activePopup,
); );
const showDetailInfo = USE_SELECTOR( const showDetailInfo = USE_SELECTOR(
"showDetailInfo", "showDetailInfo",
(state) => state.main.showDetailInfo (state) => state.main.showDetailInfo,
); );
const productImageLength = USE_SELECTOR( const productImageLength = USE_SELECTOR(
"productImageLength", "productImageLength",
(state) => state.product.productImageLength (state) => state.product.productImageLength,
); );
const themeProductInfos = USE_SELECTOR( const themeProductInfos = USE_SELECTOR(
"themeProductInfos", "themeProductInfos",
(state) => state.home.themeCurationDetailInfoData (state) => state.home.themeCurationDetailInfoData,
); );
const hotelInfos = USE_SELECTOR( const hotelInfos = USE_SELECTOR(
"hotelInfos", "hotelInfos",
(state) => state.home.themeCurationHotelDetailData (state) => state.home.themeCurationHotelDetailData,
); );
const captionEnable = USE_SELECTOR( const captionEnable = USE_SELECTOR(
"captionEnable", "captionEnable",
(state) => state.common.appStatus.captionEnable (state) => state.common.appStatus.captionEnable,
); );
const fullVideolgCatCd = USE_SELECTOR( const fullVideolgCatCd = USE_SELECTOR(
"fullVideolgCatCd", "fullVideolgCatCd",
(state) => state.main.fullVideolgCatCd (state) => state.main.fullVideolgCatCd,
); );
const featuredShowsInfos = USE_SELECTOR( const featuredShowsInfos = USE_SELECTOR(
"featuredShowsInfos", "featuredShowsInfos",
(state) => state.main.featuredShowsInfos (state) => state.main.featuredShowsInfos,
); );
const localRecentItems = USE_SELECTOR( const localRecentItems = USE_SELECTOR(
"localRecentItems", "localRecentItems",
(state) => state.localSettings?.recentItems (state) => state.localSettings?.recentItems,
); );
const httpHeader = USE_SELECTOR( const httpHeader = USE_SELECTOR(
"httpHeader", "httpHeader",
(state) => state.common?.httpHeader (state) => state.common?.httpHeader,
); );
const countryCode = USE_SELECTOR( const countryCode = USE_SELECTOR(
"countryCode", "countryCode",
(state) => state.common.httpHeader?.cntry_cd (state) => state.common.httpHeader?.cntry_cd,
); );
const liveChannelInfos = USE_SELECTOR( const liveChannelInfos = USE_SELECTOR(
"liveChannelInfos", "liveChannelInfos",
(state) => state.main.liveChannelInfos (state) => state.main.liveChannelInfos,
); );
const showNowInfos = USE_SELECTOR( const showNowInfos = USE_SELECTOR(
"showNowInfos", "showNowInfos",
(state) => state.main.showNowInfo (state) => state.main.showNowInfo,
); );
const liveShowInfos = USE_SELECTOR( const liveShowInfos = USE_SELECTOR(
"liveShowInfos", "liveShowInfos",
(state) => state.main.liveShowInfos (state) => state.main.liveShowInfos,
); );
const vodSubtitleData = USE_SELECTOR( const vodSubtitleData = USE_SELECTOR(
"vodSubtitleData", "vodSubtitleData",
(state) => state.play.subTitleBlobs (state) => state.play.subTitleBlobs,
); );
const broadcast = USE_SELECTOR( const broadcast = USE_SELECTOR(
"broadcast", "broadcast",
(state) => state.common.broadcast (state) => state.common.broadcast,
); );
const lastPanelAction = USE_SELECTOR( const lastPanelAction = USE_SELECTOR(
"lastPanelAction", "lastPanelAction",
(state) => state.panels.lastPanelAction (state) => state.panels.lastPanelAction,
); );
const nowMenu = USE_SELECTOR("nowMenu", (state) => state.common.menu.nowMenu); const nowMenu = USE_SELECTOR("nowMenu", (state) => state.common.menu.nowMenu);
const nowMenuRef = usePrevious(nowMenu); const nowMenuRef = usePrevious(nowMenu);
const entryMenu = USE_SELECTOR( const entryMenu = USE_SELECTOR(
"entryMenu", "entryMenu",
(state) => state.common.menu.entryMenu (state) => state.common.menu.entryMenu,
); );
const [videoLoaded, setVideoLoaded] = USE_STATE("videoLoaded", false); const [videoLoaded, setVideoLoaded] = USE_STATE("videoLoaded", false);
const entryMenuRef = usePrevious(entryMenu); const entryMenuRef = usePrevious(entryMenu);
@@ -378,7 +382,7 @@ import React, {
showId: currentLiveShowInfo.showId, showId: currentLiveShowInfo.showId,
showUrl: currentLiveShowInfo.showUrl, showUrl: currentLiveShowInfo.showUrl,
}, },
}) }),
); );
return; return;
@@ -460,8 +464,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -493,8 +497,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -526,8 +530,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -624,8 +628,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () => sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -657,8 +661,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () => sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -690,8 +694,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () => sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -780,8 +784,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () => sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -809,8 +813,8 @@ import React, {
clearInterval(watchInterval.current); clearInterval(watchInterval.current);
dispatch( dispatch(
sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () => sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () =>
dispatch(changeLocalSettings({ watchRecord: {} })) dispatch(changeLocalSettings({ watchRecord: {} })),
) ),
); );
}; };
} }
@@ -838,7 +842,7 @@ import React, {
resetTimer(REGULAR_TIMEOUT); resetTimer(REGULAR_TIMEOUT);
} }
}, },
[resetTimer, videoVerticalVisible] [resetTimer, videoVerticalVisible],
); );
const onClickBack = useCallback( const onClickBack = useCallback(
@@ -862,7 +866,7 @@ import React, {
...panelInfo, ...panelInfo,
modal: true, modal: true,
modalClassName: "", modalClassName: "",
}) }),
); );
videoPlayer.current?.hideControls(); videoPlayer.current?.hideControls();
setSelectedIndex(backupInitialIndex); setSelectedIndex(backupInitialIndex);
@@ -873,7 +877,7 @@ import React, {
panelInfo: { panelInfo: {
launchedFromPlayer: false, launchedFromPlayer: false,
}, },
}) }),
); );
} }
ev?.stopPropagation(); ev?.stopPropagation();
@@ -903,7 +907,7 @@ import React, {
sideContentsVisible, sideContentsVisible,
videoVerticalVisible, videoVerticalVisible,
backupInitialIndex, backupInitialIndex,
] ],
); );
useEffect(() => { useEffect(() => {
@@ -934,7 +938,7 @@ import React, {
? panelInfo.showId ? panelInfo.showId
: playListInfo[selectedIndex].showId, : playListInfo[selectedIndex].showId,
lstChgDt: showNowInfos.lstChgDt, lstChgDt: showNowInfos.lstChgDt,
}) }),
); );
}, periodInMilliseconds); }, periodInMilliseconds);
@@ -953,7 +957,7 @@ import React, {
initialFocusTimeoutJob.current.start(() => { initialFocusTimeoutJob.current.start(() => {
const initialFocusTarget = findSelector( const initialFocusTarget = findSelector(
`[data-spotlight-id="${targetId}"]` `[data-spotlight-id="${targetId}"]`,
); );
if (initialFocusTarget) { if (initialFocusTarget) {
@@ -1030,7 +1034,7 @@ import React, {
const showId = showDetailInfo[0]?.showId; const showId = showDetailInfo[0]?.showId;
const index = featuredShowsInfos.findIndex( const index = featuredShowsInfos.findIndex(
(show) => show.showId === showId (show) => show.showId === showId,
); );
let newArray = []; let newArray = [];
@@ -1049,7 +1053,7 @@ import React, {
} }
}, },
[showDetailInfo] [showDetailInfo],
); );
useEffect(() => { useEffect(() => {
@@ -1060,7 +1064,7 @@ import React, {
patnrId: panelInfo.patnrId, patnrId: panelInfo.patnrId,
showId: panelInfo.showId, showId: panelInfo.showId,
curationId: panelInfo.curationId, curationId: panelInfo.curationId,
}) }),
); );
} }
dispatch(getMainLiveShow({ vodIncFlag: "Y" })); dispatch(getMainLiveShow({ vodIncFlag: "Y" }));
@@ -1085,7 +1089,7 @@ import React, {
dispatch( dispatch(
getHomeFullVideoInfo({ getHomeFullVideoInfo({
lgCatCd: showDetailInfo[0].showCatCd, lgCatCd: showDetailInfo[0].showCatCd,
}) }),
); );
} }
if ( if (
@@ -1115,7 +1119,7 @@ import React, {
getMainLiveShowNowProduct({ getMainLiveShowNowProduct({
patnrId: playListInfo[selectedIndex]?.patnrId, patnrId: playListInfo[selectedIndex]?.patnrId,
showId: playListInfo[selectedIndex]?.showId, showId: playListInfo[selectedIndex]?.showId,
}) }),
); );
} }
@@ -1123,7 +1127,7 @@ import React, {
dispatch( dispatch(
getHomeFullVideoInfo({ getHomeFullVideoInfo({
lgCatCd: playListInfo[selectedIndex]?.catCd, lgCatCd: playListInfo[selectedIndex]?.catCd,
}) }),
); );
} }
} }
@@ -1139,7 +1143,7 @@ import React, {
panelInfo.shptmBanrTpNm === "VOD" panelInfo.shptmBanrTpNm === "VOD"
) { ) {
dispatch( dispatch(
getChatLog({ patnrId: panelInfo.patnrId, showId: panelInfo.showId }) getChatLog({ patnrId: panelInfo.patnrId, showId: panelInfo.showId }),
); );
} }
} }
@@ -1167,7 +1171,7 @@ import React, {
useEffect(() => { useEffect(() => {
if (panelInfo?.shptmBanrTpNm === "LIVE" && playListInfo?.length > 0) { if (panelInfo?.shptmBanrTpNm === "LIVE" && playListInfo?.length > 0) {
const index = playListInfo.findIndex( const index = playListInfo.findIndex(
(item) => item.chanId === panelInfo.chanId (item) => item.chanId === panelInfo.chanId,
); );
if (index !== -1 && !isUpdate) { if (index !== -1 && !isUpdate) {
setBackupInitialIndex(index); setBackupInitialIndex(index);
@@ -1296,7 +1300,7 @@ import React, {
panelInfo?.shptmBanrTpNm === "LIVE" panelInfo?.shptmBanrTpNm === "LIVE"
) { ) {
const localStartDt = convertUtcToLocal( const localStartDt = convertUtcToLocal(
liveShowInfos[selectedIndex]?.strtDt liveShowInfos[selectedIndex]?.strtDt,
); );
const curDt = new Date(); const curDt = new Date();
@@ -1318,7 +1322,7 @@ import React, {
setCurrentLiveTimeSeconds(parseInt(panelInfo.offsetHour)); setCurrentLiveTimeSeconds(parseInt(panelInfo.offsetHour));
} else if (liveShowInfos && panelInfo?.shptmBanrTpNm === "LIVE") { } else if (liveShowInfos && panelInfo?.shptmBanrTpNm === "LIVE") {
const localStartDt = convertUtcToLocal( const localStartDt = convertUtcToLocal(
liveShowInfos[selectedIndex]?.strtDt liveShowInfos[selectedIndex]?.strtDt,
); );
const curDt = new Date(); const curDt = new Date();
@@ -1370,7 +1374,7 @@ import React, {
dispatch( dispatch(
getHomeFullVideoInfo({ getHomeFullVideoInfo({
lgCatCd: playListInfo[selectedIndex].showCatCd, lgCatCd: playListInfo[selectedIndex].showCatCd,
}) }),
); );
}, 3000); }, 3000);
} }
@@ -1384,7 +1388,7 @@ import React, {
"mediainfoHandler....", "mediainfoHandler....",
type, type,
ev, ev,
videoPlayer.current?.getMediaState() videoPlayer.current?.getMediaState(),
); );
} }
if ( if (
@@ -1395,7 +1399,7 @@ import React, {
sendBroadCast({ sendBroadCast({
type: "videoError", type: "videoError",
moreInfo: { reason: "hlsError" }, moreInfo: { reason: "hlsError" },
}) }),
); );
return; return;
@@ -1411,7 +1415,7 @@ import React, {
sendBroadCast({ sendBroadCast({
type: "videoError", type: "videoError",
moreInfo: { reason: videoPlayer.current?.getMediaState().error }, moreInfo: { reason: videoPlayer.current?.getMediaState().error },
}) }),
); );
break; break;
} }
@@ -1422,7 +1426,7 @@ import React, {
} }
} }
}, },
[currentLiveTimeSeconds, liveTotalTime] [currentLiveTimeSeconds, liveTotalTime],
); );
useEffect(() => { useEffect(() => {
@@ -1453,7 +1457,7 @@ import React, {
(lastPanelAction === "previewPush" || lastPanelAction === "previewUpdate") (lastPanelAction === "previewPush" || lastPanelAction === "previewUpdate")
) { ) {
const node = document.querySelector( const node = document.querySelector(
`[data-spotlight-id="${panelInfo.modalContainerId}"]` `[data-spotlight-id="${panelInfo.modalContainerId}"]`,
); );
if (node) { if (node) {
const { width, height, top, left } = node.getBoundingClientRect(); const { width, height, top, left } = node.getBoundingClientRect();
@@ -1475,14 +1479,14 @@ import React, {
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
panelInfo: { modalStyle: modalStyle, modalScale: scale }, panelInfo: { modalStyle: modalStyle, modalScale: scale },
}) }),
); );
} else { } else {
setModalStyle(panelInfo.modalStyle); setModalStyle(panelInfo.modalStyle);
setModalScale(panelInfo.modalScale); setModalScale(panelInfo.modalScale);
console.error( console.error(
"PlayerPanel modalContainerId node not found", "PlayerPanel modalContainerId node not found",
panelInfo.modalContainerId panelInfo.modalContainerId,
); );
} }
} else if (isOnTop && !panelInfo.modal && videoPlayer.current) { } else if (isOnTop && !panelInfo.modal && videoPlayer.current) {
@@ -1502,14 +1506,14 @@ import React, {
const smallestOffsetHourIndex = useMemo(() => { const smallestOffsetHourIndex = useMemo(() => {
if (shopNowInfo) { if (shopNowInfo) {
const filteredVideos = shopNowInfo.filter( const filteredVideos = shopNowInfo.filter(
(video) => video.offsetHour >= currentTime (video) => video.offsetHour >= currentTime,
); );
const newSmallestOffsetHour = Math.min( const newSmallestOffsetHour = Math.min(
...filteredVideos.map((video) => video.offsetHour) ...filteredVideos.map((video) => video.offsetHour),
); );
const newSmallestOffsetHourIndex = shopNowInfo.findIndex( const newSmallestOffsetHourIndex = shopNowInfo.findIndex(
(video) => video.offsetHour === newSmallestOffsetHour.toString() (video) => video.offsetHour === newSmallestOffsetHour.toString(),
); );
if (shopNowInfo.length === 1) { if (shopNowInfo.length === 1) {
@@ -1542,7 +1546,11 @@ import React, {
} }
// For fullscreen, the playlist is the primary source. // For fullscreen, the playlist is the primary source.
if (playListInfo && playListInfo.length > 0 && playListInfo[selectedIndex]?.showUrl) { if (
playListInfo &&
playListInfo.length > 0 &&
playListInfo[selectedIndex]?.showUrl
) {
return playListInfo[selectedIndex]?.showUrl; return playListInfo[selectedIndex]?.showUrl;
} }
@@ -1718,7 +1726,7 @@ import React, {
dispatch(changeLocalSettings({ recentItems })); dispatch(changeLocalSettings({ recentItems }));
} }
}, },
[httpHeader, localRecentItems, dispatch] [httpHeader, localRecentItems, dispatch],
); );
const handleIndicatorDownClick = useCallback(() => { const handleIndicatorDownClick = useCallback(() => {
@@ -1744,7 +1752,7 @@ import React, {
patnrId: playListInfo[newIndex]?.patnrId, patnrId: playListInfo[newIndex]?.patnrId,
showId: playListInfo[newIndex]?.showId, showId: playListInfo[newIndex]?.showId,
curationId: playListInfo[newIndex]?.curationId, curationId: playListInfo[newIndex]?.curationId,
}) }),
); );
Spotlight.focus("playVideoShopNowBox"); Spotlight.focus("playVideoShopNowBox");
} else { } else {
@@ -1758,7 +1766,7 @@ import React, {
shptmBanrTpNm: panelInfo?.shptmBanrTpNm, shptmBanrTpNm: panelInfo?.shptmBanrTpNm,
isIndicatorByClick: true, isIndicatorByClick: true,
}, },
}) }),
); );
} }
} }
@@ -1798,7 +1806,7 @@ import React, {
patnrId: playListInfo[newIndex]?.patnrId, patnrId: playListInfo[newIndex]?.patnrId,
showId: playListInfo[newIndex]?.showId, showId: playListInfo[newIndex]?.showId,
curationId: playListInfo[newIndex]?.curationId, curationId: playListInfo[newIndex]?.curationId,
}) }),
); );
Spotlight.focus("playVideoShopNowBox"); Spotlight.focus("playVideoShopNowBox");
} else { } else {
@@ -1812,7 +1820,7 @@ import React, {
shptmBanrTpNm: panelInfo?.shptmBanrTpNm, shptmBanrTpNm: panelInfo?.shptmBanrTpNm,
isIndicatorByClick: true, isIndicatorByClick: true,
}, },
}) }),
); );
} }
} }
@@ -1840,7 +1848,7 @@ import React, {
patnrId: panelInfo.patnrId, patnrId: panelInfo.patnrId,
showId: panelInfo.showId, showId: panelInfo.showId,
curationId: panelInfo.curationId, curationId: panelInfo.curationId,
}) }),
); );
} }
}, [panelInfo.showId]); }, [panelInfo.showId]);
@@ -1862,7 +1870,7 @@ import React, {
launchedFromPlayer: true, launchedFromPlayer: true,
isPlayerFinished: true, isPlayerFinished: true,
}, },
}) }),
); );
Spotlight.pause(); Spotlight.pause();
setTimeout(() => { setTimeout(() => {
@@ -1974,7 +1982,7 @@ import React, {
useEffect(() => { useEffect(() => {
const node = document.querySelector( const node = document.querySelector(
`[data-spotlight-id=${TAB_CONTAINER_SPOTLIGHT_ID}]` `[data-spotlight-id=${TAB_CONTAINER_SPOTLIGHT_ID}]`,
); );
if (!showSideContents || !node || videoVerticalVisible) return; if (!showSideContents || !node || videoVerticalVisible) return;
@@ -1989,7 +1997,7 @@ import React, {
return () => { return () => {
TARGET_EVENTS.forEach((event) => TARGET_EVENTS.forEach((event) =>
node.removeEventListener(event, handleEvent) node.removeEventListener(event, handleEvent),
); );
if (timerId.current) { if (timerId.current) {
@@ -2087,7 +2095,7 @@ import React, {
videoLoaded, videoLoaded,
showDetailInfo?.[0]?.showId, showDetailInfo?.[0]?.showId,
playListInfo?.[selectedIndex]?.showId, playListInfo?.[selectedIndex]?.showId,
] ],
); );
// isVODPaused 상태 변경 시에만 로그를 보냄 // isVODPaused 상태 변경 시에만 로그를 보냄
@@ -2115,6 +2123,31 @@ import React, {
}; };
}, [createLogParams, dispatch]); }, [createLogParams, dispatch]);
useEffect(() => {
if (playerControl.ownerId === spotlightId && videoPlayer.current) {
const internalPlayer = videoPlayer.current.getInternalPlayer();
if (internalPlayer) {
if (playerControl.isPaused) {
internalPlayer.pause();
} else {
// It only works when it's already paused.
if (internalPlayer.paused) {
internalPlayer.play();
}
}
}
}
}, [playerControl.isPaused, playerControl.ownerId, spotlightId]);
/**
* 최초 포커스 발생시 처리
*/
useEffect(() => {
if (panelInfo.isUpdatedByClick && panelInfo.isIndicatorByClick) {
videoInitialFocused();
}
}, [panelInfo.isUpdatedByClick, panelInfo.isIndicatorByClick]);
return ( return (
<TPanel <TPanel
isTabActivated={false} isTabActivated={false}
@@ -2123,7 +2156,7 @@ import React, {
css.videoContainer, css.videoContainer,
panelInfo.modal && css.modal, panelInfo.modal && css.modal,
!isOnTop && css.background, !isOnTop && css.background,
!captionEnable && css.hideSubtitle !captionEnable && css.hideSubtitle,
)} )}
handleCancel={onClickBack} handleCancel={onClickBack}
spotlightId={spotlightId} spotlightId={spotlightId}
@@ -2246,7 +2279,7 @@ import React, {
hasText hasText
hasButton hasButton
text={$L( text={$L(
"To view the subtitles, please change the setting to 'On' in the system settings menu." "To view the subtitles, please change the setting to 'On' in the system settings menu.",
)} )}
button2Text={$L("OK")} button2Text={$L("OK")}
open={popupVisible} open={popupVisible}
@@ -2255,9 +2288,9 @@ import React, {
)} )}
</TPanel> </TPanel>
); );
}; };
const propsAreEqual = (prev, next) => { const propsAreEqual = (prev, next) => {
const keys = Object.keys(prev); const keys = Object.keys(prev);
const nextKeys = Object.keys(next); const nextKeys = Object.keys(next);
// if (!next.isOnTop) { // if (!next.isOnTop) {
@@ -2276,6 +2309,5 @@ import React, {
} }
} }
return true; return true;
}; };
export default React.memo(PlayerPanelNew, propsAreEqual); export default React.memo(PlayerPanelNew, propsAreEqual);