mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-05-15 03:51:33 +00:00
Merge pull request #645 from Stremio/feat/seek-player-action
feat(player): add seek action and handle seeking player state
This commit is contained in:
commit
9ea6c82619
5 changed files with 65 additions and 22 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -12,7 +12,7 @@
|
||||||
"@babel/runtime": "7.16.0",
|
"@babel/runtime": "7.16.0",
|
||||||
"@sentry/browser": "6.13.3",
|
"@sentry/browser": "6.13.3",
|
||||||
"@stremio/stremio-colors": "5.0.1",
|
"@stremio/stremio-colors": "5.0.1",
|
||||||
"@stremio/stremio-core-web": "0.47.8",
|
"@stremio/stremio-core-web": "0.48.0",
|
||||||
"@stremio/stremio-icons": "5.2.0",
|
"@stremio/stremio-icons": "5.2.0",
|
||||||
"@stremio/stremio-video": "0.0.46",
|
"@stremio/stremio-video": "0.0.46",
|
||||||
"a-color-picker": "1.2.1",
|
"a-color-picker": "1.2.1",
|
||||||
|
|
@ -3131,9 +3131,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@stremio/stremio-core-web": {
|
"node_modules/@stremio/stremio-core-web": {
|
||||||
"version": "0.47.8",
|
"version": "0.48.0",
|
||||||
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.8.tgz",
|
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.0.tgz",
|
||||||
"integrity": "sha512-X5yKSCm5DXR7U6oIO+2kaI1q3TnaWP6df/HFa1RBi/uw+8IYk+FB8GWpryxXyisJTFiUfQgcJDIlHROauaBQkg==",
|
"integrity": "sha512-UEVxb5weAIZ22Hz0iNKM8O1QkALcLShG9AyCe1P2WhZhyiridbwE7MtP5itBtLcLm9f/D6UeRrpUWMCS01n18Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.24.1"
|
"@babel/runtime": "7.24.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
"@babel/runtime": "7.16.0",
|
"@babel/runtime": "7.16.0",
|
||||||
"@sentry/browser": "6.13.3",
|
"@sentry/browser": "6.13.3",
|
||||||
"@stremio/stremio-colors": "5.0.1",
|
"@stremio/stremio-colors": "5.0.1",
|
||||||
"@stremio/stremio-core-web": "0.47.8",
|
"@stremio/stremio-core-web": "0.48.0",
|
||||||
"@stremio/stremio-icons": "5.2.0",
|
"@stremio/stremio-icons": "5.2.0",
|
||||||
"@stremio/stremio-video": "0.0.46",
|
"@stremio/stremio-video": "0.0.46",
|
||||||
"a-color-picker": "1.2.1",
|
"a-color-picker": "1.2.1",
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
return queryParams.has('forceTranscoding');
|
return queryParams.has('forceTranscoding');
|
||||||
}, [queryParams]);
|
}, [queryParams]);
|
||||||
|
|
||||||
const [player, videoParamsChanged, timeChanged, pausedChanged, ended, nextVideo] = usePlayer(urlParams);
|
const [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo] = usePlayer(urlParams);
|
||||||
const [settings, updateSettings] = useSettings();
|
const [settings, updateSettings] = useSettings();
|
||||||
const streamingServer = useStreamingServer();
|
const streamingServer = useStreamingServer();
|
||||||
const statistics = useStatistics(player, streamingServer);
|
const statistics = useStatistics(player, streamingServer);
|
||||||
|
|
@ -42,6 +42,8 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
const routeFocused = useRouteFocused();
|
const routeFocused = useRouteFocused();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
const [seeking, setSeeking] = React.useState(false);
|
||||||
|
|
||||||
const [casting, setCasting] = React.useState(() => {
|
const [casting, setCasting] = React.useState(() => {
|
||||||
return chromecast.active && chromecast.transport.getCastState() === cast.framework.CastState.CONNECTED;
|
return chromecast.active && chromecast.transport.getCastState() === cast.framework.CastState.CONNECTED;
|
||||||
});
|
});
|
||||||
|
|
@ -136,6 +138,7 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
|
|
||||||
const onPlayRequested = React.useCallback(() => {
|
const onPlayRequested = React.useCallback(() => {
|
||||||
video.setProp('paused', false);
|
video.setProp('paused', false);
|
||||||
|
setSeeking(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onPlayRequestedDebounced = React.useCallback(debounce(onPlayRequested, 200), []);
|
const onPlayRequestedDebounced = React.useCallback(debounce(onPlayRequested, 200), []);
|
||||||
|
|
@ -159,7 +162,8 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
|
|
||||||
const onSeekRequested = React.useCallback((time) => {
|
const onSeekRequested = React.useCallback((time) => {
|
||||||
video.setProp('time', time);
|
video.setProp('time', time);
|
||||||
}, []);
|
seek(time, video.state.duration, video.state.manifest?.name);
|
||||||
|
}, [video.state.duration, video.state.manifest]);
|
||||||
|
|
||||||
const onPlaybackSpeedChanged = React.useCallback((rate) => {
|
const onPlaybackSpeedChanged = React.useCallback((rate) => {
|
||||||
video.setProp('playbackSpeed', rate);
|
video.setProp('playbackSpeed', rate);
|
||||||
|
|
@ -342,12 +346,8 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
}, [settings.subtitlesOutlineColor]);
|
}, [settings.subtitlesOutlineColor]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (video.state.time !== null && !isNaN(video.state.time) &&
|
!seeking && timeChanged(video.state.time, video.state.duration, video.state.manifest?.name);
|
||||||
video.state.duration !== null && !isNaN(video.state.duration) &&
|
}, [video.state.time, video.state.duration, video.state.manifest, seeking]);
|
||||||
video.state.manifest !== null && typeof video.state.manifest.name === 'string') {
|
|
||||||
timeChanged(video.state.time, video.state.duration, video.state.manifest.name);
|
|
||||||
}
|
|
||||||
}, [video.state.time, video.state.duration, video.state.manifest]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (video.state.paused !== null) {
|
if (video.state.paused !== null) {
|
||||||
|
|
@ -468,6 +468,7 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
if (!menusOpen && !nextVideoPopupOpen && video.state.paused !== null) {
|
if (!menusOpen && !nextVideoPopupOpen && video.state.paused !== null) {
|
||||||
if (video.state.paused) {
|
if (video.state.paused) {
|
||||||
onPlayRequested();
|
onPlayRequested();
|
||||||
|
setSeeking(false);
|
||||||
} else {
|
} else {
|
||||||
onPauseRequested();
|
onPauseRequested();
|
||||||
}
|
}
|
||||||
|
|
@ -478,6 +479,7 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
case 'ArrowRight': {
|
case 'ArrowRight': {
|
||||||
if (!menusOpen && !nextVideoPopupOpen && video.state.time !== null) {
|
if (!menusOpen && !nextVideoPopupOpen && video.state.time !== null) {
|
||||||
const seekDuration = event.shiftKey ? settings.seekShortTimeDuration : settings.seekTimeDuration;
|
const seekDuration = event.shiftKey ? settings.seekShortTimeDuration : settings.seekTimeDuration;
|
||||||
|
setSeeking(true);
|
||||||
onSeekRequested(video.state.time + seekDuration);
|
onSeekRequested(video.state.time + seekDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -486,6 +488,7 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
case 'ArrowLeft': {
|
case 'ArrowLeft': {
|
||||||
if (!menusOpen && !nextVideoPopupOpen && video.state.time !== null) {
|
if (!menusOpen && !nextVideoPopupOpen && video.state.time !== null) {
|
||||||
const seekDuration = event.shiftKey ? settings.seekShortTimeDuration : settings.seekTimeDuration;
|
const seekDuration = event.shiftKey ? settings.seekShortTimeDuration : settings.seekTimeDuration;
|
||||||
|
setSeeking(true);
|
||||||
onSeekRequested(video.state.time - seekDuration);
|
onSeekRequested(video.state.time - seekDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -553,6 +556,11 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const onKeyUp = (event) => {
|
||||||
|
if (event.code === 'ArrowRight' || event.code === 'ArrowLeft') {
|
||||||
|
setSeeking(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
const onWheel = ({ deltaY }) => {
|
const onWheel = ({ deltaY }) => {
|
||||||
if (deltaY > 0) {
|
if (deltaY > 0) {
|
||||||
if (!menusOpen && video.state.volume !== null) {
|
if (!menusOpen && video.state.volume !== null) {
|
||||||
|
|
@ -566,10 +574,12 @@ const Player = ({ urlParams, queryParams }) => {
|
||||||
};
|
};
|
||||||
if (routeFocused) {
|
if (routeFocused) {
|
||||||
window.addEventListener('keydown', onKeyDown);
|
window.addEventListener('keydown', onKeyDown);
|
||||||
|
window.addEventListener('keyup', onKeyUp);
|
||||||
window.addEventListener('wheel', onWheel);
|
window.addEventListener('wheel', onWheel);
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('keydown', onKeyDown);
|
window.removeEventListener('keydown', onKeyDown);
|
||||||
|
window.removeEventListener('keyup', onKeyUp);
|
||||||
window.removeEventListener('wheel', onWheel);
|
window.removeEventListener('wheel', onWheel);
|
||||||
};
|
};
|
||||||
}, [player.metaItem, player.selected, streamingServer.statistics, settings.seekTimeDuration, settings.seekShortTimeDuration, routeFocused, menusOpen, nextVideoPopupOpen, video.state.paused, video.state.time, video.state.volume, video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks, video.state.playbackSpeed, toggleSubtitlesMenu, toggleInfoMenu, toggleVideosMenu, toggleStatisticsMenu]);
|
}, [player.metaItem, player.selected, streamingServer.statistics, settings.seekTimeDuration, settings.seekShortTimeDuration, routeFocused, menusOpen, nextVideoPopupOpen, video.state.paused, video.state.time, video.state.volume, video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks, video.state.playbackSpeed, toggleSubtitlesMenu, toggleInfoMenu, toggleVideosMenu, toggleStatisticsMenu]);
|
||||||
|
|
|
||||||
11
src/routes/Player/usePlayer.d.ts
vendored
11
src/routes/Player/usePlayer.d.ts
vendored
|
|
@ -1,2 +1,11 @@
|
||||||
declare const usePlayer: (urlParams: UrlParams, videoParams: any) => [Player, (time: number, duration: number, device: string) => void, (paused: boolean) => void, () => void, () => void];
|
declare const usePlayer: (urlParams: UrlParams) => [
|
||||||
|
Player,
|
||||||
|
videoParamsChanged: (videoParams: { hash: string | null, size: number | null, filename: string | null }) => void,
|
||||||
|
timeChanged: (time: number, duration: number, device: string) => void,
|
||||||
|
seek: (time: number, duration: number, device: string) => void,
|
||||||
|
pausedChanged: (paused: boolean) => void, () => void, () => void,
|
||||||
|
ended: () => void,
|
||||||
|
nextVideo: () => void,
|
||||||
|
];
|
||||||
|
|
||||||
export = usePlayer;
|
export = usePlayer;
|
||||||
|
|
|
||||||
|
|
@ -96,14 +96,37 @@ const usePlayer = (urlParams) => {
|
||||||
}, 'player');
|
}, 'player');
|
||||||
}, []);
|
}, []);
|
||||||
const timeChanged = React.useCallback((time, duration, device) => {
|
const timeChanged = React.useCallback((time, duration, device) => {
|
||||||
core.transport.dispatch({
|
if (typeof time === 'number' && typeof duration === 'number' && typeof device === 'string') {
|
||||||
action: 'Player',
|
core.transport.dispatch({
|
||||||
args: {
|
action: 'Player',
|
||||||
action: 'TimeChanged',
|
args: {
|
||||||
args: { time, duration, device }
|
action: 'TimeChanged',
|
||||||
}
|
args: {
|
||||||
}, 'player');
|
time: Math.round(time),
|
||||||
|
duration,
|
||||||
|
device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 'player');
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const seek = React.useCallback((time, duration, device) => {
|
||||||
|
if (typeof time === 'number' && typeof duration === 'number' && typeof device === 'string') {
|
||||||
|
core.transport.dispatch({
|
||||||
|
action: 'Player',
|
||||||
|
args: {
|
||||||
|
action: 'Seek',
|
||||||
|
args: {
|
||||||
|
time: Math.round(time),
|
||||||
|
duration,
|
||||||
|
device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 'player');
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const ended = React.useCallback(() => {
|
const ended = React.useCallback(() => {
|
||||||
core.transport.dispatch({
|
core.transport.dispatch({
|
||||||
action: 'Player',
|
action: 'Player',
|
||||||
|
|
@ -129,8 +152,9 @@ const usePlayer = (urlParams) => {
|
||||||
}
|
}
|
||||||
}, 'player');
|
}, 'player');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const player = useModelState({ model: 'player', action, map });
|
const player = useModelState({ model: 'player', action, map });
|
||||||
return [player, videoParamsChanged, timeChanged, pausedChanged, ended, nextVideo];
|
return [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo];
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = usePlayer;
|
module.exports = usePlayer;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue