From 0f4f0f7c978ee9642c1fa4fa3c3589e4287538e0 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 10 May 2024 14:31:06 +0200 Subject: [PATCH 01/48] refactor(Intro): use Facebook type for ctx Authenticate action --- src/routes/Intro/Intro.js | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 908499a8b..cde07bc96 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -82,32 +82,13 @@ const Intro = ({ queryParams }) => { openLoaderModal(); getFacebookToken() .then((accessToken) => { - return fetch('https://www.strem.io/fb-login-with-token/' + encodeURIComponent(accessToken)) - .then((resp) => resp.json()) - .catch(() => { - throw new Error('Login failed at getting token from Stremio'); - }) - .then(({ user } = {}) => { - if (!user || typeof user.email !== 'string' || typeof user.fbLoginToken !== 'string') { - throw new Error('Login failed at getting token from Stremio'); - } - - return { - email: user.email, - password: user.fbLoginToken - }; - }); - }) - .then(({ email, password }) => { core.transport.dispatch({ action: 'Ctx', args: { action: 'Authenticate', args: { - type: 'Login', - email, - password, - facebook: true + type: 'Facebook', + token: accessToken, } } }); From 69a1a8b92e50c302f5699f61671fa2e311cd5127 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 25 Jun 2024 19:25:31 +0200 Subject: [PATCH 02/48] chore: update stremio-core-web --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76db0e04a..351558728 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.2", + "@stremio/stremio-core-web": "0.47.7", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2971,9 +2971,9 @@ "license": "MIT" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.47.2", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.2.tgz", - "integrity": "sha512-kJXkshXT5f5go137id9MHrVA7PfHao2pGSxfEBbMDGFCqAVfF4jRFTXmfLC0cS1R+EjYhajUrSsXnEddtb2c7g==", + "version": "0.47.7", + "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.7.tgz", + "integrity": "sha512-3hTie3Yx6198TY1rS2fdA5HKPmejqTDbE8C05+HdqM6oXor9TXVoSjY9AMPlSVUJvu40sP3oeenhe2MRBUQizw==", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index bf4b1bd10..9c2fa37de 100755 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.2", + "@stremio/stremio-core-web": "0.47.7", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 10c878871ff199b3e5ada4b1a9f161b2594d2829 Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:31:23 +0100 Subject: [PATCH 03/48] copy infohash to clipboard when right clicking the search result. toast. --- .../MetaDetails/StreamsList/Stream/Stream.js | 11 +++++++++-- src/routes/MetaDetails/StreamsList/StreamsList.js | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 6587c72d0..d386cbf95 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -74,12 +74,18 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio } }, [props.onClick, profile.settings, markVideoAsWatched]); + const onContextMenu = React.useCallback((event) => { + if (typeof props.onContextMenu === 'function') { + props.onContextMenu(event); + } + }, [props.onContextMenu]); + const renderThumbnailFallback = React.useCallback(() => ( ), []); return ( - + ); + }, + [] + ); - const renderThumbnailFallback = React.useCallback(() => ( - - ), []); + const renderMenu = function renderMenu() { + return ( +
+ + {infoHash && } +
+ ); + }; return ( - + ); }; @@ -143,11 +257,11 @@ Stream.propTypes = { windows: PropTypes.string, macos: PropTypes.string, linux: PropTypes.string, - }) - }) + }), + }), }), onClick: PropTypes.func, - onContextMenu: PropTypes.func + infoHash: PropTypes.string, }; module.exports = Stream; diff --git a/src/routes/MetaDetails/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less index 22996622c..fa7509e3a 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/styles.less @@ -3,6 +3,14 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; @import (reference) '~stremio/common/screen-sizes.less'; +:import('~stremio/common/Popup/styles.less') { + context-menu-container: menu-container; + menu-direction-top-left: menu-direction-top-left; + menu-direction-bottom-left: menu-direction-bottom-left; + menu-direction-top-right: menu-direction-top-right; + menu-direction-bottom-right: menu-direction-bottom-right; +} + .stream-container { display: flex; flex-direction: row; @@ -105,6 +113,33 @@ } } +.context-menu-container { + max-width: calc(90% - 1.5rem); + z-index: 2; + + .context-menu-content { + --spatial-navigation-contain: contain; + + .context-menu-option-container { + display: flex; + flex-direction: row; + align-items: center; + padding: 1rem 1.5rem; + + &:hover, + &:focus { + background-color: var(--overlay-color); + } + + .context-menu-option-label { + font-size: 1rem; + font-weight: 500; + color:var(--primary-foreground-color); + } + } + } +} + @media only screen and (max-width: @small) { .stream-container { .description-container { @@ -128,3 +163,29 @@ } } } + +@media only screen and (max-width: @minimum) { + .video-container { + .context-menu-container { + &.menu-direction-top-left, + &.menu-direction-bottom-left { + right: 1.5rem; + } + + &.menu-direction-top-right, + &.menu-direction-bottom-right { + left: 1.5rem; + } + + &.menu-direction-top-left, + &.menu-direction-top-right { + bottom: 90%; + } + + &.menu-direction-bottom-left, + &.menu-direction-bottom-right { + top: 90%; + } + } + } +} diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 728f773b3..da7b657ab 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -5,7 +5,7 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { Button, Image, Multiselect, useToast } = require('stremio/common'); +const { Button, Image, Multiselect } = require('stremio/common'); const { useServices } = require('stremio/services'); const Stream = require('./Stream'); const styles = require('./styles'); @@ -15,7 +15,6 @@ const ALL_ADDONS_KEY = 'ALL'; const StreamsList = ({ className, video, ...props }) => { const { t } = useTranslation(); const { core } = useServices(); - const toast = useToast(); const [selectedAddon, setSelectedAddon] = React.useState(ALL_ADDONS_KEY); const onAddonSelected = React.useCallback((event) => { setSelectedAddon(event.value); @@ -38,36 +37,25 @@ const StreamsList = ({ className, video, ...props }) => { core.transport.analytics({ event: 'StreamClicked', args: { - stream - } + stream, + }, }); }, - onContextMenu: (e) => { - e.preventDefault(); - if(stream?.infoHash && navigator?.clipboard) { - stream?.infoHash && navigator?.clipboard?.writeText(stream.infoHash); - toast.show({ - type: 'success', - title: 'Copied infohash to clipboard', - timeout: 4000 - }); - } - }, - addonName: streams.addon.manifest.name - })) + addonName: streams.addon.manifest.name, + })), }; return streamsByAddon; }, {}); }, [props.streams]); const filteredStreams = React.useMemo(() => { - return selectedAddon === ALL_ADDONS_KEY ? - Object.values(streamsByAddon).map(({ streams }) => streams).flat(1) - : - streamsByAddon[selectedAddon] ? - streamsByAddon[selectedAddon].streams - : - []; + return selectedAddon === ALL_ADDONS_KEY + ? Object.values(streamsByAddon) + .map(({ streams }) => streams) + .flat(1) + : streamsByAddon[selectedAddon] + ? streamsByAddon[selectedAddon].streams + : []; }, [streamsByAddon, selectedAddon]); const selectableOptions = React.useMemo(() => { return { @@ -76,97 +64,106 @@ const StreamsList = ({ className, video, ...props }) => { { value: ALL_ADDONS_KEY, label: t('ALL_ADDONS'), - title: t('ALL_ADDONS') + title: t('ALL_ADDONS'), }, ...Object.keys(streamsByAddon).map((transportUrl) => ({ value: transportUrl, label: streamsByAddon[transportUrl].addon.manifest.name, title: streamsByAddon[transportUrl].addon.manifest.name, - })) + })), ], selected: [selectedAddon], - onSelect: onAddonSelected + onSelect: onAddonSelected, }; }, [streamsByAddon, selectedAddon]); return (
- { - props.streams.length === 0 ? -
- {' -
No addons were requested for streams!
+ {props.streams.length === 0 ? ( +
+ {' +
+ No addons were requested for streams!
- : - props.streams.every((streams) => streams.content.type === 'Err') ? -
- {' -
{t('NO_STREAM')}
-
- : - filteredStreams.length === 0 ? -
- - +
+ ) : props.streams.every((streams) => streams.content.type === 'Err') ? ( +
+ {' +
{t('NO_STREAM')}
+
+ ) : filteredStreams.length === 0 ? ( +
+ + +
+ ) : ( + + {countLoadingAddons > 0 ? ( +
+
+ {countLoadingAddons} {t('MOBILE_ADDONS_LOADING')}
- : + +
+ ) : null} +
+ {video ? ( - { - countLoadingAddons > 0 ? -
-
- {countLoadingAddons} {t('MOBILE_ADDONS_LOADING')} -
- -
- : - null - } -
- { - video ? - - -
- {`S${video?.season}E${video?.episode} ${(video?.title)}`} -
-
- : - null - } - { - Object.keys(streamsByAddon).length > 1 ? - - : - null - } -
-
- {filteredStreams.map((stream, index) => ( - - ))} + +
+ {`S${video?.season}E${video?.episode} ${video?.title}`}
- } -
+
+ {filteredStreams.map((stream, index) => ( + + ))} +
+
+ )} +
); @@ -175,7 +172,7 @@ const StreamsList = ({ className, video, ...props }) => { StreamsList.propTypes = { className: PropTypes.string, streams: PropTypes.arrayOf(PropTypes.object).isRequired, - video: PropTypes.object + video: PropTypes.object, }; module.exports = StreamsList; From 7a1597e5fa707e58586fac57d66abcc51130e33b Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 23 Jul 2024 08:29:08 +0200 Subject: [PATCH 05/48] ci(build): run workflow on pull requests --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf4a9db50..950cd250a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,12 @@ name: Build on: - push: branches: - '**' + pull_request: + branches: + - '**' # Allow manual dispatch in GH workflow_dispatch: From ad58ab069e144af48cc062bf8acf247243ecfd79 Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:49:58 +0100 Subject: [PATCH 06/48] suggested style changes. infohash menu item is now magnetic link item --- .../MetaDetails/StreamsList/Stream/Stream.js | 12 ++--- .../StreamsList/Stream/styles.less | 53 +++++++++---------- .../MetaDetails/StreamsList/StreamsList.js | 1 - 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 5cb31b251..484e5e08a 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -29,7 +29,6 @@ const Stream = ({ thumbnail, progress, deepLinks, - infoHash, ...props }) => { const profile = useProfile(); @@ -123,10 +122,10 @@ const Stream = ({ [props.onClick, profile.settings, markVideoAsWatched] ); - const copyInfoHashToClipboard = React.useCallback((event) => { + const copyMagneticLinkToClipboard = React.useCallback((event) => { event.preventDefault(); - if (infoHash && navigator?.clipboard) { - navigator?.clipboard?.writeText(infoHash); + if (deepLinks?.externalPlayer?.download && navigator?.clipboard) { + navigator.clipboard.writeText(deepLinks.externalPlayer.download); toast.show({ type: 'success', title: t('PLAYER_COPY_DOWNLOAD_LINK_SUCCESS'), @@ -207,8 +206,8 @@ const Stream = ({ - {infoHash && }
); @@ -261,7 +260,6 @@ Stream.propTypes = { }), }), onClick: PropTypes.func, - infoHash: PropTypes.string, }; module.exports = Stream; diff --git a/src/routes/MetaDetails/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less index fa7509e3a..4e5151a88 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/styles.less @@ -111,30 +111,30 @@ color: var(--primary-foreground-color); background-color: var(--secondary-accent-color); } -} -.context-menu-container { - max-width: calc(90% - 1.5rem); - z-index: 2; - - .context-menu-content { - --spatial-navigation-contain: contain; - - .context-menu-option-container { - display: flex; - flex-direction: row; - align-items: center; - padding: 1rem 1.5rem; - - &:hover, - &:focus { - background-color: var(--overlay-color); - } - - .context-menu-option-label { - font-size: 1rem; - font-weight: 500; - color:var(--primary-foreground-color); + .context-menu-container { + max-width: calc(90% - 1.5rem); + z-index: 2; + + .context-menu-content { + --spatial-navigation-contain: contain; + + .context-menu-option-container { + display: flex; + flex-direction: row; + align-items: center; + padding: 1rem 1.5rem; + + &:hover, + &:focus { + background-color: var(--overlay-color); + } + + .context-menu-option-label { + font-size: 1rem; + font-weight: 500; + color:var(--primary-foreground-color); + } } } } @@ -161,12 +161,7 @@ font-weight: 500; } } - } -} - -@media only screen and (max-width: @minimum) { - .video-container { - .context-menu-container { + .context-menu-container { &.menu-direction-top-left, &.menu-direction-bottom-left { right: 1.5rem; diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index da7b657ab..9c8cd1c43 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -151,7 +151,6 @@ const StreamsList = ({ className, video, ...props }) => { progress={stream.progress} deepLinks={stream.deepLinks} onClick={stream.onClick} - infoHash={stream.infoHash} /> ))}
From ff41ff2997e1bf00a99712dec315acaeef18866c Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 10:04:18 +0100 Subject: [PATCH 07/48] attempted to undo IDE auto formatting --- .../MetaDetails/StreamsList/Stream/Stream.js | 176 +++++++----------- 1 file changed, 72 insertions(+), 104 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 484e5e08a..e4676c676 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -4,33 +4,14 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { - Button, - Image, - useProfile, - platform, - useToast, - Popup, - useBinaryState, -} = require('stremio/common'); +const { Button, Image, useProfile, platform, useToast, Popup, useBinaryState } = require('stremio/common'); const { useServices } = require('stremio/services'); const StreamPlaceholder = require('./StreamPlaceholder'); const { t } = require('i18next'); const styles = require('./styles'); -const Stream = ({ - className, - videoId, - videoReleased, - addonName, - name, - description, - thumbnail, - progress, - deepLinks, - ...props -}) => { +const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => { const profile = useProfile(); const toast = useToast(); const { core } = useServices(); @@ -69,27 +50,36 @@ const Stream = ({ }, []); const href = React.useMemo(() => { - return deepLinks - ? deepLinks.externalPlayer - ? deepLinks.externalPlayer.web - ? deepLinks.externalPlayer.web - : deepLinks.externalPlayer.openPlayer - ? deepLinks.externalPlayer.openPlayer[platform.name] - ? deepLinks.externalPlayer.openPlayer[platform.name] - : deepLinks.externalPlayer.playlist - : deepLinks.player - : deepLinks.player - : null; + return deepLinks ? + deepLinks.externalPlayer ? + deepLinks.externalPlayer.web ? + deepLinks.externalPlayer.web + : + deepLinks.externalPlayer.openPlayer ? + deepLinks.externalPlayer.openPlayer[platform.name] ? + deepLinks.externalPlayer.openPlayer[platform.name] + : + deepLinks.externalPlayer.playlist + : + deepLinks.player + : + deepLinks.player + : + null; }, [deepLinks]); const download = React.useMemo(() => { - return href === deepLinks?.externalPlayer?.playlist - ? deepLinks.externalPlayer.fileName - : null; + return href === deepLinks?.externalPlayer?.playlist ? + deepLinks.externalPlayer.fileName + : + null; }, [href, deepLinks]); const target = React.useMemo(() => { - return href === deepLinks?.externalPlayer?.web ? '_blank' : null; + return href === deepLinks?.externalPlayer?.web ? + '_blank' + : + null; }, [href, deepLinks]); const markVideoAsWatched = React.useCallback(() => { @@ -98,28 +88,27 @@ const Stream = ({ action: 'MetaDetails', args: { action: 'MarkVideoAsWatched', - args: [{ id: videoId, released: videoReleased }, true], - }, + args: [{ id: videoId, released: videoReleased }, true] + } }); } }, [videoId, videoReleased]); - const onClick = React.useCallback( - (event) => { - if (profile.settings.playerType !== null) { - markVideoAsWatched(); - toast.show({ - type: 'success', - title: 'Stream opened in external player', - timeout: 4000, - }); - } + const onClick = React.useCallback((event) => { + if (profile.settings.playerType !== null) { + markVideoAsWatched(); + toast.show({ + type: 'success', + title: 'Stream opened in external player', + timeout: 4000 + }); + } - if (typeof props.onClick === 'function') { - props.onClick(event); - } - }, - [props.onClick, profile.settings, markVideoAsWatched] + if (typeof props.onClick === 'function') { + props.onClick(event); + } + }, + [props.onClick, profile.settings, markVideoAsWatched] ); const copyMagneticLinkToClipboard = React.useCallback((event) => { @@ -129,69 +118,48 @@ const Stream = ({ toast.show({ type: 'success', title: t('PLAYER_COPY_DOWNLOAD_LINK_SUCCESS'), - timeout: 4000, + timeout: 4000 }); } + closeMenu(); }, []); - const renderThumbnailFallback = React.useCallback( - () => ( - - ), - [] - ); + const renderThumbnailFallback = React.useCallback(() => ( + + ), []); const renderLabel = React.useMemo( () => function renderLabel({ className, thumbnail, progress, children, ...props }) { return ( - From 829ebb87e7967c918a2cb32012889265b630f0ee Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 10:09:46 +0100 Subject: [PATCH 08/48] more formatting reverts --- .../MetaDetails/StreamsList/Stream/Stream.js | 12 +- .../MetaDetails/StreamsList/StreamsList.js | 180 +++++++++--------- 2 files changed, 91 insertions(+), 101 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index e4676c676..3f6b24483 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -107,9 +107,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio if (typeof props.onClick === 'function') { props.onClick(event); } - }, - [props.onClick, profile.settings, markVideoAsWatched] - ); + }, [props.onClick, profile.settings, markVideoAsWatched]); const copyMagneticLinkToClipboard = React.useCallback((event) => { event.preventDefault(); @@ -223,11 +221,11 @@ Stream.propTypes = { android: PropTypes.string, windows: PropTypes.string, macos: PropTypes.string, - linux: PropTypes.string, - }), - }), + linux: PropTypes.string + }) + }) }), - onClick: PropTypes.func, + onClick: PropTypes.func }; module.exports = Stream; diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 9c8cd1c43..f932ea0ee 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -37,25 +37,25 @@ const StreamsList = ({ className, video, ...props }) => { core.transport.analytics({ event: 'StreamClicked', args: { - stream, - }, + stream + } }); }, - addonName: streams.addon.manifest.name, - })), + addonName: streams.addon.manifest.name + })) }; return streamsByAddon; }, {}); }, [props.streams]); const filteredStreams = React.useMemo(() => { - return selectedAddon === ALL_ADDONS_KEY - ? Object.values(streamsByAddon) - .map(({ streams }) => streams) - .flat(1) - : streamsByAddon[selectedAddon] - ? streamsByAddon[selectedAddon].streams - : []; + return selectedAddon === ALL_ADDONS_KEY ? + Object.values(streamsByAddon).map(({ streams }) => streams).flat(1) + : + streamsByAddon[selectedAddon] ? + streamsByAddon[selectedAddon].streams + : + []; }, [streamsByAddon, selectedAddon]); const selectableOptions = React.useMemo(() => { return { @@ -64,105 +64,97 @@ const StreamsList = ({ className, video, ...props }) => { { value: ALL_ADDONS_KEY, label: t('ALL_ADDONS'), - title: t('ALL_ADDONS'), + title: t('ALL_ADDONS') }, ...Object.keys(streamsByAddon).map((transportUrl) => ({ value: transportUrl, label: streamsByAddon[transportUrl].addon.manifest.name, title: streamsByAddon[transportUrl].addon.manifest.name, - })), + })) ], selected: [selectedAddon], - onSelect: onAddonSelected, + onSelect: onAddonSelected }; }, [streamsByAddon, selectedAddon]); return (
- {props.streams.length === 0 ? ( -
- {' -
- No addons were requested for streams! + { + props.streams.length === 0 ? +
+ {' +
No addons were requested for streams!
-
- ) : props.streams.every((streams) => streams.content.type === 'Err') ? ( -
- {' -
{t('NO_STREAM')}
-
- ) : filteredStreams.length === 0 ? ( -
- - -
- ) : ( - - {countLoadingAddons > 0 ? ( -
-
- {countLoadingAddons} {t('MOBILE_ADDONS_LOADING')} -
- + : + props.streams.every((streams) => streams.content.type === 'Err') ? +
+ {' +
{t('NO_STREAM')}
- ) : null} -
- {video ? ( + : + filteredStreams.length === 0 ? +
+ + +
+ : - -
- {`S${video?.season}E${video?.episode} ${video?.title}`} + { + countLoadingAddons > 0 ? +
+
+ {countLoadingAddons} {t('MOBILE_ADDONS_LOADING')} +
+ +
+ : + null + } +
+ { + video ? + + +
+ {`S${video?.season}E${video?.episode} ${(video?.title)}`} +
+
+ : + null + } + { + Object.keys(streamsByAddon).length > 1 ? + + : + null + } +
+
+ {filteredStreams.map((stream, index) => ( + + ))}
- ) : null} - {Object.keys(streamsByAddon).length > 1 ? ( - - ) : null} -
-
- {filteredStreams.map((stream, index) => ( - - ))} -
-
- )} -
); @@ -171,7 +163,7 @@ const StreamsList = ({ className, video, ...props }) => { StreamsList.propTypes = { className: PropTypes.string, streams: PropTypes.arrayOf(PropTypes.object).isRequired, - video: PropTypes.object, + video: PropTypes.object }; module.exports = StreamsList; From bb170f53c83f75d6544590191bdfa03105313c45 Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 10:11:43 +0100 Subject: [PATCH 09/48] couple more --- src/routes/MetaDetails/StreamsList/Stream/Stream.js | 2 +- src/routes/MetaDetails/StreamsList/StreamsList.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 3f6b24483..8b1dba2ca 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -221,7 +221,7 @@ Stream.propTypes = { android: PropTypes.string, windows: PropTypes.string, macos: PropTypes.string, - linux: PropTypes.string + linux: PropTypes.string, }) }) }), diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index f932ea0ee..ae7d2416e 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -146,7 +146,6 @@ const StreamsList = ({ className, video, ...props }) => { progress={stream.progress} deepLinks={stream.deepLinks} onClick={stream.onClick} - onContextMenu={stream.onContextMenu} /> ))}
From c0b82fdefeba34c360c6b24618e4d6f315201fba Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 10:17:22 +0100 Subject: [PATCH 10/48] added an error toast on copy fail --- .../MetaDetails/StreamsList/Stream/Stream.js | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 8b1dba2ca..1ea5f1df0 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -8,7 +8,6 @@ const { Button, Image, useProfile, platform, useToast, Popup, useBinaryState } = const { useServices } = require('stremio/services'); const StreamPlaceholder = require('./StreamPlaceholder'); const { t } = require('i18next'); - const styles = require('./styles'); const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => { @@ -112,11 +111,27 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const copyMagneticLinkToClipboard = React.useCallback((event) => { event.preventDefault(); if (deepLinks?.externalPlayer?.download && navigator?.clipboard) { - navigator.clipboard.writeText(deepLinks.externalPlayer.download); + navigator.clipboard.writeText(deepLinks.externalPlayer.download) + .then(() => { + toast.show({ + type: 'success', + title: t('PLAYER_COPY_DOWNLOAD_LINK_SUCCESS'), + timeout: 4000 + }); + }) + .catch(() => { + toast.show({ + type: 'error', + title: t('PLAYER_COPY_DOWNLOAD_LINK_ERROR'), + timeout: 4000, + }); + }); + + } else { toast.show({ - type: 'success', - title: t('PLAYER_COPY_DOWNLOAD_LINK_SUCCESS'), - timeout: 4000 + type: 'error', + title: t('PLAYER_COPY_DOWNLOAD_LINK_ERROR'), + timeout: 4000, }); } closeMenu(); From 922c1d455752c4521847c683f82d584b8954dc2d Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 10:22:09 +0100 Subject: [PATCH 11/48] button title --- src/routes/MetaDetails/StreamsList/Stream/Stream.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 1ea5f1df0..4ec684082 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -184,10 +184,10 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const renderMenu = function renderMenu() { return (
- - {deepLinks?.externalPlayer?.download && }
From 17ad9f83b39403e2dbf2ed06043201952e7e27b8 Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 16:19:02 +0100 Subject: [PATCH 12/48] added route focus. updated translation keys. fixed memo check --- .../MetaDetails/StreamsList/Stream/Stream.js | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 4ec684082..3d4c1bfd9 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -6,6 +6,7 @@ const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { Button, Image, useProfile, platform, useToast, Popup, useBinaryState } = require('stremio/common'); const { useServices } = require('stremio/services'); +const { useRouteFocused } = require('stremio-router'); const StreamPlaceholder = require('./StreamPlaceholder'); const { t } = require('i18next'); const styles = require('./styles'); @@ -14,9 +15,16 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const profile = useProfile(); const toast = useToast(); const { core } = useServices(); + const routeFocused = useRouteFocused(); const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false); + React.useEffect(() => { + if (!routeFocused) { + closeMenu(); + } + }, [routeFocused]); + const popupLabelOnMouseUp = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented) { if (event.nativeEvent.ctrlKey || event.nativeEvent.button === 2) { @@ -115,14 +123,14 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio .then(() => { toast.show({ type: 'success', - title: t('PLAYER_COPY_DOWNLOAD_LINK_SUCCESS'), + title: t('PLAYER_COPY_STREAM_SUCCESS'), timeout: 4000 }); }) .catch(() => { toast.show({ type: 'error', - title: t('PLAYER_COPY_DOWNLOAD_LINK_ERROR'), + title: t('PLAYER_COPY_STREAM_ERROR'), timeout: 4000, }); }); @@ -130,7 +138,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio } else { toast.show({ type: 'error', - title: t('PLAYER_COPY_DOWNLOAD_LINK_ERROR'), + title: t('PLAYER_COPY_STREAM_ERROR'), timeout: 4000, }); } @@ -143,7 +151,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const renderLabel = React.useMemo( () => - function renderLabel({ className, thumbnail, progress, children, ...props }) { + function renderLabel({ className, thumbnail, progress, addonName, name, description, children, ...props }) { return ( ); }, - [] + [ thumbnail, progress, addonName, name, description ] ); const renderMenu = function renderMenu() { return (
- - {deepLinks?.externalPlayer?.download && }
); @@ -199,6 +207,9 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio className={className} thumbnail={thumbnail} progress={progress} + addonName={addonName} + name={name} + description={description} href={href} {...props} onMouseUp={popupLabelOnMouseUp} From 9b1e5841e64d067a3811893f148e2b1b3b9c91b7 Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Tue, 23 Jul 2024 16:29:38 +0100 Subject: [PATCH 13/48] removed memo, the props come from popup --- src/routes/MetaDetails/StreamsList/Stream/Stream.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 3d4c1bfd9..a5539198b 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -186,7 +186,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio ); }, - [ thumbnail, progress, addonName, name, description ] + [] ); const renderMenu = function renderMenu() { From 6a5dcb9fae508fa661461a3cd3354a048f05da13 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 24 Jul 2024 16:11:41 +0300 Subject: [PATCH 14/48] feature: multiselect menu --- .../MultiselectMenu/Dropdown/Dropdown.less | 30 ++++++++++ .../MultiselectMenu/Dropdown/Dropdown.tsx | 53 ++++++++++++++++++ .../Dropdown/Option/Option.less | 30 ++++++++++ .../Dropdown/Option/Option.tsx | 42 ++++++++++++++ .../MultiselectMenu/Dropdown/Option/index.ts | 5 ++ src/common/MultiselectMenu/Dropdown/index.ts | 5 ++ .../MultiselectMenu/MultiselectMenu.less | 34 +++++++++++ .../MultiselectMenu/MultiselectMenu.tsx | 56 +++++++++++++++++++ src/common/MultiselectMenu/index.ts | 5 ++ src/common/MultiselectMenu/types.d.ts | 9 +++ src/common/index.js | 2 + .../VideosList/SeasonsBar/SeasonsBar.js | 14 ++--- 12 files changed, 278 insertions(+), 7 deletions(-) create mode 100644 src/common/MultiselectMenu/Dropdown/Dropdown.less create mode 100644 src/common/MultiselectMenu/Dropdown/Dropdown.tsx create mode 100644 src/common/MultiselectMenu/Dropdown/Option/Option.less create mode 100644 src/common/MultiselectMenu/Dropdown/Option/Option.tsx create mode 100644 src/common/MultiselectMenu/Dropdown/Option/index.ts create mode 100644 src/common/MultiselectMenu/Dropdown/index.ts create mode 100644 src/common/MultiselectMenu/MultiselectMenu.less create mode 100644 src/common/MultiselectMenu/MultiselectMenu.tsx create mode 100644 src/common/MultiselectMenu/index.ts create mode 100644 src/common/MultiselectMenu/types.d.ts diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.less b/src/common/MultiselectMenu/Dropdown/Dropdown.less new file mode 100644 index 000000000..1e15419ef --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.less @@ -0,0 +1,30 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.dropdown { + background: var(--modal-background-color); + display: none; + position: absolute; + width: 100%; + top: 100%; + left: 0; + z-index: 10; + box-shadow: var(--outer-glow); + border-radius: var(--border-radius); + overflow: hidden; + + &.open { + display: block; + } + + .back-button { + display: flex; + align-items: center; + gap: 0 0.5rem; + padding: 0.75rem; + color: var(--primary-foreground-color); + + .back-button-icon { + width: 1.5rem; + } + } +} \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Dropdown.tsx b/src/common/MultiselectMenu/Dropdown/Dropdown.tsx new file mode 100644 index 000000000..1c09de925 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Dropdown.tsx @@ -0,0 +1,53 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import Button from 'stremio/common/Button'; +import { useTranslation } from 'react-i18next'; +import classNames from 'classnames'; +import Option from './Option'; +import Icon from '@stremio/stremio-icons/react'; +import styles from './Dropdown.less'; + +type Props = { + options: MultiselectMenuOption[]; + selectedOption?: MultiselectMenuOption | null; + menuOpen: boolean | (() => void); + level: number; + setLevel: (level: number) => void; + onSelect: (option: MultiselectMenuOption) => void; +}; + +const Dropdown = ({ level, setLevel, options, onSelect, selectedOption, menuOpen }: Props) => { + const { t } = useTranslation(); + const onBackButtonClick = () => { + setLevel(level - 1); + }; + + return ( +
+ { + level > 0 ? + + : null + } + { + options + .filter((option: MultiselectMenuOption) => !option.hidden) + .map((option: MultiselectMenuOption) => ( +
+ ); +}; + +export default Dropdown; \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.less b/src/common/MultiselectMenu/Dropdown/Option/Option.less new file mode 100644 index 000000000..067934dfc --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.less @@ -0,0 +1,30 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +.option { + font-size: var(--font-size-normal); + color: var(--primary-foreground-color); + align-items: center; + display: flex; + flex-direction: row; + padding: 1rem; + + .label { + flex: 1; + color: var(--primary-foreground-color); + } + + .icon { + flex: none; + // display: none; + width: 0.5rem; + height: 0.5rem; + border-radius: 100%; + margin-left: 1rem; + background-color: var(--secondary-accent-color); + opacity: 1; + } + + &:hover { + background-color: rgba(255, 255, 255, 0.15); + } +} \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx new file mode 100644 index 000000000..7ade6dfa5 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -0,0 +1,42 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React, { useMemo } from 'react'; +import classNames from 'classnames'; +import Button from 'stremio/common/Button'; +import styles from './Option.less'; +import Icon from '@stremio/stremio-icons/react'; + +type Props = { + option: MultiselectMenuOption; + selectedOption?: MultiselectMenuOption | null; + onSelect: (option: MultiselectMenuOption) => void; +}; + +const Option = ({ option, selectedOption, onSelect }: Props) => { + // consider using option.id === selectedOption?.id instead + const selected = useMemo(() => option?.value === selectedOption?.value, [option, selectedOption]); + + return ( + + ); +}; + +export default Option; \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/Option/index.ts b/src/common/MultiselectMenu/Dropdown/Option/index.ts new file mode 100644 index 000000000..6004f7754 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/Option/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Option from './Option'; + +export default Option; \ No newline at end of file diff --git a/src/common/MultiselectMenu/Dropdown/index.ts b/src/common/MultiselectMenu/Dropdown/index.ts new file mode 100644 index 000000000..ce3622a25 --- /dev/null +++ b/src/common/MultiselectMenu/Dropdown/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import Dropdown from './Dropdown'; + +export default Dropdown; \ No newline at end of file diff --git a/src/common/MultiselectMenu/MultiselectMenu.less b/src/common/MultiselectMenu/MultiselectMenu.less new file mode 100644 index 000000000..156e2035d --- /dev/null +++ b/src/common/MultiselectMenu/MultiselectMenu.less @@ -0,0 +1,34 @@ + +@border-radius: 2.75rem; + +.multiselect-menu { + background-color: var(--overlay-color); + position: relative; + min-width: 150px; + overflow: visible; + border-radius: @border-radius; + &.disabled { + pointer-events: none; + opacity: 0.3; + } + + .multiselect-button { + color: var(--primary-foreground-color); + background-color: rgba(255, 255, 255, 0.05); + padding: 0.75rem 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; + gap: 0 0.5rem; + border-radius: @border-radius; + + .icon { + width: 1.5rem; + color: var(--primary-foreground-color); + + &.open { + transform: rotate(180deg); + } + } + } +} \ No newline at end of file diff --git a/src/common/MultiselectMenu/MultiselectMenu.tsx b/src/common/MultiselectMenu/MultiselectMenu.tsx new file mode 100644 index 000000000..5eb073eca --- /dev/null +++ b/src/common/MultiselectMenu/MultiselectMenu.tsx @@ -0,0 +1,56 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import React from 'react'; +import Button from 'stremio/common/Button'; +import useBinaryState from 'stremio/common/useBinaryState'; +import Dropdown from './Dropdown'; +import classNames from 'classnames'; +import Icon from '@stremio/stremio-icons/react'; +import styles from './MultiselectMenu.less'; + +type Props = { + className?: string, + title?: string; + options: MultiselectMenuOption[]; + selectedOption?: MultiselectMenuOption; + onSelect: () => void; +}; + +const MultiselectMenu = ({ className, title, options, selectedOption, onSelect }: Props) => { + const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false); + const multiselectMenuRef = React.useRef(null); + const [level, setLevel] = React.useState(0); + + const onOptionSelect = (option: MultiselectMenuOption) => { + option.level ? setLevel(level + 1) : onSelect(), closeMenu(); + }; + + return ( +
+ + { + menuOpen ? + + : null + } +
+ ); +}; + +export default MultiselectMenu; \ No newline at end of file diff --git a/src/common/MultiselectMenu/index.ts b/src/common/MultiselectMenu/index.ts new file mode 100644 index 000000000..e526218cd --- /dev/null +++ b/src/common/MultiselectMenu/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2024 Smart code 203358507 + +import MultiselectMenu from './MultiselectMenu'; + +export default MultiselectMenu; \ No newline at end of file diff --git a/src/common/MultiselectMenu/types.d.ts b/src/common/MultiselectMenu/types.d.ts new file mode 100644 index 000000000..a1724ab9b --- /dev/null +++ b/src/common/MultiselectMenu/types.d.ts @@ -0,0 +1,9 @@ +type MultiselectMenuOption = { + id?: number; + label: string; + value: string; + destination?: string; + default?: boolean; + hidden?: boolean; + level?: MultiselectMenuOption[]; +}; \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index 8046dab15..c582a13ca 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -15,6 +15,7 @@ const MetaPreview = require('./MetaPreview'); const MetaRow = require('./MetaRow'); const ModalDialog = require('./ModalDialog'); const Multiselect = require('./Multiselect'); +const { default: MultiselectMenu } = require('./MultiselectMenu'); const { HorizontalNavBar, VerticalNavBar } = require('./NavBar'); const PaginationInput = require('./PaginationInput'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); @@ -63,6 +64,7 @@ module.exports = { MetaRow, ModalDialog, Multiselect, + MultiselectMenu, HorizontalNavBar, VerticalNavBar, PaginationInput, diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js index d75080d01..6ecc2c815 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js @@ -5,9 +5,10 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const { t } = require('i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { Button, Multiselect } = require('stremio/common'); +const { Button } = require('stremio/common'); const SeasonsBarPlaceholder = require('./SeasonsBarPlaceholder'); const styles = require('./styles'); +const { MultiselectMenu } = require('stremio/common'); const SeasonsBar = ({ className, seasons, season, onSelect }) => { const options = React.useMemo(() => { @@ -16,8 +17,8 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { label: season > 0 ? `${t('SEASON')} ${season}` : t('SPECIAL') })); }, [seasons]); - const selected = React.useMemo(() => { - return [String(season)]; + const selectedSeason = React.useMemo(() => { + return { label: String(season), value: String(season) }; }, [season]); const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { @@ -61,12 +62,11 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => {
Prev
- 0 ? `${t('SEASON')} ${season}` : t('SPECIAL')} - direction={'bottom-left'} options={options} - selected={selected} + title={season > 0 ? `${t('SEASON')} ${season}` : t('SPECIAL')} + selectedOption={selectedSeason} onSelect={seasonOnSelect} /> : null diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.less b/src/common/MultiselectMenu/Dropdown/Option/Option.less index 067934dfc..a0ee1743f 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.less +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.less @@ -15,7 +15,6 @@ .icon { flex: none; - // display: none; width: 0.5rem; height: 0.5rem; border-radius: 100%; diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx index 28a431b1f..4309e766e 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -9,7 +9,7 @@ import Icon from '@stremio/stremio-icons/react'; type Props = { option: MultiselectMenuOption; selectedOption?: MultiselectMenuOption | null; - onSelect: (value: string) => void; + onSelect: (value: number) => void; }; const Option = ({ option, selectedOption, onSelect }: Props) => { @@ -32,7 +32,7 @@ const Option = ({ option, selectedOption, onSelect }: Props) => { } { option.level ? - + : null } diff --git a/src/common/MultiselectMenu/MultiselectMenu.less b/src/common/MultiselectMenu/MultiselectMenu.less index 58eec12dd..3c7b81b59 100644 --- a/src/common/MultiselectMenu/MultiselectMenu.less +++ b/src/common/MultiselectMenu/MultiselectMenu.less @@ -3,11 +3,11 @@ @border-radius: 2.75rem; .multiselect-menu { - background-color: var(--overlay-color); position: relative; - min-width: 150px; + min-width: 8.5rem; overflow: visible; border-radius: @border-radius; + &.disabled { pointer-events: none; opacity: 0.3; @@ -15,7 +15,6 @@ .multiselect-button { color: var(--primary-foreground-color); - background-color: rgba(255, 255, 255, 0.05); padding: 0.75rem 1.5rem; display: flex; justify-content: space-between; @@ -24,12 +23,17 @@ border-radius: @border-radius; .icon { - width: 1.5rem; + width: 1rem; color: var(--primary-foreground-color); + opacity: 0.6; &.open { transform: rotate(180deg); } } } + + &:hover { + background-color: var(--overlay-color); + } } \ No newline at end of file diff --git a/src/common/MultiselectMenu/MultiselectMenu.tsx b/src/common/MultiselectMenu/MultiselectMenu.tsx index 030b097da..2bd298752 100644 --- a/src/common/MultiselectMenu/MultiselectMenu.tsx +++ b/src/common/MultiselectMenu/MultiselectMenu.tsx @@ -14,7 +14,7 @@ type Props = { title?: string; options: MultiselectMenuOption[]; selectedOption?: MultiselectMenuOption; - onSelect: (event: any) => void; + onSelect: (value: number) => void; }; const MultiselectMenu = ({ className, title, options, selectedOption, onSelect }: Props) => { @@ -22,9 +22,8 @@ const MultiselectMenu = ({ className, title, options, selectedOption, onSelect } const multiselectMenuRef = useOutsideClick(() => closeMenu()); const [level, setLevel] = React.useState(0); - const onOptionSelect = (event: any) => { - console.log(event.value); - level ? setLevel(level + 1) : onSelect(event), closeMenu(); + const onOptionSelect = (value: number) => { + level ? setLevel(level + 1) : onSelect(value), closeMenu(); }; return ( @@ -37,7 +36,7 @@ const MultiselectMenu = ({ className, title, options, selectedOption, onSelect } aria-expanded={menuOpen} > {title} - + { menuOpen ? diff --git a/src/common/MultiselectMenu/types.d.ts b/src/common/MultiselectMenu/types.d.ts index a1724ab9b..7ed039ddd 100644 --- a/src/common/MultiselectMenu/types.d.ts +++ b/src/common/MultiselectMenu/types.d.ts @@ -1,7 +1,7 @@ type MultiselectMenuOption = { id?: number; label: string; - value: string; + value: number; destination?: string; default?: boolean; hidden?: boolean; diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js index 6ecc2c815..71c10ce92 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js @@ -36,8 +36,7 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { }); } }, [season, seasons, onSelect]); - const seasonOnSelect = React.useCallback((event) => { - const value = parseFloat(event.value); + const seasonOnSelect = React.useCallback((value) => { if (typeof onSelect === 'function') { onSelect({ type: 'select', From 8d18820ca18d9d6ddac844e8b4b1bf7561a81245 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 26 Jul 2024 12:10:13 +0300 Subject: [PATCH 20/48] feat: External Players - add visionos (Vision Pro) as a platform and moonplayer url scheme Signed-off-by: Lachezar Lechev --- src/common/CONSTANTS.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index aeaa51462..fef278f0b 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -44,7 +44,7 @@ const EXTERNAL_PLAYERS = [ { label: 'EXTERNAL_PLAYER_DISABLED', value: null, - platforms: ['ios', 'android', 'windows', 'linux', 'macos'], + platforms: ['ios', 'visionos', 'android', 'windows', 'linux', 'macos'], }, { label: 'EXTERNAL_PLAYER_ALLOW_CHOOSING', @@ -54,7 +54,7 @@ const EXTERNAL_PLAYERS = [ { label: 'VLC', value: 'vlc', - platforms: ['ios', 'android'], + platforms: ['ios', 'visionos', 'android'], }, { label: 'MPV', @@ -79,12 +79,17 @@ const EXTERNAL_PLAYERS = [ { label: 'Outplayer', value: 'outplayer', - platforms: ['ios'], + platforms: ['ios', 'visionos'], + }, + { + label: 'Moonplayer', + value: 'moonplayer', + platforms: ['visionos'], }, { label: 'M3U Playlist', value: 'm3u', - platforms: ['ios', 'android', 'windows', 'linux', 'macos'], + platforms: ['ios', 'visionos', 'android', 'windows', 'linux', 'macos'], }, ]; From 24ef298694c05ffa91f9cd71bcaaced9660e5945 Mon Sep 17 00:00:00 2001 From: Namyts <35004248+Namyts@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:20:28 +0100 Subject: [PATCH 21/48] memo stuff --- .../MetaDetails/StreamsList/Stream/Stream.js | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index a5539198b..495eed42d 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -116,9 +116,13 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio } }, [props.onClick, profile.settings, markVideoAsWatched]); - const copyMagneticLinkToClipboard = React.useCallback((event) => { + const streamLink = React.useMemo(() => { + return deepLinks?.externalPlayer?.download; + }, [deepLinks]); + + const copyStreamLink = React.useCallback((event) => { event.preventDefault(); - if (deepLinks?.externalPlayer?.download && navigator?.clipboard) { + if (streamLink && navigator?.clipboard) { navigator.clipboard.writeText(deepLinks.externalPlayer.download) .then(() => { toast.show({ @@ -143,7 +147,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio }); } closeMenu(); - }, []); + }, [streamLink]); const renderThumbnailFallback = React.useCallback(() => ( @@ -186,21 +190,23 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio ); }, - [] + [onClick] ); - const renderMenu = function renderMenu() { - return ( -
- - {deepLinks?.externalPlayer?.download && } -
- ); - }; + const renderMenu = React.useMemo( + () => { + return ( +
+ + {streamLink && } +
+ ); + }, [copyStreamLink, onClick] + ); return ( Date: Fri, 26 Jul 2024 10:24:28 +0100 Subject: [PATCH 22/48] render menu formatting --- .../MetaDetails/StreamsList/Stream/Stream.js | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 495eed42d..23a1ce607 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -194,18 +194,19 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio ); const renderMenu = React.useMemo( - () => { - return ( -
- - {streamLink && } -
- ); - }, [copyStreamLink, onClick] + () => + function renderMenu() { + return ( +
+ + {streamLink && } +
+ ); + }, [copyStreamLink, onClick] ); return ( From 37103862bd7d0fd85347c58569dd82e7e6da997a Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 11:38:33 +0200 Subject: [PATCH 23/48] ci: add contents write permission to build workflow --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 950cd250a..fceb851fc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,9 @@ on: # Allow manual dispatch in GH workflow_dispatch: +permissions: + contents: write + jobs: build: runs-on: ubuntu-latest From 5de7d1e9379e7d404535e0e101560c910e93a217 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 12:31:14 +0200 Subject: [PATCH 24/48] fix(MetaDetails): list container overflow on mobile --- src/routes/MetaDetails/StreamsList/styles.less | 1 + src/routes/MetaDetails/VideosList/styles.less | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/routes/MetaDetails/StreamsList/styles.less b/src/routes/MetaDetails/StreamsList/styles.less index 295478f2f..3ddb27813 100644 --- a/src/routes/MetaDetails/StreamsList/styles.less +++ b/src/routes/MetaDetails/StreamsList/styles.less @@ -182,6 +182,7 @@ .streams-container { margin-top: 0; + overflow: visible; scrollbar-color: @color-surface-light5-20 transparent; &::-webkit-scrollbar-thumb { diff --git a/src/routes/MetaDetails/VideosList/styles.less b/src/routes/MetaDetails/VideosList/styles.less index 40146c289..e1b2215ae 100644 --- a/src/routes/MetaDetails/VideosList/styles.less +++ b/src/routes/MetaDetails/VideosList/styles.less @@ -74,5 +74,9 @@ @media only screen and (max-width: @minimum) { .videos-list-container { overflow: visible; + + .videos-container { + overflow: auto; + } } } \ No newline at end of file From a65f9509bb192dd427ea7009cbdaa90954c923b6 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 13:45:25 +0200 Subject: [PATCH 25/48] ci: trigger either on push or pull_request for build workflow --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fceb851fc..f5d07029e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,10 +3,10 @@ name: Build on: push: branches: - - '**' + - development pull_request: branches: - - '**' + - development # Allow manual dispatch in GH workflow_dispatch: From c9b0463b056e3ff48b097a2d1eae59b31e16980e Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 13:46:57 +0200 Subject: [PATCH 26/48] ci(build): ignore tags on push --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5d07029e..b13674628 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,8 @@ on: push: branches: - development + tags-ignore: + - '**' pull_request: branches: - development From 396f44ed8a5f0d2937b131099931becbe023225c Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 14:55:38 +0200 Subject: [PATCH 27/48] chore(Stream): formatting --- .../MetaDetails/StreamsList/Stream/Stream.js | 126 +++++++++--------- .../StreamsList/Stream/styles.less | 1 + 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 23a1ce607..aa47b1765 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -4,11 +4,11 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); +const { t } = require('i18next'); const { Button, Image, useProfile, platform, useToast, Popup, useBinaryState } = require('stremio/common'); const { useServices } = require('stremio/services'); const { useRouteFocused } = require('stremio-router'); const StreamPlaceholder = require('./StreamPlaceholder'); -const { t } = require('i18next'); const styles = require('./styles'); const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => { @@ -19,12 +19,6 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false); - React.useEffect(() => { - if (!routeFocused) { - closeMenu(); - } - }, [routeFocused]); - const popupLabelOnMouseUp = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented) { if (event.nativeEvent.ctrlKey || event.nativeEvent.button === 2) { @@ -89,6 +83,10 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio null; }, [href, deepLinks]); + const streamLink = React.useMemo(() => { + return deepLinks?.externalPlayer?.download; + }, [deepLinks]); + const markVideoAsWatched = React.useCallback(() => { if (typeof videoId === 'string') { core.transport.dispatch({ @@ -116,12 +114,9 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio } }, [props.onClick, profile.settings, markVideoAsWatched]); - const streamLink = React.useMemo(() => { - return deepLinks?.externalPlayer?.download; - }, [deepLinks]); - const copyStreamLink = React.useCallback((event) => { event.preventDefault(); + closeMenu(); if (streamLink && navigator?.clipboard) { navigator.clipboard.writeText(deepLinks.externalPlayer.download) .then(() => { @@ -146,68 +141,69 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio timeout: 4000, }); } - closeMenu(); }, [streamLink]); const renderThumbnailFallback = React.useCallback(() => ( ), []); - const renderLabel = React.useMemo( - () => - function renderLabel({ className, thumbnail, progress, addonName, name, description, children, ...props }) { - return ( - - ); - }, - [onClick] - ); + const renderLabel = React.useMemo(() => function renderLabel({ className, thumbnail, progress, addonName, name, description, children, ...props }) { + return ( + + ); + }, [onClick]); - const renderMenu = React.useMemo( - () => - function renderMenu() { - return ( -
- - {streamLink && + { + streamLink && + } -
- ); - }, [copyStreamLink, onClick] - ); + + } +
+ ); + }, [copyStreamLink, onClick]); + + React.useEffect(() => { + if (!routeFocused) { + closeMenu(); + } + }, [routeFocused]); return ( Date: Fri, 26 Jul 2024 16:26:04 +0300 Subject: [PATCH 28/48] feat: detect vision os as a platform --- src/common/platform.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/common/platform.js b/src/common/platform.js index 1e112de6d..170967f85 100644 --- a/src/common/platform.js +++ b/src/common/platform.js @@ -1,8 +1,8 @@ -// Copyright (C) 2017-2023 Smart code 203358507 +// Copyright (C) 2017-2024 Smart code 203358507 // this detects ipad properly in safari // while bowser does not -function iOS() { +const iOS = () => { return [ 'iPad Simulator', 'iPhone Simulator', @@ -11,14 +11,20 @@ function iOS() { 'iPhone', 'iPod' ].includes(navigator.platform) - || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); -} + || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); +}; const Bowser = require('bowser'); const browser = Bowser.parse(window.navigator?.userAgent || ''); -const name = iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase(); +const isVisionProUser = () => { + const isMacintosh = navigator.userAgent.includes('Macintosh'); + const hasFiveTouchPoints = navigator.maxTouchPoints === 5; + return isMacintosh && hasFiveTouchPoints; +}; + +const name = isVisionProUser() ? 'visionos' : (iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase()); module.exports = { name, From 85b0391cbcc443591e791754909853727bf3ad84 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 26 Jul 2024 17:09:56 +0300 Subject: [PATCH 29/48] chore: stremio-core-web - use GH pages version for the feature Signed-off-by: Lachezar Lechev --- package-lock.json | 7 ++++--- package.json | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 351558728..6854816cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.7", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2972,8 +2972,9 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.47.7.tgz", - "integrity": "sha512-3hTie3Yx6198TY1rS2fdA5HKPmejqTDbE8C05+HdqM6oXor9TXVoSjY9AMPlSVUJvu40sP3oeenhe2MRBUQizw==", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "integrity": "sha512-JnnFAlSkLUc+Cl+W1KhpCqLrTnjJPmc1PpDojYF2BIVzvSmwi4VRA8FinxI5c+Nn4LQ2xS8afRBnE1p/X0PxlA==", + "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index 9c2fa37de..ed216269d 100755 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "gpl-2.0", "scripts": { "start": "webpack serve --mode development", + "start-prod": "webpack serve --mode production", "build": "webpack --mode production", "test": "jest", "lint": "eslint src" @@ -15,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.7", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From d8fbd1855b3b90bc9919459cc03969e3e3103381 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 18:06:54 +0200 Subject: [PATCH 30/48] refactor(Stream): use memo deps instead of passing props to Popup --- src/routes/MetaDetails/StreamsList/Stream/Stream.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index aa47b1765..c3f6d8c8f 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -147,9 +147,9 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio ), []); - const renderLabel = React.useMemo(() => function renderLabel({ className, thumbnail, progress, addonName, name, description, children, ...props }) { + const renderLabel = React.useMemo(() => function renderLabel({ className, children, ...props }) { return ( - ); - }, [onClick]); + }, [thumbnail, progress, addonName, name, description, href, target, download, onClick]); const renderMenu = React.useMemo(() => function renderMenu() { return ( @@ -208,13 +208,6 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio return ( Date: Fri, 26 Jul 2024 18:07:20 +0200 Subject: [PATCH 31/48] refactor(Stream): simplify copyStreamLink function --- src/routes/MetaDetails/StreamsList/Stream/Stream.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index c3f6d8c8f..40ccb2f07 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -117,8 +117,8 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const copyStreamLink = React.useCallback((event) => { event.preventDefault(); closeMenu(); - if (streamLink && navigator?.clipboard) { - navigator.clipboard.writeText(deepLinks.externalPlayer.download) + if (streamLink) { + navigator.clipboard.writeText(streamLink) .then(() => { toast.show({ type: 'success', @@ -133,13 +133,6 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio timeout: 4000, }); }); - - } else { - toast.show({ - type: 'error', - title: t('PLAYER_COPY_STREAM_ERROR'), - timeout: 4000, - }); } }, [streamLink]); From fd5cad6fef54373d549b4488c4b72ca7dda2d4a7 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 19:19:36 +0200 Subject: [PATCH 32/48] chore: update stremio-core-web --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 6854816cc..6cf8288b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2973,7 +2973,7 @@ "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-JnnFAlSkLUc+Cl+W1KhpCqLrTnjJPmc1PpDojYF2BIVzvSmwi4VRA8FinxI5c+Nn4LQ2xS8afRBnE1p/X0PxlA==", + "integrity": "sha512-DGEgZQPqmp5Dvsbw6CTHuRmG5iEV+xWIfKqoiUUy6m8cFkYARcFseMz1TlUiOScJaYNg4yLAhHQ8YO85JU3yKA==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" From 8a3fb4cf17876e47c69a2b78232c096c22c85b72 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 Jul 2024 19:47:39 +0200 Subject: [PATCH 33/48] chore: update stremio-core-web --- package-lock.json | 7 +++---- package.json | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cf8288b1..73ef3f20a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@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/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2972,9 +2972,8 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-DGEgZQPqmp5Dvsbw6CTHuRmG5iEV+xWIfKqoiUUy6m8cFkYARcFseMz1TlUiOScJaYNg4yLAhHQ8YO85JU3yKA==", - "license": "MIT", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", + "integrity": "sha512-7ozM/pJFsjKkgGxuDpBn6MSWbHCqsXf4VDXSlBr9+TKLK7YT6cL+lEgMVzQfksK14b3d2LcXQ3BCX2b6F7AIfg==", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index ed216269d..5aaacf3a1 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@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/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From e8958f2c36674dd669087d0c937887cbd8b218f2 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 29 Jul 2024 12:57:21 +0300 Subject: [PATCH 34/48] refactor: rename the Moonplayer string --- src/common/CONSTANTS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index fef278f0b..742c138d6 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -82,7 +82,7 @@ const EXTERNAL_PLAYERS = [ platforms: ['ios', 'visionos'], }, { - label: 'Moonplayer', + label: 'Moonplayer (VisionOS)', value: 'moonplayer', platforms: ['visionos'], }, From 103fce78945ba275f9df0f75bee445ce8a22809b Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 29 Jul 2024 13:05:31 +0300 Subject: [PATCH 35/48] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5aaacf3a1..1a6afee9a 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@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/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "0.47.7", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 54728d63ce28a8ec86cd79eb0f1b509c5e5b7fad Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 29 Jul 2024 13:12:13 +0300 Subject: [PATCH 36/48] add: docs --- src/common/platform.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/platform.js b/src/common/platform.js index 170967f85..7e423489a 100644 --- a/src/common/platform.js +++ b/src/common/platform.js @@ -18,6 +18,8 @@ const Bowser = require('bowser'); const browser = Bowser.parse(window.navigator?.userAgent || ''); +// Edge case: iPad is included in this function +// Keep in mind maxTouchPoints for Vision Pro might change in the future const isVisionProUser = () => { const isMacintosh = navigator.userAgent.includes('Macintosh'); const hasFiveTouchPoints = navigator.maxTouchPoints === 5; From 60d5eb92fe30434a2b624d96945fd537f93b9c37 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 29 Jul 2024 14:25:37 +0300 Subject: [PATCH 37/48] chore: update stremio-core-web to dev. build for branch Signed-off-by: Lachezar Lechev --- package-lock.json | 7 ++++--- package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73ef3f20a..08ed918f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@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/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2972,8 +2972,9 @@ }, "node_modules/@stremio/stremio-core-web": { "version": "0.47.7", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-player-visionos/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-7ozM/pJFsjKkgGxuDpBn6MSWbHCqsXf4VDXSlBr9+TKLK7YT6cL+lEgMVzQfksK14b3d2LcXQ3BCX2b6F7AIfg==", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "integrity": "sha512-VDUcbMlxk4jo0B2vG2dBAQNT502TnFOB742BGy742Qr30m9u4gFFh+zrHMIhMdm3324Du1G1upgvsjcfZTI72w==", + "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" } diff --git a/package.json b/package.json index 1a6afee9a..ed216269d 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@babel/runtime": "7.16.0", "@sentry/browser": "6.13.3", "@stremio/stremio-colors": "5.0.1", - "@stremio/stremio-core-web": "0.47.7", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 2b60b3a5f024033d69e2ef6e6248e89c184dfe85 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 29 Jul 2024 14:00:53 +0200 Subject: [PATCH 38/48] ci(build): use head_ref instead of ref_name when available --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b13674628..dee0401ca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: run: npm run lint # Create recursivelly the destiantion dir with # "--parrents where no error if existing, make parent directories as needed." - - run: mkdir -p ./build/${{ github.ref_name }} + - run: mkdir -p ./build/${{ github.head_ref || github.ref_name }} - name: Deploy to GitHub Pages if: ${{ github.actor != 'dependabot[bot]' }} uses: peaceiris/actions-gh-pages@v4 @@ -40,5 +40,5 @@ jobs: publish_dir: ./build # in stremio, we use `feat/features-name` or `fix/this-bug` # so we need a recursive creation of the destination dir - destination_dir: ${{ github.ref_name }} + destination_dir: ${{ github.head_ref || github.ref_name }} allow_empty_commit: true From b816a0b835fffdaa54b23d6c4b69135ea354e13c Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 19 Aug 2024 16:28:13 +0300 Subject: [PATCH 39/48] chore(stremio-core-web) - Update package with pre-release tag --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08ed918f9..023732cd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@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/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/stremio-core-web-v0.47.8/dev/stremio-stremio-core-web-0.47.8.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", @@ -2971,9 +2971,9 @@ "license": "MIT" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.47.7", - "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/feat/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", - "integrity": "sha512-VDUcbMlxk4jo0B2vG2dBAQNT502TnFOB742BGy742Qr30m9u4gFFh+zrHMIhMdm3324Du1G1upgvsjcfZTI72w==", + "version": "0.47.8", + "resolved": "https://stremio.github.io/stremio-core/stremio-core-web/stremio-core-web-v0.47.8/dev/stremio-stremio-core-web-0.47.8.tgz", + "integrity": "sha512-qdNlsRdUXlNm999QE/smOVFXe/nJ2x28NO5OTriNqGMO1DGcp7HgCJ1V11RG4Tv/DkEDC8w4l0kkoDXspBzL3w==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" diff --git a/package.json b/package.json index ed216269d..f8c4b5d77 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@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/external-moonplayer-url-support-for-ios/dev/stremio-stremio-core-web-0.47.7.tgz", + "@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/stremio-core-web-v0.47.8/dev/stremio-stremio-core-web-0.47.8.tgz", "@stremio/stremio-icons": "5.2.0", "@stremio/stremio-video": "0.0.38", "a-color-picker": "1.2.1", From 48e44a0332a320d3297ac28ac8d6976c7b254903 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 27 Aug 2024 13:43:25 +0300 Subject: [PATCH 40/48] feature: add onDoubleClick function to scrolltop --- src/common/Button/Button.js | 4 +++- .../VerticalNavBar/NavTabButton/NavTabButton.js | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 9d5ef7c1e..b9afe3217 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -6,7 +6,7 @@ const classnames = require('classnames'); const styles = require('./styles'); const { useLongPress } = require('use-long-press'); -const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, ...props }, ref) => { +const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, onDoubleClick, ...props }, ref) => { const longPress = useLongPress(onLongPress, { detect: 'pointer' }); const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { @@ -42,6 +42,7 @@ const Button = React.forwardRef(({ className, href, disabled, children, onLongPr href, onKeyDown, onMouseDown, + onDoubleClick, ...longPress() }, children @@ -58,6 +59,7 @@ Button.propTypes = { onKeyDown: PropTypes.func, onMouseDown: PropTypes.func, onLongPress: PropTypes.func, + onDoubleClick: PropTypes.func }; module.exports = Button; diff --git a/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js b/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js index 7ecef38c6..5372454e2 100644 --- a/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js +++ b/src/common/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js @@ -15,8 +15,17 @@ const NavTabButton = ({ className, logo, icon, label, href, selected, onClick }) : null ), [icon]); + const onDoubleClick = () => { + const scrollableElements = document.querySelectorAll('div'); + + scrollableElements.forEach((element) => { + if (element.scrollHeight > element.clientHeight) { + element.scrollTo(0, 0); + } + }); + }; return ( - +
+ {`S${video?.season}E${video?.episode} ${(video?.title)}`} +
+ + : + null + } + { + Object.keys(streamsByAddon).length > 1 ? + + : + null + } +
{ props.streams.length === 0 ?
@@ -109,30 +142,6 @@ const StreamsList = ({ className, video, ...props }) => { : null } -
- { - video ? - - -
- {`S${video?.season}E${video?.episode} ${(video?.title)}`} -
-
- : - null - } - { - Object.keys(streamsByAddon).length > 1 ? - - : - null - } -
{filteredStreams.map((stream, index) => ( { - return deepLinks ? - typeof deepLinks.player === 'string' ? - deepLinks.player - : - typeof deepLinks.metaDetailsStreams === 'string' ? - deepLinks.metaDetailsStreams - : - null - : - null; + const videoButtonOnClick = React.useCallback(() => { + if (deepLinks) { + if (typeof deepLinks.player === 'string') { + window.location = deepLinks.player; + } else if (typeof deepLinks.metaDetailsStreams === 'string') { + window.location.replace(deepLinks.metaDetailsStreams); + } + } }, [deepLinks]); const renderLabel = React.useMemo(() => function renderLabel({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, children, ...props }) { return ( @@ -171,7 +168,7 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w watched={watched} progress={progress} scheduled={scheduled} - href={href} + onClick={videoButtonOnClick} {...props} onMouseUp={popupLabelOnMouseUp} onLongPress={popupLabelOnLongPress} From b002a1c1943fd30e47356776e03496b31cb5b842 Mon Sep 17 00:00:00 2001 From: ArtificialSloth Date: Tue, 17 Sep 2024 04:41:48 -0400 Subject: [PATCH 44/48] fixed indentation --- src/routes/MetaDetails/StreamsList/StreamsList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 6dd4f1c6f..840664c8b 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -26,7 +26,7 @@ const StreamsList = ({ className, video, ...props }) => { `?${new URLSearchParams({'season': video.season})}` : null - )); + )); } else { window.history.back(); } From a1b94a68ff3ba428f3a31afb3de4cc411c92a18c Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 18 Sep 2024 16:30:40 +0300 Subject: [PATCH 45/48] refactor: inline function --- src/common/MultiselectMenu/Dropdown/Option/Option.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx index 4309e766e..68884610f 100644 --- a/src/common/MultiselectMenu/Dropdown/Option/Option.tsx +++ b/src/common/MultiselectMenu/Dropdown/Option/Option.tsx @@ -1,6 +1,6 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import classNames from 'classnames'; import Button from 'stremio/common/Button'; import styles from './Option.less'; @@ -16,11 +16,15 @@ const Option = ({ option, selectedOption, onSelect }: Props) => { // consider using option.id === selectedOption?.id instead const selected = useMemo(() => option?.value === selectedOption?.value, [option, selectedOption]); + const handleClick = useCallback(() => { + onSelect(option.value); + }, [onSelect, option.value]); + return (