Skip to content

Commit

Permalink
feat(project): implement enablecontinuewatching config setting
Browse files Browse the repository at this point in the history
  • Loading branch information
royschut committed Jun 14, 2021
1 parent 7296635 commit 0d9694d
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 81 deletions.
11 changes: 8 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { Component } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { I18nextProvider, getI18n } from 'react-i18next';
import type { Config } from 'types/Config';

import Root from './components/Root/Root';
import ConfigProvider from './providers/ConfigProvider';
import QueryProvider from './providers/QueryProvider';
import UIStateProvider from './providers/uiStateProvider';
import './i18n/config';
import './styles/main.scss';
import { loadWatchHistory } from './store/WatchHistoryStore';
import { initializeWatchHistory } from './store/WatchHistoryStore';

interface State {
error: Error | null;
}
Expand All @@ -22,8 +24,10 @@ class App extends Component {
this.setState({ error });
}

componentDidMount() {
loadWatchHistory();
initializeServices(config: Config) {
if (config.options.enableContinueWatching) {
initializeWatchHistory();
}
}

render() {
Expand All @@ -34,6 +38,7 @@ class App extends Component {
configLocation={window.configLocation}
onLoading={(isLoading: boolean) => console.info(`Loading config: ${isLoading}`)}
onValidationError={(error: Error) => console.error(`Config ${error}`)}
onValidationCompleted={(config) => this.initializeServices(config)}
>
<Router>
<UIStateProvider>
Expand Down
19 changes: 10 additions & 9 deletions src/containers/Cinema/Cinema.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useContext, useEffect, useState } from 'react';
import type { Config } from 'types/Config';
import type { PlaylistItem } from 'types/playlist';
import type { WatchHistoryItem } from 'types/watchHistory';

import { WatchHistoryStore, useWatchHistoryUpdater, WatchHistoryItem } from '../../store/WatchHistoryStore';
import { watchHistoryStore, useWatchHistoryUpdater } from '../../store/WatchHistoryStore';
import { ConfigContext } from '../../providers/ConfigProvider';
import { addScript } from '../../utils/dom';

Expand All @@ -19,7 +20,6 @@ const Cinema: React.FC<Props> = ({ item, onPlay, onPause }: Props) => {
const [initialized, setInitialized] = useState(false);
const file = item.sources[0]?.file;
const scriptUrl = `https://content.jwplatform.com/libraries/${config.player}.js`;
const continueTillPercentage = 0.95;

const createWatchHistoryItem = (): WatchHistoryItem | undefined => {
const player = window.jwplayer && (window.jwplayer('cinema') as jwplayer.JWPlayer);
Expand All @@ -31,20 +31,21 @@ const Cinema: React.FC<Props> = ({ item, onPlay, onPause }: Props) => {
position: player.getPosition(),
} as WatchHistoryItem;
};
const watchHistory = WatchHistoryStore.useState((state) => state.watchHistory);
const watchHistory = watchHistoryStore.useState((state) => state.watchHistory);
const updateWatchHistory = useWatchHistoryUpdater(createWatchHistoryItem);

useEffect(() => {
const getPlayer = () => window.jwplayer && (window.jwplayer('cinema') as jwplayer.JWPlayer);
const loadVideo = () => {
const player = getPlayer();
const position = watchHistory.find((historyItem) => historyItem.mediaid === item.mediaid)?.position;
player.setup({ file });
player.setup({ file, image: item.image, title: item.title, autostart: 'viewable' });
player.on('ready', () => {
if (position && position < player.getDuration() * continueTillPercentage) {
player.seek(position);
const { watchHistory } = watchHistoryStore.getRawState();
const position = watchHistory.find((historyItem) => historyItem.mediaid === item.mediaid)?.position;

if (position) {
setTimeout(() => player.seek(position), 1000);
}
player.play();
});
player.on('play', () => onPlay && onPlay());
player.on('pause', () => onPause && onPause());
Expand All @@ -54,7 +55,7 @@ const Cinema: React.FC<Props> = ({ item, onPlay, onPause }: Props) => {
getPlayer() ? loadVideo() : addScript(scriptUrl, loadVideo);
setInitialized(true);
}
}, [item.mediaid, onPlay, onPause, config.player, file, scriptUrl, initialized, watchHistory, updateWatchHistory]);
}, [item, onPlay, onPause, config.player, file, scriptUrl, initialized, watchHistory, updateWatchHistory]);

return <div className={styles.Cinema} id="cinema" />;
};
Expand Down
5 changes: 4 additions & 1 deletion src/providers/ConfigProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ export type ProviderProps = {
configLocation: string;
onLoading: (isLoading: boolean) => void;
onValidationError: (error: Error) => void;
onValidationCompleted: (config: Config) => void;
};

const ConfigProvider: FunctionComponent<ProviderProps> = ({
children,
configLocation,
onLoading,
onValidationError,
onValidationCompleted,
}) => {
const [config, setConfig] = useState<Config>(defaultConfig);
const [loading, setLoading] = useState<boolean>(true);
Expand All @@ -49,6 +51,7 @@ const ConfigProvider: FunctionComponent<ProviderProps> = ({
setCssVariables(configValidated.options);
onLoading(false);
setLoading(false);
onValidationCompleted(config);
})
.catch((error: Error) => {
onValidationError(error);
Expand All @@ -57,7 +60,7 @@ const ConfigProvider: FunctionComponent<ProviderProps> = ({
});
};
loadAndValidateConfig(configLocation);
}, [configLocation, onLoading, onValidationError]);
}, [configLocation, onLoading, onValidationError, onValidationCompleted]);

const setCssVariables = ({ backgroundColor, highlightColor, headerBackground }: Options) => {
const root = document.querySelector(':root') as HTMLElement;
Expand Down
49 changes: 0 additions & 49 deletions src/services/persist.service.ts

This file was deleted.

37 changes: 18 additions & 19 deletions src/store/WatchHistoryStore.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,49 @@
import { Store } from 'pullstate';
import { useEffect } from 'react';
import type { WatchHistoryItem } from 'types/watchHistory';

import * as persist from '../services/persist.service';
import * as persist from '../utils/persist';

export type WatchHistoryItem = {
mediaid: string;
position: number;
};
const PERSIST_KEY_WATCH_HISTORY = `watchhistory${window.configId ? `-${window.configId}` : ''}`;

type WatchHistoryStore = {
watchHistory: WatchHistoryItem[];
};

export const WatchHistoryStore = new Store<WatchHistoryStore>({
export const watchHistoryStore = new Store<WatchHistoryStore>({
watchHistory: [],
});
WatchHistoryStore.subscribe(
(state) => state.watchHistory,
(watchHistory) => persist.storeWatchHistory(watchHistory),
);

export const loadWatchHistory = () => {
const watchHistory = persist.loadWatchHistory();
export const initializeWatchHistory = () => {
const localHistory = persist.getItem(PERSIST_KEY_WATCH_HISTORY);
const watchHistory: WatchHistoryItem[] = localHistory ? (localHistory as WatchHistoryItem[]) : [];

return (
watchHistory &&
WatchHistoryStore.update((state) => {
if (watchHistory) {
watchHistoryStore.update((state) => {
state.watchHistory = watchHistory;
})
});
}

return watchHistoryStore.subscribe(
(state) => state.watchHistory,
(watchHistory) => persist.setItem(PERSIST_KEY_WATCH_HISTORY, watchHistory),
);
};

export const useWatchHistoryUpdater = (createWatchHistoryItem: () => WatchHistoryItem | undefined): void => {
useEffect(() => {
const savePosition = () => {
const { watchHistory } = WatchHistoryStore.getRawState();
const { watchHistory } = watchHistoryStore.getRawState();
const item = createWatchHistoryItem();
if (!item) return;

const index = watchHistory.findIndex((historyItem) => historyItem.mediaid === item.mediaid);
if (index > -1) {
WatchHistoryStore.update((state) => {
watchHistoryStore.update((state) => {
state.watchHistory[index] = item;
});
} else {
WatchHistoryStore.update((state) => {
watchHistoryStore.update((state) => {
state.watchHistory.push(item);
});
}
Expand Down
42 changes: 42 additions & 0 deletions src/utils/persist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
*
* Persist util: store items to localStorage
*
*/

const LOCAL_STORAGE_PREFIX = `jwshowcase.`;

const setItem = (key: string, value: unknown) => {
const storageKey = `${LOCAL_STORAGE_PREFIX}${key}`;
const storageValue = JSON.stringify(value);

try {
window.localStorage.setItem(storageKey, storageValue);
} catch (error: unknown) {
console.error(error);
}
};

const getItem = (key: string) => {
const storageKey = `${LOCAL_STORAGE_PREFIX}${key}`;

try {
return parseJSON(window.localStorage.getItem(storageKey));
} catch (error: unknown) {
console.error(error);
}
};

const parseJSON = (value?: string | null): unknown | undefined => {
if (!value) return;

try {
const parsedValue = JSON.parse(value);

return parsedValue;
} catch (error: unknown) {
return;
}
};

export { setItem, getItem };
4 changes: 4 additions & 0 deletions types/watchHistory.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type WatchHistoryItem = {
mediaid: string;
position: number;
};

0 comments on commit 0d9694d

Please sign in to comment.