// Copyright (C) 2017-2023 Smart code 203358507 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 { useCore } = require('stremio/core'); const { useProfile, usePlatform, useToast, useBinaryState } = require('stremio/common'); const { Button, Image, Popup } = require('stremio/components'); const { useRouteFocused } = require('stremio-router'); const StreamPlaceholder = require('./StreamPlaceholder'); const styles = require('./styles'); const Stream = ({ className, videoId, videoReleased, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => { const profile = useProfile(); const toast = useToast(); const platform = usePlatform(); const core = useCore(); const routeFocused = useRouteFocused(); 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; }, [deepLinks]); const download = React.useMemo(() => { return href === deepLinks?.externalPlayer?.playlist ? deepLinks.externalPlayer.fileName : null; }, [href, deepLinks]); const target = React.useMemo(() => { return href === deepLinks?.externalPlayer?.web ? '_blank' : null; }, [href, deepLinks]); const streamLink = React.useMemo(() => { return deepLinks?.externalPlayer?.streaming; }, [deepLinks]); const downloadLink = React.useMemo(() => { return deepLinks?.externalPlayer?.download; }, [deepLinks]); const magnetLink = React.useMemo(() => { return deepLinks?.externalPlayer?.magnet; }, [deepLinks]); const markVideoAsWatched = React.useCallback(() => { if (typeof videoId === 'string') { core.transport.dispatch({ action: 'MetaDetails', args: { action: 'MarkVideoAsWatched', args: [{ id: videoId, released: videoReleased }, true] } }); } }, [videoId, videoReleased]); const onClick = React.useCallback((event) => { if (event.nativeEvent.togglePopupPrevented) { return; } 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 copyMagnetLink = React.useCallback((event) => { event.preventDefault(); closeMenu(); if (magnetLink) { navigator.clipboard.writeText(magnetLink) .then(() => { toast.show({ type: 'success', title: t('PLAYER_COPY_MAGNET_LINK_SUCCESS'), timeout: 4000 }); }) .catch(() => { toast.show({ type: 'error', title: t('PLAYER_COPY_MAGNET_LINK_ERROR'), timeout: 4000, }); }); } }, [magnetLink]); const copyDownloadLink = React.useCallback((event) => { event.preventDefault(); closeMenu(); if (downloadLink) { navigator.clipboard.writeText(downloadLink) .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, }); }); } }, [downloadLink]); const copyStreamLink = React.useCallback((event) => { event.preventDefault(); closeMenu(); if (streamLink) { navigator.clipboard.writeText(streamLink) .then(() => { toast.show({ type: 'success', title: t('PLAYER_COPY_STREAM_SUCCESS'), timeout: 4000 }); }) .catch(() => { toast.show({ type: 'error', title: t('PLAYER_COPY_STREAM_ERROR'), timeout: 4000, }); }); } }, [streamLink]); const renderThumbnailFallback = React.useCallback(() => ( ), []); const renderLabel = React.useMemo(() => function renderLabel({ className, children, ...props }) { return ( ); }, [thumbnail, progress, addonName, name, description, href, target, download, onClick]); const renderMenu = React.useMemo(() => function renderMenu() { return (
{description}
{ streamLink && } { magnetLink && } { downloadLink && }
); }, [copyStreamLink, onClick]); React.useEffect(() => { if (!routeFocused) { closeMenu(); } }, [routeFocused]); return ( ); }; Stream.Placeholder = StreamPlaceholder; Stream.propTypes = { className: PropTypes.string, videoId: PropTypes.string, videoReleased: PropTypes.instanceOf(Date), addonName: PropTypes.string, name: PropTypes.string, description: PropTypes.string, thumbnail: PropTypes.string, progress: PropTypes.number, deepLinks: PropTypes.shape({ player: PropTypes.string, externalPlayer: PropTypes.shape({ download: PropTypes.string, magnet: PropTypes.string, streaming: PropTypes.string, playlist: PropTypes.string, fileName: PropTypes.string, web: PropTypes.string, openPlayer: PropTypes.shape({ ios: PropTypes.string, android: PropTypes.string, windows: PropTypes.string, macos: PropTypes.string, linux: PropTypes.string, }) }) }), onClick: PropTypes.func }; module.exports = Stream;