// 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 { 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 }) => { 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) { 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 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 (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 streamLink = React.useMemo(() => { return deepLinks?.externalPlayer?.download; }, [deepLinks]); const copyStreamLink = React.useCallback((event) => { event.preventDefault(); if (streamLink && navigator?.clipboard) { navigator.clipboard.writeText(deepLinks.externalPlayer.download) .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, }); }); } else { toast.show({ type: 'error', title: t('PLAYER_COPY_STREAM_ERROR'), 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 renderMenu = React.useMemo( () => function renderMenu() { return (
{streamLink && }
); }, [copyStreamLink, onClick] ); 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, 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;