diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 08886cd03..973b6a625 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ jobs: # "--parrents where no error if existing, make parent directories as needed." - run: mkdir -p ./build/${{ github.head_ref || github.ref_name }} - name: Deploy to GitHub Pages - if: github.repository == 'Stremio/stremio-web' && github.actor != 'dependabot[bot]' + if: github.event.pull_request.head.repo.fork == false && github.actor != 'dependabot[bot]' uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/package-lock.json b/package-lock.json index 65057bf18..b8631f786 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stremio", - "version": "5.0.0-beta.12", + "version": "5.0.0-beta.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.12", + "version": "5.0.0-beta.13", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.16.0", @@ -14,7 +14,7 @@ "@stremio/stremio-colors": "5.0.1", "@stremio/stremio-core-web": "0.48.0", "@stremio/stremio-icons": "5.2.0", - "@stremio/stremio-video": "0.0.38", + "@stremio/stremio-video": "0.0.46", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -36,7 +36,7 @@ "react-i18next": "^12.1.1", "react-is": "18.2.0", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", - "stremio-translations": "github:Stremio/stremio-translations#378218c9617f3e763ba5f6755e4d39c1c158747d", + "stremio-translations": "github:Stremio/stremio-translations#57d66ecc8e2df4e73a613dc5e17123ce62ae63f7", "url": "0.11.0", "use-long-press": "^3.1.5" }, @@ -3135,7 +3135,6 @@ "version": "0.48.0", "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.0.tgz", "integrity": "sha512-UEVxb5weAIZ22Hz0iNKM8O1QkALcLShG9AyCe1P2WhZhyiridbwE7MtP5itBtLcLm9f/D6UeRrpUWMCS01n18Q==", - "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } @@ -3164,9 +3163,9 @@ "integrity": "sha512-rABlPBTFF17QcSm/4IizVoE/jh+REt+waqA0RvIxuGjQppXlvj7CalqVvTam0CC2wgY00zNG1v/9kVHUDVzo4Q==" }, "node_modules/@stremio/stremio-video": { - "version": "0.0.38", - "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.38.tgz", - "integrity": "sha512-ev9z3YdMcZAsTQjEwOLfqB9EI8GdbQzwSGMZIOLPR/7/Ce7BQIctwDnEtTLgPmCsRpYZsqOD1PiBwU9tiDHZ8w==", + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.46.tgz", + "integrity": "sha512-U15CGB6CrUZKq3IKcEouAEH2RQoLy2+BI/hDStEYEACxlRlFaavKPI2opl37muh9TY089RnZVBYAM3yDidBZdg==", "dependencies": { "buffer": "6.0.3", "color": "4.2.3", @@ -3178,7 +3177,7 @@ "magnet-uri": "6.2.0", "url": "0.11.0", "video-name-parser": "1.4.6", - "vtt.js": "github:jaruba/vtt.js#e4f5f5603730866bacb174a93f51b734c9f29e6a" + "vtt.js": "github:jaruba/vtt.js#84d33d157848407d790d78423dacc41a096294f0" } }, "node_modules/@stylistic/eslint-plugin": { @@ -13733,8 +13732,9 @@ }, "node_modules/stremio-translations": { "version": "1.44.9", - "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#378218c9617f3e763ba5f6755e4d39c1c158747d", - "integrity": "sha512-3GboN8JS2LgrdIVK/gW+n6r1kLrGG+D/tWkRv8PJo2mZLzh49HTzS2u7XXUSkNmA4AGUyEf8QRjyBhlOg8JNTQ==" + "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#57d66ecc8e2df4e73a613dc5e17123ce62ae63f7", + "integrity": "sha512-Q3Q++Tx3quu71tgTfS8CEP6CajdGyig92SdtRyGMsLHHkgBgzP9ggYBUHVbKAfXcKUegABIkW8CxMueEw758Xg==", + "license": "MIT" }, "node_modules/string_decoder": { "version": "1.1.1", @@ -14894,8 +14894,8 @@ }, "node_modules/vtt.js": { "version": "0.13.0", - "resolved": "git+ssh://git@github.com/jaruba/vtt.js.git#e4f5f5603730866bacb174a93f51b734c9f29e6a", - "integrity": "sha512-RXV60lPGrmjuRcV/jRuydLC2thMaMlmK4Vc3DtBmVSotFA3986sgW0H5AH9IUmHzQo4bFR2gELYLcfwVh7Dqow==", + "resolved": "git+ssh://git@github.com/jaruba/vtt.js.git#84d33d157848407d790d78423dacc41a096294f0", + "integrity": "sha512-N/WeijIW9oiGmfqWdEcNqSblzfnXR8dfsBRNPIG9YYFhIBU0Y2c7w8Sfl0bDOZVhjA5qHbwoHx6SxDgRLiraTQ==", "license": "Apache-2.0" }, "node_modules/w3c-hr-time": { diff --git a/package.json b/package.json index 6be38fa66..29d20645f 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.12", + "version": "5.0.0-beta.13", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", @@ -18,7 +18,7 @@ "@stremio/stremio-colors": "5.0.1", "@stremio/stremio-core-web": "0.48.0", "@stremio/stremio-icons": "5.2.0", - "@stremio/stremio-video": "0.0.38", + "@stremio/stremio-video": "0.0.46", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -40,7 +40,7 @@ "react-i18next": "^12.1.1", "react-is": "18.2.0", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", - "stremio-translations": "github:Stremio/stremio-translations#378218c9617f3e763ba5f6755e4d39c1c158747d", + "stremio-translations": "github:Stremio/stremio-translations#57d66ecc8e2df4e73a613dc5e17123ce62ae63f7", "url": "0.11.0", "use-long-press": "^3.1.5" }, diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index c08cf471d..af8426600 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -93,7 +93,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/Image/Image.js b/src/common/Image/Image.js index c962a8a91..33140504b 100644 --- a/src/common/Image/Image.js +++ b/src/common/Image/Image.js @@ -19,9 +19,9 @@ const Image = ({ className, src, alt, fallbackSrc, renderFallback, ...props }) = typeof renderFallback === 'function' ? renderFallback() : - {alt} + {alt} : - {alt}; + {alt}; }; Image.propTypes = { 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/common/interfaceLanguages.json b/src/common/interfaceLanguages.json index 235193f0d..d4eaa7f60 100644 --- a/src/common/interfaceLanguages.json +++ b/src/common/interfaceLanguages.json @@ -7,6 +7,10 @@ "name": "български език", "codes": ["bg-BG", "bul"] }, + { + "name": "বাংলা", + "codes": ["bn-Bd", "ben"] + }, { "name": "català", "codes": ["ca-CA", "cat"] @@ -75,6 +79,14 @@ "name": "italiano", "codes": ["it-IT", "ita"] }, + { + "name": "日本語 (にほんご)", + "codes": ["ja-JP", "jpn"] + }, + { + "name": "한국어", + "codes": ["ko-KR", "kor"] + }, { "name": "македонски јазик", "codes": ["mk-MK", "mkd"] @@ -135,6 +147,10 @@ "name": "українська мова", "codes": ["uk-UA", "ukr"] }, + { + "name": "Tiếng Việt", + "codes": ["vi-VN", "vie"] + }, { "name": "中文(中华人民共和国)", "codes": ["zh-CN", "zho"] @@ -147,4 +163,4 @@ "name": "中文(台灣)", "codes": ["zh-TW", "zho"] } -] \ No newline at end of file +] 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 d0d2a4d6b..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', @@ -116,7 +117,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w }
{ - upcoming ? + upcoming && !watched ?
Upcoming
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) => (