From a726ffb60d172f261ddc71b34788c2e33cc0248a Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Fri, 6 Dec 2024 14:39:16 +0200 Subject: [PATCH 01/94] feat: init side drawer component --- src/routes/Player/ControlBar/ControlBar.js | 18 ++-- src/routes/Player/Player.js | 91 ++++++---------- src/routes/Player/SideDrawer/SideDrawer.less | 32 ++++++ src/routes/Player/SideDrawer/SideDrawer.tsx | 106 +++++++++++++++++++ src/routes/Player/styles.less | 81 ++++++++++++++ src/types/MetaItem.d.ts | 2 +- src/types/Video.d.ts | 5 + 7 files changed, 268 insertions(+), 67 deletions(-) create mode 100644 src/routes/Player/SideDrawer/SideDrawer.less create mode 100644 src/routes/Player/SideDrawer/SideDrawer.tsx diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index a68a542bf..505ce982f 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -35,9 +35,9 @@ const ControlBar = ({ onVolumeChangeRequested, onSeekRequested, onToggleSubtitlesMenu, - onToggleInfoMenu, + // onToggleInfoMenu, onToggleSpeedMenu, - onToggleVideosMenu, + onToggleSideDrawer, onToggleOptionsMenu, onToggleStatisticsMenu, ...props @@ -48,9 +48,9 @@ const ControlBar = ({ const onSubtitlesButtonMouseDown = React.useCallback((event) => { event.nativeEvent.subtitlesMenuClosePrevented = true; }, []); - const onInfoButtonMouseDown = React.useCallback((event) => { - event.nativeEvent.infoMenuClosePrevented = true; - }, []); + // const onInfoButtonMouseDown = React.useCallback((event) => { + // event.nativeEvent.infoMenuClosePrevented = true; + // }, []); const onSpeedButtonMouseDown = React.useCallback((event) => { event.nativeEvent.speedMenuClosePrevented = true; }, []); @@ -151,9 +151,9 @@ const ControlBar = ({ - + */} @@ -162,7 +162,7 @@ const ControlBar = ({ { metaItem?.content?.videos?.length > 0 ? - : @@ -202,7 +202,7 @@ ControlBar.propTypes = { onToggleSubtitlesMenu: PropTypes.func, onToggleInfoMenu: PropTypes.func, onToggleSpeedMenu: PropTypes.func, - onToggleVideosMenu: PropTypes.func, + onToggleSideDrawer: PropTypes.func, onToggleOptionsMenu: PropTypes.func, onToggleStatisticsMenu: PropTypes.func, }; diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 5ace96f77..1a6b238c0 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -15,9 +15,7 @@ const Error = require('./Error'); const ControlBar = require('./ControlBar'); const NextVideoPopup = require('./NextVideoPopup'); const StatisticsMenu = require('./StatisticsMenu'); -const InfoMenu = require('./InfoMenu'); const OptionsMenu = require('./OptionsMenu'); -const VideosMenu = require('./VideosMenu'); const SubtitlesMenu = require('./SubtitlesMenu'); const SpeedMenu = require('./SpeedMenu'); const usePlayer = require('./usePlayer'); @@ -26,6 +24,8 @@ const useStatistics = require('./useStatistics'); const useVideo = require('./useVideo'); const styles = require('./styles'); const Video = require('./Video'); +const { default: SideDrawer } = require('./SideDrawer/SideDrawer'); +const { default: Icon } = require('@stremio/stremio-icons/react'); const Player = ({ urlParams, queryParams }) => { const { t } = useTranslation(); @@ -54,27 +54,24 @@ const Player = ({ urlParams, queryParams }) => { const [optionsMenuOpen, , closeOptionsMenu, toggleOptionsMenu] = useBinaryState(false); const [subtitlesMenuOpen, , closeSubtitlesMenu, toggleSubtitlesMenu] = useBinaryState(false); - const [infoMenuOpen, , closeInfoMenu, toggleInfoMenu] = useBinaryState(false); const [speedMenuOpen, , closeSpeedMenu, toggleSpeedMenu] = useBinaryState(false); - const [videosMenuOpen, , closeVideosMenu, toggleVideosMenu] = useBinaryState(false); const [statisticsMenuOpen, , closeStatisticsMenu, toggleStatisticsMenu] = useBinaryState(false); const [nextVideoPopupOpen, openNextVideoPopup, closeNextVideoPopup] = useBinaryState(false); + const [sideDrawerOpen, openSideDrawer, closeSideDrawer, toggleSideDrawer] = useBinaryState(false); const menusOpen = React.useMemo(() => { - return optionsMenuOpen || subtitlesMenuOpen || infoMenuOpen || speedMenuOpen || videosMenuOpen || statisticsMenuOpen; - }, [optionsMenuOpen, subtitlesMenuOpen, infoMenuOpen, speedMenuOpen, videosMenuOpen, statisticsMenuOpen]); + return optionsMenuOpen || subtitlesMenuOpen || speedMenuOpen || statisticsMenuOpen; + }, [optionsMenuOpen, subtitlesMenuOpen, speedMenuOpen, statisticsMenuOpen]); const closeMenus = React.useCallback(() => { closeOptionsMenu(); closeSubtitlesMenu(); - closeInfoMenu(); closeSpeedMenu(); - closeVideosMenu(); closeStatisticsMenu(); }, []); const overlayHidden = React.useMemo(() => { - return immersed && !casting && video.state.paused !== null && !video.state.paused && !menusOpen && !nextVideoPopupOpen; + return immersed && !casting && video.state.paused !== null && !video.state.paused && !menusOpen && !nextVideoPopupOpen && !sideDrawerOpen; }, [immersed, casting, video.state.paused, menusOpen, nextVideoPopupOpen]); const nextVideoPopupDismissed = React.useRef(false); @@ -237,15 +234,9 @@ const Player = ({ urlParams, queryParams }) => { if (!event.nativeEvent.subtitlesMenuClosePrevented) { closeSubtitlesMenu(); } - if (!event.nativeEvent.infoMenuClosePrevented) { - closeInfoMenu(); - } if (!event.nativeEvent.speedMenuClosePrevented) { closeSpeedMenu(); } - if (!event.nativeEvent.videosMenuClosePrevented) { - closeVideosMenu(); - } if (!event.nativeEvent.statisticsMenuClosePrevented) { closeStatisticsMenu(); } @@ -412,19 +403,19 @@ const Player = ({ urlParams, queryParams }) => { } }, [video.state.audioTracks, video.state.subtitlesTracks, video.state.extraSubtitlesTracks]); - React.useEffect(() => { - if (player.metaItem === null || player.metaItem.type !== 'Ready') { - closeInfoMenu(); - closeVideosMenu(); - } - }, [player.metaItem]); - React.useEffect(() => { if (video.state.playbackSpeed === null) { closeSpeedMenu(); } }, [video.state.playbackSpeed]); + React.useEffect(() => { + if (sideDrawerOpen) { + closeMenus(); + setImmersed(true); + } + }, [sideDrawerOpen]); + React.useEffect(() => { const toastFilter = (item) => item?.dataset?.type === 'CoreEvent'; toast.addFilter(toastFilter); @@ -521,7 +512,7 @@ const Player = ({ urlParams, queryParams }) => { case 'KeyI': { closeMenus(); if (player.metaItem !== null && player.metaItem.type === 'Ready') { - toggleInfoMenu(); + toggleSideDrawer(); } break; @@ -534,14 +525,6 @@ const Player = ({ urlParams, queryParams }) => { break; } - case 'KeyV': { - closeMenus(); - if (player.metaItem !== null && player.metaItem.type === 'Ready' && player.metaItem?.content?.videos?.length > 0) { - toggleVideosMenu(); - } - - break; - } case 'KeyD': { closeMenus(); if (streamingServer.statistics !== null && streamingServer.statistics.type !== 'Err' && player.selected && typeof player.selected.stream.infoHash === 'string' && typeof player.selected.stream.fileIdx === 'number') { @@ -563,11 +546,11 @@ const Player = ({ urlParams, queryParams }) => { }; const onWheel = ({ deltaY }) => { if (deltaY > 0) { - if (!menusOpen && video.state.volume !== null) { + if (!menusOpen && !sideDrawerOpen && video.state.volume !== null) { onVolumeChangeRequested(video.state.volume - 5); } } else { - if (!menusOpen && video.state.volume !== null) { + if (!menusOpen && !sideDrawerOpen && video.state.volume !== null) { onVolumeChangeRequested(video.state.volume + 5); } } @@ -582,7 +565,7 @@ const Player = ({ urlParams, queryParams }) => { window.removeEventListener('keyup', onKeyUp); 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, toggleStatisticsMenu, toggleSideDrawer]); React.useEffect(() => { video.events.on('error', onError); @@ -691,10 +674,9 @@ const Player = ({ urlParams, queryParams }) => { onSeekRequested={onSeekRequested} onToggleOptionsMenu={toggleOptionsMenu} onToggleSubtitlesMenu={toggleSubtitlesMenu} - onToggleInfoMenu={toggleInfoMenu} onToggleSpeedMenu={toggleSpeedMenu} - onToggleVideosMenu={toggleVideosMenu} onToggleStatisticsMenu={toggleStatisticsMenu} + onToggleSideDrawer={toggleSideDrawer} onMouseMove={onBarMouseMove} onMouseOver={onBarMouseMove} /> @@ -719,6 +701,22 @@ const Player = ({ urlParams, queryParams }) => { : null } + { + player.metaItem !== null && player.metaItem.type === 'Ready' ? + <> +
+ +
+ + + : null + } { subtitlesMenuOpen ? { : null } - { - infoMenuOpen ? - - : - null - } { speedMenuOpen ? { : null } - { - videosMenuOpen ? - - : - null - } { optionsMenuOpen ? void; + sideDrawerOpen: boolean; +}; + +const SideDrawer = ({ seriesInfo, className, closeSideBar, sideDrawerOpen, ...props }: Props) => { + const [season, setSeason] = React.useState(seriesInfo?.season); + const metaItem = React.useMemo(() => { + return props.metaItem !== null && Array.isArray(props.metaItem.videos) && seriesInfo ? + { + ...props.metaItem, + links: props.metaItem.links.filter(({ category }) => category === CONSTANTS.SHARE_LINK_CATEGORY) + } + : + props.metaItem; + }, [props.metaItem]); + const videos = React.useMemo(() => { + return props.metaItem && Array.isArray(props.metaItem.videos) ? + props.metaItem.videos.filter((video) => video.season === season) + : + props.metaItem.videos; + }, [props.metaItem, season]); + const seasons = React.useMemo(() => { + return props.metaItem && props.metaItem.videos + .map(({ season }) => season) + .filter((season, index, seasons) => { + return season !== null && season !== undefined && + !isNaN(season) && + typeof season === 'number' && + seasons.indexOf(season) === index; + }) + .sort((a, b) => (a || Number.MAX_SAFE_INTEGER) - (b || Number.MAX_SAFE_INTEGER)); + }, [props.metaItem.videos]); + + const seasonOnSelect = React.useCallback((event: { value: string }) => { + setSeason(parseInt(event.value)); + }, []); + + return ( + <> +
+
+
+ { + metaItem !== null ? + + : + null + } +
+ { + videos !== null && seriesInfo ? + <> + +
+ {videos.map((video, index) => ( +
+ + : null + } + +
+ + ); +}; + +export default SideDrawer; diff --git a/src/routes/Player/styles.less b/src/routes/Player/styles.less index 8bff42fe1..9f48bbc91 100644 --- a/src/routes/Player/styles.less +++ b/src/routes/Player/styles.less @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; +@import (reference) '~stremio/common/screen-sizes.less'; :import('~stremio/common/Slider/styles.less') { active-slider-within: active-slider-within; @@ -112,5 +113,85 @@ html:not(.active-slider-within) { backdrop-filter: blur(15px); overflow: auto; } + + &.side-drawer-button { + right: -4rem; + top: 50%; + left: initial; + bottom: initial; + height: 12.5rem; + width: 7.5rem; + transform: translateY(-50%); + display: flex; + justify-content: center; + align-items: center; + background-color: var(--modal-background-color); + cursor: pointer; + border-top-left-radius: 50%; + border-bottom-left-radius: 50%; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + + .icon { + width: 2.5rem; + height: 2.5rem; + color: var(--primary-foreground-color); + opacity: 0.6; + margin-right: 4rem; + transition: all 0.3s ease-in-out; + + } + + &.open { + display: none; + } + + &:hover { + .icon { + opacity: 1; + } + } + } + + &.side-drawer-layer { + top: 0; + right: 0; + left: initial; + bottom: initial; + max-width: 30%; + height: 100vh; + border-top-left-radius: var(--border-radius); + border-bottom-left-radius: var(--border-radius); + background-color: var(--modal-background-color); + box-shadow: 0 1.35rem 2.7rem var(--color-background-dark5-40), + 0 1.1rem 0.85rem var(--color-background-dark5-20); + backdrop-filter: blur(15px); + overflow: visible; + padding: 1rem; + z-index: 1; + transition: transform 0.3s ease-in-out; + transform: translateX(100%); + + &.open { + transform: translateX(0); + } + + @media screen and (max-width: @small) { + max-width: 40%; + } + + @media screen and (max-width: @xsmall) { + max-width: 50%; + } + + @media screen and (max-width: @xxsmall) { + max-width: 60%; + } + + @media screen and (max-width: @minimum) { + max-width: 70%; + } + } } } \ No newline at end of file diff --git a/src/types/MetaItem.d.ts b/src/types/MetaItem.d.ts index 0d692a580..56e7db3c7 100644 --- a/src/types/MetaItem.d.ts +++ b/src/types/MetaItem.d.ts @@ -15,7 +15,7 @@ type MetaItemPreview = { posterShape: PosterShape, releaseInfo: string | null, runtime: string | null, - released: string | null, + released: Date | null | undefined, trailerStreams: TrailerStream[], links: Link[], behaviorHints: BehaviorHints, diff --git a/src/types/Video.d.ts b/src/types/Video.d.ts index 92bc704f5..7ed3d0fac 100644 --- a/src/types/Video.d.ts +++ b/src/types/Video.d.ts @@ -14,4 +14,9 @@ type Video = { episode?: number, streams: Stream[], trailerStreams: TrailerStream[], + watched: boolean, + progress: number, + upcoming: boolean, + deepLinks: VideoDeepLinks, + scheduled: boolean, }; From a81792ea5d6c1397330ac65fc42f95bba8d2ce85 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Fri, 6 Dec 2024 14:45:25 +0200 Subject: [PATCH 02/94] remove: InfoMenu and VideosMenu --- src/routes/Player/ControlBar/ControlBar.js | 8 --- src/routes/Player/InfoMenu/InfoMenu.js | 77 ---------------------- src/routes/Player/InfoMenu/index.js | 5 -- src/routes/Player/InfoMenu/styles.less | 10 --- src/routes/Player/VideosMenu/VideosMenu.js | 51 -------------- src/routes/Player/VideosMenu/index.js | 5 -- src/routes/Player/VideosMenu/styles.less | 7 -- 7 files changed, 163 deletions(-) delete mode 100644 src/routes/Player/InfoMenu/InfoMenu.js delete mode 100644 src/routes/Player/InfoMenu/index.js delete mode 100644 src/routes/Player/InfoMenu/styles.less delete mode 100644 src/routes/Player/VideosMenu/VideosMenu.js delete mode 100644 src/routes/Player/VideosMenu/index.js delete mode 100644 src/routes/Player/VideosMenu/styles.less diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 505ce982f..1d1330539 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -35,7 +35,6 @@ const ControlBar = ({ onVolumeChangeRequested, onSeekRequested, onToggleSubtitlesMenu, - // onToggleInfoMenu, onToggleSpeedMenu, onToggleSideDrawer, onToggleOptionsMenu, @@ -48,9 +47,6 @@ const ControlBar = ({ const onSubtitlesButtonMouseDown = React.useCallback((event) => { event.nativeEvent.subtitlesMenuClosePrevented = true; }, []); - // const onInfoButtonMouseDown = React.useCallback((event) => { - // event.nativeEvent.infoMenuClosePrevented = true; - // }, []); const onSpeedButtonMouseDown = React.useCallback((event) => { event.nativeEvent.speedMenuClosePrevented = true; }, []); @@ -151,9 +147,6 @@ const ControlBar = ({ - {/* */} @@ -200,7 +193,6 @@ ControlBar.propTypes = { onVolumeChangeRequested: PropTypes.func, onSeekRequested: PropTypes.func, onToggleSubtitlesMenu: PropTypes.func, - onToggleInfoMenu: PropTypes.func, onToggleSpeedMenu: PropTypes.func, onToggleSideDrawer: PropTypes.func, onToggleOptionsMenu: PropTypes.func, diff --git a/src/routes/Player/InfoMenu/InfoMenu.js b/src/routes/Player/InfoMenu/InfoMenu.js deleted file mode 100644 index eec5e7286..000000000 --- a/src/routes/Player/InfoMenu/InfoMenu.js +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -// const Stream = require('stremio/routes/MetaDetails/StreamsList/Stream'); -// const AddonDetails = require('stremio/common/AddonDetailsModal/AddonDetails'); -const { MetaPreview, CONSTANTS } = require('stremio/common'); -const styles = require('./styles'); - -const InfoMenu = ({ className, ...props }) => { - const metaItem = React.useMemo(() => { - return props.metaItem !== null ? - { - ...props.metaItem, - links: props.metaItem.links.filter(({ category }) => category === CONSTANTS.SHARE_LINK_CATEGORY) - } - : - null; - }, [props.metaItem]); - const onMouseDown = React.useCallback((event) => { - event.nativeEvent.infoMenuClosePrevented = true; - }, []); - return ( -
- { - metaItem !== null ? - - : - null - } - {/* { - props.stream !== null ? - - : - null - } */} - {/* { - props.addon !== null ? - - : - null - } */} -
- ); -}; - -InfoMenu.propTypes = { - className: PropTypes.string, - metaItem: PropTypes.object, - addon: PropTypes.object, - stream: PropTypes.object -}; - -module.exports = InfoMenu; diff --git a/src/routes/Player/InfoMenu/index.js b/src/routes/Player/InfoMenu/index.js deleted file mode 100644 index 8dae65490..000000000 --- a/src/routes/Player/InfoMenu/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const InfoMenu = require('./InfoMenu'); - -module.exports = InfoMenu; diff --git a/src/routes/Player/InfoMenu/styles.less b/src/routes/Player/InfoMenu/styles.less deleted file mode 100644 index 32a72b77d..000000000 --- a/src/routes/Player/InfoMenu/styles.less +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -.info-menu-container { - width: 30rem; - padding: 2rem; - - .stream { - pointer-events: none; - } -} \ No newline at end of file diff --git a/src/routes/Player/VideosMenu/VideosMenu.js b/src/routes/Player/VideosMenu/VideosMenu.js deleted file mode 100644 index 9d5819db7..000000000 --- a/src/routes/Player/VideosMenu/VideosMenu.js +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const Video = require('../../MetaDetails/VideosList/Video'); -const styles = require('./styles'); - -const VideosMenu = ({ className, metaItem, seriesInfo }) => { - const onMouseDown = React.useCallback((event) => { - event.nativeEvent.videosMenuClosePrevented = true; - }, []); - const videos = React.useMemo(() => { - return seriesInfo && typeof seriesInfo.season === 'number' && Array.isArray(metaItem.videos) ? - metaItem.videos.filter(({ season }) => season === seriesInfo.season) - : - metaItem.videos; - }, [metaItem, seriesInfo]); - return ( -
- { - videos.map((video, index) => ( -
- ); -}; - -VideosMenu.propTypes = { - className: PropTypes.string, - metaItem: PropTypes.object, - seriesInfo: PropTypes.shape({ - season: PropTypes.number, - episode: PropTypes.number, - }), -}; - -module.exports = VideosMenu; diff --git a/src/routes/Player/VideosMenu/index.js b/src/routes/Player/VideosMenu/index.js deleted file mode 100644 index c2fa21666..000000000 --- a/src/routes/Player/VideosMenu/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const VideosMenu = require('./VideosMenu'); - -module.exports = VideosMenu; diff --git a/src/routes/Player/VideosMenu/styles.less b/src/routes/Player/VideosMenu/styles.less deleted file mode 100644 index 8cc7e4805..000000000 --- a/src/routes/Player/VideosMenu/styles.less +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -.videos-menu-container { - width: 30rem; - padding: 1rem; - padding-bottom: 0; -} \ No newline at end of file From 61c578160bd77f592da06bfb9086ac5792c95907 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Fri, 6 Dec 2024 14:48:50 +0200 Subject: [PATCH 03/94] refactor(SideDrawer): simplify the conditionals --- src/routes/Player/SideDrawer/SideDrawer.tsx | 38 ++++++++------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/routes/Player/SideDrawer/SideDrawer.tsx b/src/routes/Player/SideDrawer/SideDrawer.tsx index faddc91b9..56a2a8cf6 100644 --- a/src/routes/Player/SideDrawer/SideDrawer.tsx +++ b/src/routes/Player/SideDrawer/SideDrawer.tsx @@ -17,7 +17,7 @@ type Props = { const SideDrawer = ({ seriesInfo, className, closeSideBar, sideDrawerOpen, ...props }: Props) => { const [season, setSeason] = React.useState(seriesInfo?.season); const metaItem = React.useMemo(() => { - return props.metaItem !== null && Array.isArray(props.metaItem.videos) && seriesInfo ? + return seriesInfo ? { ...props.metaItem, links: props.metaItem.links.filter(({ category }) => category === CONSTANTS.SHARE_LINK_CATEGORY) @@ -26,19 +26,16 @@ const SideDrawer = ({ seriesInfo, className, closeSideBar, sideDrawerOpen, ...pr props.metaItem; }, [props.metaItem]); const videos = React.useMemo(() => { - return props.metaItem && Array.isArray(props.metaItem.videos) ? + return Array.isArray(props.metaItem.videos) ? props.metaItem.videos.filter((video) => video.season === season) : props.metaItem.videos; }, [props.metaItem, season]); const seasons = React.useMemo(() => { - return props.metaItem && props.metaItem.videos + return props.metaItem.videos .map(({ season }) => season) .filter((season, index, seasons) => { - return season !== null && season !== undefined && - !isNaN(season) && - typeof season === 'number' && - seasons.indexOf(season) === index; + return seasons.indexOf(season) === index; }) .sort((a, b) => (a || Number.MAX_SAFE_INTEGER) - (b || Number.MAX_SAFE_INTEGER)); }, [props.metaItem.videos]); @@ -52,24 +49,19 @@ const SideDrawer = ({ seriesInfo, className, closeSideBar, sideDrawerOpen, ...pr
- { - metaItem !== null ? - - : - null - } +
{ - videos !== null && seriesInfo ? + seriesInfo ? <> Date: Fri, 6 Dec 2024 15:37:23 +0200 Subject: [PATCH 04/94] refactor: simlifications, fix arrows --- .../MetaDetails/VideosList/SeasonsBar/styles.less | 4 ---- src/routes/Player/Player.js | 6 +++--- src/routes/Player/SideDrawer/SideDrawer.tsx | 14 +++++++------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less b/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less index f030385b4..b725e5b81 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less @@ -36,10 +36,6 @@ background-color: var(--overlay-color); } - &:focus { - background-color: var(--primary-foreground-color); - } - &>:first-child { margin-right: 0.5rem; } diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 1a6b238c0..03fe5cbcc 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -71,7 +71,7 @@ const Player = ({ urlParams, queryParams }) => { }, []); const overlayHidden = React.useMemo(() => { - return immersed && !casting && video.state.paused !== null && !video.state.paused && !menusOpen && !nextVideoPopupOpen && !sideDrawerOpen; + return immersed && !casting && video.state.paused !== null && !video.state.paused && !menusOpen && !nextVideoPopupOpen; }, [immersed, casting, video.state.paused, menusOpen, nextVideoPopupOpen]); const nextVideoPopupDismissed = React.useRef(false); @@ -486,14 +486,14 @@ const Player = ({ urlParams, queryParams }) => { break; } case 'ArrowUp': { - if (!menusOpen && !nextVideoPopupOpen && video.state.volume !== null) { + if (!menusOpen && !nextVideoPopupOpen && !sideDrawerOpen && video.state.volume !== null) { onVolumeChangeRequested(video.state.volume + 5); } break; } case 'ArrowDown': { - if (!menusOpen && !nextVideoPopupOpen && video.state.volume !== null) { + if (!menusOpen && !nextVideoPopupOpen && !sideDrawerOpen && video.state.volume !== null) { onVolumeChangeRequested(video.state.volume - 5); } diff --git a/src/routes/Player/SideDrawer/SideDrawer.tsx b/src/routes/Player/SideDrawer/SideDrawer.tsx index 56a2a8cf6..cc43e2fb8 100644 --- a/src/routes/Player/SideDrawer/SideDrawer.tsx +++ b/src/routes/Player/SideDrawer/SideDrawer.tsx @@ -1,10 +1,10 @@ import React from 'react'; +import { CONSTANTS } from 'stremio/common'; import MetaPreview from 'stremio/common/MetaPreview/MetaPreview'; import Video from '../../MetaDetails/VideosList/Video/Video'; -import styles from './SideDrawer.less'; -import classNames from 'classnames'; -import { CONSTANTS } from 'stremio/common'; import SeasonsBar from 'stremio/routes/MetaDetails/VideosList/SeasonsBar'; +import classNames from 'classnames'; +import styles from './SideDrawer.less'; type Props = { seriesInfo: any; @@ -26,11 +26,11 @@ const SideDrawer = ({ seriesInfo, className, closeSideBar, sideDrawerOpen, ...pr props.metaItem; }, [props.metaItem]); const videos = React.useMemo(() => { - return Array.isArray(props.metaItem.videos) ? - props.metaItem.videos.filter((video) => video.season === season) + return Array.isArray(metaItem.videos) ? + metaItem.videos.filter((video) => video.season === season) : - props.metaItem.videos; - }, [props.metaItem, season]); + metaItem.videos; + }, [metaItem, season]); const seasons = React.useMemo(() => { return props.metaItem.videos .map(({ season }) => season) From 8098bc5c33e23344e488b1d56cb9c34bb5a7dce2 Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 8 Dec 2024 13:57:40 +0100 Subject: [PATCH 05/94] fix: mark video as watched on player --- .../VideosList => common}/Video/Video.js | 20 +++++-------- .../VideoPlaceholder/VideoPlaceholder.js | 0 .../Video/VideoPlaceholder/index.js | 0 .../Video/VideoPlaceholder/styles.less | 0 .../VideosList => common}/Video/index.js | 0 .../VideosList => common}/Video/styles.less | 0 src/common/index.js | 2 ++ .../MetaDetails/VideosList/VideosList.js | 28 ++++++++++-------- src/routes/Player/Player.js | 9 +++--- src/routes/Player/VideosMenu/VideosMenu.js | 29 ++++++++++++------- 10 files changed, 48 insertions(+), 40 deletions(-) rename src/{routes/MetaDetails/VideosList => common}/Video/Video.js (94%) rename src/{routes/MetaDetails/VideosList => common}/Video/VideoPlaceholder/VideoPlaceholder.js (100%) rename src/{routes/MetaDetails/VideosList => common}/Video/VideoPlaceholder/index.js (100%) rename src/{routes/MetaDetails/VideosList => common}/Video/VideoPlaceholder/styles.less (100%) rename src/{routes/MetaDetails/VideosList => common}/Video/index.js (100%) rename src/{routes/MetaDetails/VideosList => common}/Video/styles.less (100%) diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/common/Video/Video.js similarity index 94% rename from src/routes/MetaDetails/VideosList/Video/Video.js rename to src/common/Video/Video.js index 25b67aae9..f74b994eb 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/common/Video/Video.js @@ -4,15 +4,16 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { t } = require('i18next'); -const { useServices } = require('stremio/services'); const { useRouteFocused } = require('stremio-router'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { Button, Image, Popup, useBinaryState } = require('stremio/common'); +const Button = require('stremio/common/Button'); +const Image = require('stremio/common/Image'); +const Popup = require('stremio/common/Popup'); +const useBinaryState = require('stremio/common/useBinaryState'); const VideoPlaceholder = require('./VideoPlaceholder'); const styles = require('./styles'); -const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, deepLinks, ...props }) => { - const { core } = useServices(); +const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, deepLinks, onMarkVideoAsWatched, ...props }) => { const routeFocused = useRouteFocused(); const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false); const popupLabelOnMouseUp = React.useCallback((event) => { @@ -49,13 +50,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w event.preventDefault(); event.stopPropagation(); closeMenu(); - core.transport.dispatch({ - action: 'MetaDetails', - args: { - action: 'MarkVideoAsWatched', - args: [{ id, released }, !watched] - } - }); + onMarkVideoAsWatched({ id, released }, watched); }, [id, released, watched]); const videoButtonOnClick = React.useCallback(() => { if (deepLinks) { @@ -198,7 +193,8 @@ Video.propTypes = { deepLinks: PropTypes.shape({ metaDetailsStreams: PropTypes.string, player: PropTypes.string - }) + }), + onMarkVideoAsWatched: PropTypes.func, }; module.exports = Video; diff --git a/src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js b/src/common/Video/VideoPlaceholder/VideoPlaceholder.js similarity index 100% rename from src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js rename to src/common/Video/VideoPlaceholder/VideoPlaceholder.js diff --git a/src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/index.js b/src/common/Video/VideoPlaceholder/index.js similarity index 100% rename from src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/index.js rename to src/common/Video/VideoPlaceholder/index.js diff --git a/src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/styles.less b/src/common/Video/VideoPlaceholder/styles.less similarity index 100% rename from src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/styles.less rename to src/common/Video/VideoPlaceholder/styles.less diff --git a/src/routes/MetaDetails/VideosList/Video/index.js b/src/common/Video/index.js similarity index 100% rename from src/routes/MetaDetails/VideosList/Video/index.js rename to src/common/Video/index.js diff --git a/src/routes/MetaDetails/VideosList/Video/styles.less b/src/common/Video/styles.less similarity index 100% rename from src/routes/MetaDetails/VideosList/Video/styles.less rename to src/common/Video/styles.less diff --git a/src/common/index.js b/src/common/index.js index 0605a3f9b..45eb0ef41 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -29,6 +29,7 @@ const Slider = require('./Slider'); const { default: TextInput } = require('./TextInput'); const { ToastProvider, useToast } = require('./Toast'); const { TooltipProvider, Tooltip } = require('./Tooltips'); +const Video = require('./Video'); const comparatorWithPriorities = require('./comparatorWithPriorities'); const CONSTANTS = require('./CONSTANTS'); const { withCoreSuspender, useCoreSuspender } = require('./CoreSuspender'); @@ -83,6 +84,7 @@ module.exports = { useToast, TooltipProvider, Tooltip, + Video, comparatorWithPriorities, CONSTANTS, withCoreSuspender, diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 6013e4f01..3a446b44f 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -4,12 +4,13 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { t } = require('i18next'); -const { Image, SearchBar, Toggle } = require('stremio/common'); +const { useServices } = require('stremio/services'); +const { Image, SearchBar, Toggle, Video } = require('stremio/common'); const SeasonsBar = require('./SeasonsBar'); -const Video = require('./Video'); const styles = require('./styles'); const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, toggleNotifications }) => { + const { core } = useServices(); const showNotificationsToggle = React.useMemo(() => { return metaItem?.content?.content?.inLibrary && metaItem?.content?.content?.videos?.length; }, [metaItem]); @@ -59,6 +60,17 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, const searchInputOnChange = React.useCallback((event) => { setSearch(event.currentTarget.value); }, []); + + const onMarkVideoAsWatched = (video, watched) => { + core.transport.dispatch({ + action: 'MetaDetails', + args: { + action: 'MarkVideoAsWatched', + args: [video, !watched] + } + }); + }; + return (
{ @@ -120,16 +132,8 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, .map((video, index) => (