video caption track

This commit is contained in:
yonghyon
2024-04-27 13:53:04 +09:00
parent 9be6af7966
commit 37490171e7
13 changed files with 562 additions and 75 deletions

View File

@@ -79,3 +79,7 @@ SubCategory.jsx 참고(Home)
} }
} }
``` ```
# 자막영상
ontv4u 검색 후 첫 영상

View File

@@ -10,6 +10,7 @@ import {
changeAppStatus, changeAppStatus,
getDeviceId, getDeviceId,
getHttpHeaderForServiceRequest, getHttpHeaderForServiceRequest,
getSystemSettings,
} from "../actions/commonActions"; } from "../actions/commonActions";
import { getAuthenticationCode } from "../actions/deviceActions"; import { getAuthenticationCode } from "../actions/deviceActions";
import { import {
@@ -131,10 +132,7 @@ function AppBase(props) {
} }
dispatch(getDeviceId()); dispatch(getDeviceId());
dispatch(getHttpHeaderForServiceRequest()); dispatch(getHttpHeaderForServiceRequest());
//todo subscribe dispatch(getSystemSettings());
// dispatch(getSystemSettings());
// //get captionEnable
// dispatch(getSystemSettings2());
// dispatch(getSystemInfo()); // dispatch(getSystemInfo());
document.addEventListener("visibilitychange", visibilityChanged); document.addEventListener("visibilitychange", visibilityChanged);
document.addEventListener("webOSRelaunch", handleRelaunchEvent); document.addEventListener("webOSRelaunch", handleRelaunchEvent);

View File

@@ -57,6 +57,26 @@ export const alertToast = (payload) => (dispatch, getState) => {
} }
}; };
export const getSystemSettings =
() => (dispatch, getState) => {
console.log("getSystemSettings ");
lunaSend.getSystemSettings({"category":"caption", "keys": ["captionEnable"]},{
onSuccess: (res) => {
},
onFailure: (err) => {
},
onComplete: (res) => {
console.log("getSystemSettings onComplete",res);
if(res && res.settings){
if(typeof res.settings.captionEnable !== 'undefined'){
dispatch(changeAppStatus({captionEnable: res.settings.captionEnable}));
}
}
}
});
};
export const getHttpHeaderForServiceRequest = export const getHttpHeaderForServiceRequest =
(onComplete) => (dispatch, getState) => { (onComplete) => (dispatch, getState) => {
console.log("getHttpHeaderForServiceRequest "); console.log("getHttpHeaderForServiceRequest ");

View File

@@ -99,22 +99,31 @@ export const getSubTitle =
dispatch({ dispatch({
type: types.GET_SUBTITLE, type: types.GET_SUBTITLE,
payload: response.data.data, payload: {url: showSubtitleUrl, data: response.data.data},
}); });
}; };
const onFail = (error) => { const onFail = (error) => {
console.error("getSubTitle onFail", error); console.error("getSubTitle onFail", error);
dispatch({
type: types.GET_SUBTITLE,
payload: {url: showSubtitleUrl, data: "Error"},
});
}; };
TAxios( if(!getState().play.subTitleBlobs[showSubtitleUrl]){
dispatch, TAxios(
getState, dispatch,
"get", getState,
URLS.SUBTITLE, "get",
{ showSubtitleUrl }, URLS.SUBTITLE,
{}, { showSubtitleUrl },
onSuccess, {},
onFail onSuccess,
); onFail
);
}else{
console.log("playActions getSubTitle no Nothing it's exist", showSubtitleUrl);
}
}; };

View File

@@ -0,0 +1,391 @@
"use strict";
/* eslint-disable */
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Media = exports.handledMediaEventsMap = exports.getKeyFromSource = exports["default"] = void 0;
var _dispatcher = require("@enact/core/dispatcher");
var _handle = require("@enact/core/handle");
var _propTypes = _interopRequireDefault(require("@enact/core/internal/prop-types"));
var _propTypes2 = _interopRequireDefault(require("prop-types"));
var _react = _interopRequireDefault(require("react"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
/**
* Generates a key representing the source node or nodes provided
*
* Example:
* ```
* getKeyFromSource('path/file.mp4'); // 'path/file.mp4'
* getKeyFromSource(
* <source src="path/file.mp4" type="video/mp4" />
* ); // 'path/file.mp4'
* getKeyFromSource([
* <source src="path/file.mp4" type="video/mp4" />,
* <source src="path/file.ogg" type="video/ogg" />,
* ]); // 'path/file.mp4+path/file.ogg'
* ```
*
* @function
* @param {String|Element|Element[]} source URI for a source, `<source>` node, or array of
* `<source>` nodes
* @returns {String} Key representing sources
* @memberof ui/Media
* @public
*/
var getKeyFromSource = function getKeyFromSource() {
var source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
if ( /*#__PURE__*/_react["default"].isValidElement(source)) {
return _react["default"].Children.toArray(source).filter(function (s) {
return !!s;
}).map(function (s) {
return s.props.src;
}).join('+');
}
return String(source);
};
/**
* Maps standard media event `type` values to React-style callback prop names
*
* See https://reactjs.org/docs/events.html#media-events
*
* ```
* {
* abort : 'onAbort',
* canplay : 'onCanPlay',
* canplaythrough : 'onCanPlayThrough',
* durationchange : 'onDurationChange',
* emptied : 'onEmptied',
* encrypted : 'onEncrypted',
* ended : 'onEnded',
* error : 'onError',
* loadeddata : 'onLoadedData',
* loadedmetadata : 'onLoadedMetadata',
* loadstart : 'onLoadStart',
* pause : 'onPause',
* play : 'onPlay',
* playing : 'onPlaying',
* progress : 'onProgress',
* ratechange : 'onRateChange',
* seeked : 'onSeeked',
* seeking : 'onSeeking',
* stalled : 'onStalled',
* suspend : 'onSuspend',
* timeupdate : 'onTimeUpdate',
* volumechange : 'onVolumeChange',
* waiting : 'onWaiting'
* }
* ```
*
* @typedef {Object} handledMediaEventsMap
* @memberof ui/Media
* @public
*/
exports.getKeyFromSource = getKeyFromSource;
var handledMediaEventsMap = {
abort: 'onAbort',
canplay: 'onCanPlay',
canplaythrough: 'onCanPlayThrough',
durationchange: 'onDurationChange',
emptied: 'onEmptied',
encrypted: 'onEncrypted',
ended: 'onEnded',
error: 'onError',
loadeddata: 'onLoadedData',
loadedmetadata: 'onLoadedMetadata',
loadstart: 'onLoadStart',
pause: 'onPause',
play: 'onPlay',
playing: 'onPlaying',
progress: 'onProgress',
ratechange: 'onRateChange',
seeked: 'onSeeked',
seeking: 'onSeeking',
stalled: 'onStalled',
suspend: 'onSuspend',
timeupdate: 'onTimeUpdate',
volumechange: 'onVolumeChange',
waiting: 'onWaiting'
};
/**
* A component representation of HTMLMediaElement.
*
* @class Media
* @memberof ui/Media
* @ui
* @public
*/
exports.handledMediaEventsMap = handledMediaEventsMap;
var Media = /*#__PURE__*/function (_React$Component) {
_inherits(Media, _React$Component);
var _super = _createSuper(Media);
function Media(props) {
var _this;
_classCallCheck(this, Media);
_this = _super.call(this, props);
_this.attachCustomMediaEvents = function () {
for (var eventName in _this.handledCustomMediaForwards) {
(0, _dispatcher.on)(eventName, _this.handledCustomMediaForwards[eventName], _this.media);
}
};
_this.detachCustomMediaEvents = function () {
for (var eventName in _this.handledCustomMediaForwards) {
(0, _dispatcher.off)(eventName, _this.handledCustomMediaForwards[eventName], _this.media);
}
};
_this.handleEvent = function (ev) {
(0, _handle.forward)('onUpdate', {
type: 'onUpdate'
}, _this.props); // fetch the forward() we generated earlier, using the event type as a key to find the real event name.
var fwd = _this.handledMediaForwards[handledMediaEventsMap[ev.type]];
if (fwd) {
fwd(ev, _this.props);
}
};
_this.mediaRef = function (node) {
_this.media = node;
};
_this.media = null;
_this.handledMediaForwards = {};
_this.handledMediaEvents = {};
_this.handledCustomMediaForwards = {}; // Generate event handling forwarders and a smooth block to pass to <Video>
for (var key in props.mediaEventsMap) {
var eventName = props.mediaEventsMap[key];
_this.handledMediaForwards[eventName] = (0, _handle.forward)(eventName);
_this.handledMediaEvents[eventName] = _this.handleEvent;
} // Generate event handling forwarders for the custom events too
var _loop = function _loop(_eventName) {
var propName = props.customMediaEventsMap[_eventName];
var forwardEvent = (0, _handle.forward)(propName);
_this.handledCustomMediaForwards[_eventName] = function (ev) {
return forwardEvent(ev, _this.props);
};
};
for (var _eventName in props.customMediaEventsMap) {
_loop(_eventName);
}
return _this;
}
_createClass(Media, [{
key: "componentDidMount",
value: function componentDidMount() {
this.attachCustomMediaEvents();
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(_ref) {
var prevSource = _ref.source;
var source = this.props.source;
if (getKeyFromSource(source) !== getKeyFromSource(prevSource)) {
this.load();
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
this.detachCustomMediaEvents();
}
}, {
key: "play",
value: function play() {
return this.media.play();
}
}, {
key: "pause",
value: function pause() {
this.media.pause();
}
}, {
key: "load",
value: function load() {
this.media.load();
}
}, {
key: "render",
value: function render() {
var _this$props = this.props,
customMediaEventsMap = _this$props.customMediaEventsMap,
Component = _this$props.mediaComponent,
source = _this$props.source,
track = _this$props.track,
rest = _objectWithoutProperties(_this$props, ["customMediaEventsMap", "mediaComponent", "source", "track"]);
delete rest.mediaEventsMap;
delete rest.onUpdate; // Remove the events we manually added so they aren't added twice or fail.
for (var eventName in customMediaEventsMap) {
delete rest[customMediaEventsMap[eventName]];
}
return /*#__PURE__*/_react["default"].createElement(Component, Object.assign({}, rest, this.handledMediaEvents, {
ref: this.mediaRef
}), source, track);
}
}, {
key: "currentTime",
get: function get() {
return this.media.currentTime;
},
set: function set(currentTime) {
this.media.currentTime = currentTime;
}
}, {
key: "duration",
get: function get() {
return this.media.duration;
}
}, {
key: "error",
get: function get() {
return this.media.networkState === this.media.NETWORK_NO_SOURCE;
}
}, {
key: "loading",
get: function get() {
return this.media.readyState < this.media.HAVE_ENOUGH_DATA;
}
}, {
key: "paused",
get: function get() {
return this.media.paused;
}
}, {
key: "playbackRate",
get: function get() {
return this.media.playbackRate;
},
set: function set(playbackRate) {
this.media.playbackRate = playbackRate;
}
}, {
key: "proportionLoaded",
get: function get() {
return this.media.buffered.length && this.media.buffered.end(this.media.buffered.length - 1) / this.media.duration;
}
}, {
key: "proportionPlayed",
get: function get() {
return this.media.currentTime / this.media.duration;
}
}]);
return Media;
}(_react["default"].Component);
exports.Media = Media;
Media.propTypes =
/** @lends ui/Media.Media.prototype */
{
/**
* A type of media component.
*
* @type {String|Component}
* @required
* @public
*/
mediaComponent: _propTypes["default"].renderable.isRequired,
/**
* An event map object for custom media events.
*
* List custom events that aren't standard to React. These will be directly added to the media
* element and props matching their name will be executed as callback functions when the event fires.
*
* Example:
* ```
* {'umsmediainfo': 'onUMSMediaInfo'} // `onUMSMediaInfo` prop function will execute when the `umsmediainfo` event happens
* ```
*
* @type {Object}
* @public
*/
customMediaEventsMap: _propTypes2["default"].object,
/**
* A event map object for media events.
*
* @type {Object}
* @default {@link ui/Media.handledMediaEventsMap}
* @public
*/
mediaEventsMap: _propTypes2["default"].object,
/**
* A function to be run when media updates.
*
* @type {Function}
* @public
*/
onUpdate: _propTypes2["default"].func,
/**
* Media sources passed as children to `mediaComponent`
*
* See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source
*
* @type {*}
* @public
*/
source: _propTypes2["default"].any,
track: _propTypes2["default"].any //yhcho
};
Media.defaultProps = {
mediaEventsMap: handledMediaEventsMap
};
var _default = Media;
exports["default"] = _default;

View File

@@ -42,7 +42,7 @@ import Announce from "@enact/ui/AnnounceDecorator/Announce";
import ComponentOverride from "@enact/ui/ComponentOverride"; import ComponentOverride from "@enact/ui/ComponentOverride";
import { FloatingLayerDecorator } from "@enact/ui/FloatingLayer"; import { FloatingLayerDecorator } from "@enact/ui/FloatingLayer";
import { FloatingLayerContext } from "@enact/ui/FloatingLayer/FloatingLayerDecorator"; import { FloatingLayerContext } from "@enact/ui/FloatingLayer/FloatingLayerDecorator";
import Media from "@enact/ui/Media"; import Media from "./Media";
import Slottable from "@enact/ui/Slottable"; import Slottable from "@enact/ui/Slottable";
import Touchable from "@enact/ui/Touchable"; import Touchable from "@enact/ui/Touchable";
@@ -719,6 +719,7 @@ const VideoPlayerBase = class extends React.Component {
onIntroDisabled: PropTypes.func, onIntroDisabled: PropTypes.func,
modalClassName: PropTypes.any, modalClassName: PropTypes.any,
src: PropTypes.string, //for ReactPlayer src: PropTypes.string, //for ReactPlayer
reactPlayerConfig: PropTypes.string, //for ReactPlayer
}; };
static contextType = FloatingLayerContext; static contextType = FloatingLayerContext;
@@ -2063,6 +2064,7 @@ const VideoPlayerBase = class extends React.Component {
src, src,
width, width,
height, height,
reactPlayerConfig,
...mediaProps ...mediaProps
} = this.props; } = this.props;
@@ -2108,6 +2110,7 @@ const VideoPlayerBase = class extends React.Component {
mediaProps.width = width; mediaProps.width = width;
mediaProps.height = height; mediaProps.height = height;
mediaProps.videoRef = this.setVideoRef; mediaProps.videoRef = this.setVideoRef;
mediaProps.config = reactPlayerConfig;
} }
const controlsAriaProps = this.getControlsAriaProps(); const controlsAriaProps = this.getControlsAriaProps();

View File

@@ -2,41 +2,6 @@ import appinfo from '../../webos-meta/appinfo.json';
import * as Config from '../utils/Config'; import * as Config from '../utils/Config';
import LS2Request from './LS2Request'; import LS2Request from './LS2Request';
export const getSystemSettings = (
parameters,
{ onSuccess, onFailure, onComplete }
) => {
if (typeof window === "object" && window.PalmSystem) {
if (process.env.REACT_APP_MODE === "DEBUG") {
console.log("LUNA SEND getSystemSettings");
return "Some Hard Coded Mock Data";
} else {
return new LS2Request().send({
service: "luna://com.webos.settingsservice",
method: "getSystemSettings",
subscribe: true,
parameters: parameters,
onSuccess,
onFailure,
onComplete,
});
}
} else if (typeof window === "object") {
const language =
typeof window.navigator === "object"
? window.navigator.language || window.navigator.userLanguage
: "en-US";
const res = {
settings: {
smartServiceCountryCode2: language.split("-")[1],
captionEnable: true,
},
returnValue: true,
};
onSuccess(res);
onComplete(res);
}
};
export const getSystemInfo = ( export const getSystemInfo = (
parameters, parameters,
{ onSuccess, onFailure, onComplete } { onSuccess, onFailure, onComplete }

View File

@@ -87,3 +87,39 @@ export const getHttpHeaderForServiceRequest = ({
}); });
} }
}; };
export const getSystemSettings = (
parameters,
{ onSuccess, onFailure, onComplete }
) => {
if (typeof window === "object" && window.PalmSystem) {
if (process.env.REACT_APP_MODE === "DEBUG") {
console.log("LUNA SEND getSystemSettings");
return "Some Hard Coded Mock Data";
} else {
return new LS2Request().send({
service: "luna://com.webos.settingsservice",
method: "getSystemSettings",
subscribe: true,
parameters: parameters,
onSuccess,
onFailure,
onComplete,
});
}
} else if (typeof window === "object") {
const language =
typeof window.navigator === "object"
? window.navigator.language || window.navigator.userLanguage
: "en-US";
const res = {
settings: {
smartServiceCountryCode2: language.split("-")[1],
captionEnable: true,
},
returnValue: true,
};
onSuccess(res);
onComplete(res);
}
};

View File

@@ -12,6 +12,7 @@ const initialState = {
loginUserData: {}, loginUserData: {},
toast: false, toast: false,
toastText: null, toastText: null,
captionEnable: false
}, },
httpHeader: null, httpHeader: null,
isGnbOpened: false, isGnbOpened: false,

View File

@@ -1,6 +1,8 @@
import { types } from '../actions/actionTypes'; import { types } from '../actions/actionTypes';
const initialState = {}; const initialState = {
subTitleBlobs: {},
};
export const playReducer = (state = initialState, action) => { export const playReducer = (state = initialState, action) => {
switch (action.type) { switch (action.type) {
@@ -10,8 +12,13 @@ export const playReducer = (state = initialState, action) => {
chatData: action.payload.text, chatData: action.payload.text,
}; };
case types.GET_SUBTITLE: { case types.GET_SUBTITLE: {
let srtText = action.payload.text; let srtText = action.payload.data?.text;
if(!srtText){
return {
...state,
subTitleBlobs: { ...state.subTitleBlobs, [action.payload.url]: "Error" },
};
}
var srtRegex = var srtRegex =
/(.*\n)?(\d\d:\d\d:\d\d),(\d\d\d --> \d\d:\d\d:\d\d),(\d\d\d)/g; /(.*\n)?(\d\d:\d\d:\d\d),(\d\d\d --> \d\d:\d\d:\d\d),(\d\d\d)/g;
var vttText = "WEBVTT\n\n" + srtText.replace(srtRegex, "$1$2.$3.$4"); var vttText = "WEBVTT\n\n" + srtText.replace(srtRegex, "$1$2.$3.$4");
@@ -20,7 +27,7 @@ export const playReducer = (state = initialState, action) => {
return { return {
...state, ...state,
subTitle: blobUrl, subTitleBlobs: { ...state.subTitleBlobs, [action.payload.url]: blobUrl },
}; };
} }

View File

@@ -53,7 +53,7 @@ export const ACTIVE_POPUP = {
alarmOffPopup: "alarmOffPopup", alarmOffPopup: "alarmOffPopup",
qrPopup: "qrPopup", qrPopup: "qrPopup",
}; };
export const DEBUG_VIDEO_SUBTITLE_TEST = false;
export const AUTO_SCROLL_DELAY = 600; export const AUTO_SCROLL_DELAY = 600;
export const AUTO_SCROLL_GAP = 20; export const AUTO_SCROLL_GAP = 20;
export const SINGLE = "SINGLE"; export const SINGLE = "SINGLE";

View File

@@ -29,6 +29,7 @@ import {
getSubTitle, getSubTitle,
startVideoPlayer, startVideoPlayer,
} from "../../actions/playActions"; } from "../../actions/playActions";
import * as Config from "../../utils/Config";
import { MediaControls } from "../../components/MediaPlayer"; import { MediaControls } from "../../components/MediaPlayer";
import TButton from "../../components/TButton/TButton"; import TButton from "../../components/TButton/TButton";
import TButtonTab, { LIST_TYPE } from "../../components/TButtonTab/TButtonTab"; import TButtonTab, { LIST_TYPE } from "../../components/TButtonTab/TButtonTab";
@@ -46,6 +47,7 @@ import FeaturedShowContents from "./PlayerTabContents/FeaturedShowContents";
import LiveChannelContents from "./PlayerTabContents/LiveChannelContents"; import LiveChannelContents from "./PlayerTabContents/LiveChannelContents";
import ShopNowContents from "./PlayerTabContents/ShopNowContents"; import ShopNowContents from "./PlayerTabContents/ShopNowContents";
import YouMayLikeContents from "./PlayerTabContents/YouMayLikeContents"; import YouMayLikeContents from "./PlayerTabContents/YouMayLikeContents";
import dummyVtt from "../../../assets/mock/video.vtt";
const SpottableBtn = Spottable("button"); const SpottableBtn = Spottable("button");
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
@@ -78,6 +80,7 @@ const PlayerPanel = ({
const chatData = useSelector((state) => state.play.chatData); const chatData = useSelector((state) => state.play.chatData);
const youmaylikeInfos = useSelector((state) => state.main.youmaylikeInfos); const youmaylikeInfos = useSelector((state) => state.main.youmaylikeInfos);
const showDetailInfo = useSelector((state) => state.main.showDetailInfo); const showDetailInfo = useSelector((state) => state.main.showDetailInfo);
const captionEnable = useSelector((state) => state.common.appStatus.captionEnable);
const featuredShowsInfos = useSelector( const featuredShowsInfos = useSelector(
(state) => state.main.featuredShowsInfos (state) => state.main.featuredShowsInfos
); );
@@ -86,7 +89,8 @@ const PlayerPanel = ({
const showNowInfos = useSelector((state) => state.main.showNowInfo); const showNowInfos = useSelector((state) => state.main.showNowInfo);
const showNowProduct = useSelector((state) => state.main.showNowProduct); const showNowProduct = useSelector((state) => state.main.showNowProduct);
const liveShowInfos = useSelector((state) => state.main.liveShowInfos); const liveShowInfos = useSelector((state) => state.main.liveShowInfos);
const vodSubtitleData = useSelector((state) => state.play.subTitle); //getSubTitle
const vodSubtitleData = useSelector((state) => state.play.subTitleBlobs);
const tabList = [ const tabList = [
$L("SHOP NOW"), $L("SHOP NOW"),
$L(panelInfo?.shptmBanrTpNm === "LIVE" ? "LIVE CHANNEL" : "FEATURED SHOWS"), $L(panelInfo?.shptmBanrTpNm === "LIVE" ? "LIVE CHANNEL" : "FEATURED SHOWS"),
@@ -234,18 +238,6 @@ const PlayerPanel = ({
} }
}, [panelInfo, playListInfo]); }, [panelInfo, playListInfo]);
useEffect(() => {
if (
playListInfo &&
playListInfo.length > 0 &&
playListInfo[0].showSubtitlUrl
) {
dispatch(
getSubTitle({ showSubtitleUrl: playListInfo[0].showSubtitlUrl })
);
}
}, [dispatch, playListInfo]);
useEffect(() => { useEffect(() => {
if (!panelInfo) return; if (!panelInfo) return;
@@ -357,6 +349,52 @@ const PlayerPanel = ({
}, [panelInfo, isOnTop]); }, [panelInfo, isOnTop]);
delete props.panelInfo; delete props.panelInfo;
const currentSubtTitleUrl = useMemo(()=>{
return playListInfo && playListInfo[selectedIndex]?.showSubtitlUrl;
},[playListInfo, selectedIndex]);
const currentPlayingUrl = useMemo(()=>{
// return "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4";
return playListInfo && playListInfo[selectedIndex]?.showUrl;
},[playListInfo, selectedIndex]);
const currentSubtitleBlob = useMemo(()=>{
if(Config.DEBUG_VIDEO_SUBTITLE_TEST){
return dummyVtt;
}
return vodSubtitleData[currentSubtTitleUrl];
},[vodSubtitleData, currentSubtTitleUrl]);
const isReadyToPlay = useMemo(()=>{
if(!currentPlayingUrl){
return false;
}
if(!Config.DEBUG_VIDEO_SUBTITLE_TEST && currentSubtTitleUrl && !currentSubtitleBlob){
return false;
}
return true;
},[currentPlayingUrl, currentSubtTitleUrl, currentSubtitleBlob]);
useEffect(() => {
if (currentSubtTitleUrl) {
dispatch(getSubTitle({ showSubtitleUrl: currentSubtTitleUrl }));
}
}, [currentSubtTitleUrl]);
const reactPlayerSubtitleConfig = useMemo(() => {
if(currentSubtitleBlob){
return {file: {
attributes: {
crossOrigin: "true",
},
tracks: [{kind: 'subtitles', src: currentSubtitleBlob, default: true}],
}};
}else{
return undefined;
}
},[currentSubtitleBlob]);
return ( return (
<TPanel <TPanel
isTabActivated={false} isTabActivated={false}
@@ -364,10 +402,12 @@ const PlayerPanel = ({
className={classNames( className={classNames(
css.videoContainer, css.videoContainer,
panelInfo.modal && css.modal, panelInfo.modal && css.modal,
!isOnTop && css.background !isOnTop && css.background,
!captionEnable && css.hideSubtitle
)} )}
handleCancel={onClickBack} handleCancel={onClickBack}
> >
{isReadyToPlay &&
<VideoPlayer <VideoPlayer
setApiProvider={getPlayer} setApiProvider={getPlayer}
disabled={panelInfo.modal} disabled={panelInfo.modal}
@@ -380,15 +420,23 @@ const PlayerPanel = ({
setSelectedIndex={setSelectedIndex} // 선택한 인덱스 Set setSelectedIndex={setSelectedIndex} // 선택한 인덱스 Set
selectedIndex={selectedIndex} // 선택한 인덱스 selectedIndex={selectedIndex} // 선택한 인덱스
spotlightDisabled={sideOpen || panelInfo.modal} spotlightDisabled={sideOpen || panelInfo.modal}
src={playListInfo && playListInfo[selectedIndex]?.showUrl} src={currentPlayingUrl}
style={panelInfo.modal ? modalStyle : {}} style={panelInfo.modal ? modalStyle : {}}
modalClassName={panelInfo.modal && panelInfo.modalClassName} modalClassName={panelInfo.modal && panelInfo.modalClassName}
reactPlayerConfig={reactPlayerSubtitleConfig}
> >
<source {
src={playListInfo && playListInfo[selectedIndex]?.showUrl} typeof window === "object" && window.PalmSystem &&
type="application/mpegurl" <source
/> src={currentPlayingUrl}
type="application/mpegurl"
/>
}
{ typeof window === "object" && window.PalmSystem && currentSubtitleBlob &&
<track kind="subtitles" src={currentSubtitleBlob} default/>
}
</VideoPlayer> </VideoPlayer>
}
{playListInfo && playListInfo[selectedIndex]?.orderPhnNo && ( {playListInfo && playListInfo[selectedIndex]?.orderPhnNo && (
<VideoOverlayWithPhoneNumber <VideoOverlayWithPhoneNumber
className={css.videoOverlayWithPhoneNumber} className={css.videoOverlayWithPhoneNumber}

View File

@@ -175,4 +175,9 @@
display: none; display: none;
} }
} }
&.hideSubtitle{
video::cue {
visibility: hidden;
}
}
} }