{
typeof thumbnail === 'string' && thumbnail.length > 0 ?
@@ -140,7 +146,8 @@ Stream.propTypes = {
})
})
}),
- onClick: PropTypes.func
+ onClick: PropTypes.func,
+ onContextMenu: PropTypes.func
};
module.exports = Stream;
diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js
index ae7d2416e..728f773b3 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 } = require('stremio/common');
+const { Button, Image, Multiselect, useToast } = require('stremio/common');
const { useServices } = require('stremio/services');
const Stream = require('./Stream');
const styles = require('./styles');
@@ -15,6 +15,7 @@ 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);
@@ -41,6 +42,17 @@ const StreamsList = ({ className, video, ...props }) => {
}
});
},
+ 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
}))
};
@@ -146,6 +158,7 @@ const StreamsList = ({ className, video, ...props }) => {
progress={stream.progress}
deepLinks={stream.deepLinks}
onClick={stream.onClick}
+ onContextMenu={stream.onContextMenu}
/>
))}
From 179afa67801f7720c1d73d1b78cba9c338c2cb26 Mon Sep 17 00:00:00 2001
From: Namyts <35004248+Namyts@users.noreply.github.com>
Date: Tue, 23 Jul 2024 00:45:29 +0100
Subject: [PATCH 02/14] added context menu to steam list items with ability to
copy stream infohash. switch steam to use Popup, just like Video
---
.../MetaDetails/StreamsList/Stream/Stream.js | 270 +++++++++++++-----
.../StreamsList/Stream/styles.less | 61 ++++
.../MetaDetails/StreamsList/StreamsList.js | 195 +++++++------
3 files changed, 349 insertions(+), 177 deletions(-)
diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js
index d386cbf95..5cb31b251 100644
--- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js
+++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js
@@ -4,47 +4,93 @@ 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 } = 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,
+ infoHash,
+ ...props
+}) => {
const profile = useProfile();
const toast = useToast();
const { core } = useServices();
+ const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false);
+
+ const popupLabelOnMouseUp = React.useCallback((event) => {
+ if (!event.nativeEvent.togglePopupPrevented) {
+ if (event.nativeEvent.ctrlKey || event.nativeEvent.button === 2) {
+ event.preventDefault();
+ toggleMenu();
+ }
+ }
+ }, []);
+ const popupLabelOnContextMenu = React.useCallback((event) => {
+ if (!event.nativeEvent.togglePopupPrevented && !event.nativeEvent.ctrlKey) {
+ event.preventDefault();
+ }
+ }, [toggleMenu]);
+ const popupLabelOnLongPress = React.useCallback((event) => {
+ if (event.nativeEvent.pointerType !== 'mouse' && !event.nativeEvent.togglePopupPrevented) {
+ toggleMenu();
+ }
+ }, [toggleMenu]);
+ const popupMenuOnPointerDown = React.useCallback((event) => {
+ event.nativeEvent.togglePopupPrevented = true;
+ }, []);
+ const popupMenuOnContextMenu = React.useCallback((event) => {
+ event.nativeEvent.togglePopupPrevented = true;
+ }, []);
+ const popupMenuOnClick = React.useCallback((event) => {
+ event.nativeEvent.togglePopupPrevented = true;
+ }, []);
+ const popupMenuOnKeyDown = React.useCallback((event) => {
+ event.nativeEvent.buttonClickPrevented = true;
+ }, []);
+
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(() => {
@@ -53,68 +99,136 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio
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();
+ 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]
+ );
+
+ const copyInfoHashToClipboard = React.useCallback((event) => {
+ event.preventDefault();
+ if (infoHash && navigator?.clipboard) {
+ navigator?.clipboard?.writeText(infoHash);
toast.show({
type: 'success',
- title: 'Stream opened in external player',
- timeout: 4000
+ title: t('PLAYER_COPY_DOWNLOAD_LINK_SUCCESS'),
+ timeout: 4000,
});
}
+ }, []);
- if (typeof props.onClick === 'function') {
- props.onClick(event);
- }
- }, [props.onClick, profile.settings, markVideoAsWatched]);
+ const renderThumbnailFallback = React.useCallback(
+ () => (
+
- {
- 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') ?
-
- :
- filteredStreams.length === 0 ?
-
-
-
+
+ ) : props.streams.every((streams) => streams.content.type === 'Err') ? (
+
+ ) : 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 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 03/14] 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 04/14] 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 (
-
+
- {typeof thumbnail === 'string' && thumbnail.length > 0 ? (
-
-
-
- ) : (
-
-
- {name || addonName}
+ {
+ typeof thumbnail === 'string' && thumbnail.length > 0 ?
+
+
-
- )}
- {progress !== null && !isNaN(progress) && progress > 0 ? (
-
- ) : null}
-
-
- {description}
+ :
+
+ }
+ {
+ progress !== null && !isNaN(progress) && progress > 0 ?
+
+ :
+ null
+ }
+
{description}
{children}
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 05/14] 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') ? (
-
- ) : filteredStreams.length === 0 ? (
-
-
-
-
- ) : (
-
- {countLoadingAddons > 0 ? (
-
-
- {countLoadingAddons} {t('MOBILE_ADDONS_LOADING')}
-
-
+ :
+ props.streams.every((streams) => streams.content.type === 'Err') ?
+
- ) : 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) => (
-
- ))}
-
-
- )}
-
+ }
+
- {t('ADDON_CATALOGUE_MORE')}
+ { t('ADDON_CATALOGUE_MORE') }
);
@@ -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 06/14] 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 07/14] 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 08/14] 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 (
-
+
{t('CTX_PLAY')}
- {deepLinks?.externalPlayer?.download &&
+ {deepLinks?.externalPlayer?.download &&
{t('CTX_COPY_VIDEO_DOWNLOAD_LINK')}
}
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 09/14] 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 (
@@ -178,17 +186,17 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio
);
},
- []
+ [ thumbnail, progress, addonName, name, description ]
);
const renderMenu = function renderMenu() {
return (
-
+
{t('CTX_PLAY')}
- {deepLinks?.externalPlayer?.download &&
- {t('CTX_COPY_VIDEO_DOWNLOAD_LINK')}
+ {deepLinks?.externalPlayer?.download &&
+ {t('CTX_COPY_STREAM_LINK')}
}
);
@@ -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 10/14] 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 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 11/14] 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 (
-
-
- {t('CTX_PLAY')}
-
- {deepLinks?.externalPlayer?.download &&
- {t('CTX_COPY_STREAM_LINK')}
- }
-
- );
- };
+ const renderMenu = React.useMemo(
+ () => {
+ return (
+
+
+ {t('CTX_PLAY')}
+
+ {streamLink &&
+ {t('CTX_COPY_STREAM_LINK')}
+ }
+
+ );
+ }, [copyStreamLink, onClick]
+ );
return (
Date: Fri, 26 Jul 2024 10:24:28 +0100
Subject: [PATCH 12/14] 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 (
-
-
- {t('CTX_PLAY')}
-
- {streamLink &&
- {t('CTX_COPY_STREAM_LINK')}
- }
-
- );
- }, [copyStreamLink, onClick]
+ () =>
+ function renderMenu() {
+ return (
+
+
+ {t('CTX_PLAY')}
+
+ {streamLink &&
+ {t('CTX_COPY_STREAM_LINK')}
+ }
+
+ );
+ }, [copyStreamLink, onClick]
);
return (
From a65f9509bb192dd427ea7009cbdaa90954c923b6 Mon Sep 17 00:00:00 2001
From: Tim
Date: Fri, 26 Jul 2024 13:45:25 +0200
Subject: [PATCH 13/14] 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 14/14] 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