diff --git a/package-lock.json b/package-lock.json index 840007364..2af6603ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,8 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/streming-server-urls-bucket/dev/stremio-stremio-core-web-0.47.8.tgz", - "@stremio/stremio-icons": "5.4.0", + "@stremio/stremio-core-web": "0.47.8", + "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.46", "a-color-picker": "1.2.1", "bowser": "2.11.0", @@ -3132,9 +3132,8 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.8", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/streming-server-urls-bucket/dev/stremio-stremio-core-web-0.47.8.tgz", - "license": "MIT", - "integrity": "sha512-Y9o1ax6TJuYB9GYeXuRjMgyt9bpORLhzgzU2+ie2b1nIa9+5IS+jCWhgJFud35Io479GZJNVUeP83KxVktbuNg==", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.8.tgz", + "integrity": "sha512-X5yKSCm5DXR7U6oIO+2kaI1q3TnaWP6df/HFa1RBi/uw+8IYk+FB8GWpryxXyisJTFiUfQgcJDIlHROauaBQkg==", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index fe6ece826..727c152fa 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -94,7 +94,7 @@ const EXTERNAL_PLAYERS = [ }, ]; -const WHITELISTED_HOSTS = ['stremio.com', 'strem.io', 'stremio.zendesk.com', 'google.com', 'youtube.com', 'twitch.tv', 'twitter.com', 'netflix.com', 'adex.network', 'amazon.com', 'forms.gle']; +const WHITELISTED_HOSTS = ['stremio.com', 'strem.io', 'stremio.zendesk.com', 'google.com', 'youtube.com', 'twitch.tv', 'twitter.com', 'x.com', 'netflix.com', 'adex.network', 'amazon.com', 'forms.gle']; module.exports = { CHROMECAST_RECEIVER_APP_ID, diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 52d0a2513..1efa6ea6e 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -70,7 +70,7 @@ const ModalDialog = ({ className, title, buttons, children, dataset, onCloseRequ : null } -
+
{children}
{ diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 9aafca16a..bde17932d 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -67,6 +67,7 @@ .modal-dialog-content { z-index: 1; position: relative; + overflow-y: auto; .title-container { flex: 1 0 auto; @@ -78,7 +79,7 @@ color: var(--primary-foreground-color); } - .modal-dialog-content { + .body-container { flex: 1; align-self: stretch; overflow-y: auto; @@ -157,9 +158,11 @@ z-index: 0; padding: 0 1.5rem; - .buttons-container { - flex-direction: column; - gap: 1rem; + .modal-dialog-content { + .buttons-container { + flex-direction: column; + gap: 1rem; + } } } diff --git a/src/common/Multiselect/styles.less b/src/common/Multiselect/styles.less index 31b44182a..b82fd06c5 100644 --- a/src/common/Multiselect/styles.less +++ b/src/common/Multiselect/styles.less @@ -27,6 +27,9 @@ max-height: 2.4em; font-weight: 500; color: var(--primary-foreground-color); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .icon { diff --git a/src/routes/MetaDetails/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less index 4136c3a63..22b2abc61 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/styles.less @@ -58,7 +58,6 @@ .addon-name { width: 7rem; - max-height: 3.6em; font-size: 1.1rem; text-align: left; color: var(--primary-foreground-color); diff --git a/src/routes/MetaDetails/StreamsList/styles.less b/src/routes/MetaDetails/StreamsList/styles.less index 3ddb27813..c22b14071 100644 --- a/src/routes/MetaDetails/StreamsList/styles.less +++ b/src/routes/MetaDetails/StreamsList/styles.less @@ -108,7 +108,6 @@ .select-input-container { min-width: 40%; - flex: 0 0 auto; flex-grow: 1; background: none; diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index a9ef3be86..25b67aae9 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -47,6 +47,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w }, []); const toggleWatchedOnClick = React.useCallback((event) => { event.preventDefault(); + event.stopPropagation(); closeMenu(); core.transport.dispatch({ action: 'MetaDetails', diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index c7d94d82c..5ace96f77 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -34,7 +34,7 @@ const Player = ({ urlParams, queryParams }) => { return queryParams.has('forceTranscoding'); }, [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 streamingServer = useStreamingServer(); const statistics = useStatistics(player, streamingServer); @@ -42,6 +42,8 @@ const Player = ({ urlParams, queryParams }) => { const routeFocused = useRouteFocused(); const toast = useToast(); + const [seeking, setSeeking] = React.useState(false); + const [casting, setCasting] = React.useState(() => { return chromecast.active && chromecast.transport.getCastState() === cast.framework.CastState.CONNECTED; }); @@ -136,6 +138,7 @@ const Player = ({ urlParams, queryParams }) => { const onPlayRequested = React.useCallback(() => { video.setProp('paused', false); + setSeeking(false); }, []); const onPlayRequestedDebounced = React.useCallback(debounce(onPlayRequested, 200), []); @@ -159,7 +162,8 @@ const Player = ({ urlParams, queryParams }) => { const onSeekRequested = React.useCallback((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) => { video.setProp('playbackSpeed', rate); @@ -342,12 +346,8 @@ const Player = ({ urlParams, queryParams }) => { }, [settings.subtitlesOutlineColor]); React.useEffect(() => { - if (video.state.time !== null && !isNaN(video.state.time) && - video.state.duration !== null && !isNaN(video.state.duration) && - 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]); + !seeking && timeChanged(video.state.time, video.state.duration, video.state.manifest?.name); + }, [video.state.time, video.state.duration, video.state.manifest, seeking]); React.useEffect(() => { if (video.state.paused !== null) { @@ -468,6 +468,7 @@ const Player = ({ urlParams, queryParams }) => { if (!menusOpen && !nextVideoPopupOpen && video.state.paused !== null) { if (video.state.paused) { onPlayRequested(); + setSeeking(false); } else { onPauseRequested(); } @@ -478,6 +479,7 @@ const Player = ({ urlParams, queryParams }) => { case 'ArrowRight': { if (!menusOpen && !nextVideoPopupOpen && video.state.time !== null) { const seekDuration = event.shiftKey ? settings.seekShortTimeDuration : settings.seekTimeDuration; + setSeeking(true); onSeekRequested(video.state.time + seekDuration); } @@ -486,6 +488,7 @@ const Player = ({ urlParams, queryParams }) => { case 'ArrowLeft': { if (!menusOpen && !nextVideoPopupOpen && video.state.time !== null) { const seekDuration = event.shiftKey ? settings.seekShortTimeDuration : settings.seekTimeDuration; + setSeeking(true); 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 }) => { if (deltaY > 0) { if (!menusOpen && video.state.volume !== null) { @@ -566,10 +574,12 @@ const Player = ({ urlParams, queryParams }) => { }; if (routeFocused) { window.addEventListener('keydown', onKeyDown); + window.addEventListener('keyup', onKeyUp); window.addEventListener('wheel', onWheel); } return () => { window.removeEventListener('keydown', onKeyDown); + 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]); diff --git a/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js b/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js index 0130c58e2..c65cb9c9e 100644 --- a/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js +++ b/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js @@ -204,7 +204,15 @@ const SubtitlesMenu = React.memo((props) => {
{subtitlesTracksForLanguage.map((track, index) => (