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()
:
-
+
:
-
;
+
;
};
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 ?
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) => (