import React, { useCallback, useMemo, useState } from 'react'; import type { SessionInfo } from '@jellyfin/sdk/lib/generated-client/models/session-info'; import Typography from '@mui/material/Typography'; import Card from '@mui/material/Card'; import CardMedia from '@mui/material/CardMedia'; import { getDeviceIcon } from 'utils/image'; import Stack from '@mui/material/Stack'; import getNowPlayingName from '../../sessions/utils/getNowPlayingName'; import getSessionNowPlayingTime from '../../sessions/utils/getSessionNowPlayingTime'; import getNowPlayingImageUrl from '../../sessions/utils/getNowPlayingImageUrl'; import { getDefaultBackgroundClass } from 'components/cardbuilder/cardBuilderUtils'; import Comment from '@mui/icons-material/Comment'; import PlayArrow from '@mui/icons-material/PlayArrow'; import Pause from '@mui/icons-material/Pause'; import Stop from '@mui/icons-material/Stop'; import Info from '@mui/icons-material/Info'; import LinearProgress from '@mui/material/LinearProgress'; import CardActions from '@mui/material/CardActions'; import IconButton from '@mui/material/IconButton'; import SimpleAlert from 'components/SimpleAlert'; import playmethodhelper from 'components/playback/playmethodhelper'; import globalize from 'lib/globalize'; import getSessionNowPlayingStreamInfo from '../../sessions/utils/getSessionNowPlayingStreamInfo'; import { useSendPlayStateCommand } from '../../sessions/api/usePlayPauseSession'; import { PlaystateCommand } from '@jellyfin/sdk/lib/generated-client/models/playstate-command'; import InputDialog from 'components/InputDialog'; import { useSendMessage } from '../../sessions/api/useSendMessage'; type DeviceCardProps = { device: SessionInfo; }; const DeviceCard = ({ device }: DeviceCardProps) => { const [ playbackInfoTitle, setPlaybackInfoTitle ] = useState(''); const [ playbackInfoDesc, setPlaybackInfoDesc ] = useState(''); const [ isPlaybackInfoOpen, setIsPlaybackInfoOpen ] = useState(false); const [ isMessageDialogOpen, setIsMessageDialogOpen ] = useState(false); const sendMessage = useSendMessage(); const playStateCommand = useSendPlayStateCommand(); const onPlayPauseSession = useCallback(() => { if (device.Id) { playStateCommand.mutate({ sessionId: device.Id, command: PlaystateCommand.PlayPause }); } }, [ device, playStateCommand ]); const onStopSession = useCallback(() => { if (device.Id) { playStateCommand.mutate({ sessionId: device.Id, command: PlaystateCommand.Stop }); } }, [ device, playStateCommand ]); const onMessageSend = useCallback((message: string) => { if (device.Id) { sendMessage.mutate({ sessionId: device.Id, messageCommand: { Text: message, TimeoutMs: 5000 } }); setIsMessageDialogOpen(false); } }, [ sendMessage, device ]); const showMessageDialog = useCallback(() => { setIsMessageDialogOpen(true); }, []); const onMessageDialogClose = useCallback(() => { setIsMessageDialogOpen(false); }, []); const closePlaybackInfo = useCallback(() => { setIsPlaybackInfoOpen(false); }, []); const showPlaybackInfo = useCallback(() => { const displayPlayMethod = playmethodhelper.getDisplayPlayMethod(device); switch (displayPlayMethod) { case 'Remux': setPlaybackInfoTitle(globalize.translate('Remuxing')); setPlaybackInfoDesc(globalize.translate('RemuxHelp1') + '\n' + globalize.translate('RemuxHelp2')); break; case 'DirectStream': setPlaybackInfoTitle(globalize.translate('DirectStreaming')); setPlaybackInfoDesc(globalize.translate('DirectStreamHelp1') + '\n' + globalize.translate('DirectStreamHelp2')); break; case 'DirectPlay': setPlaybackInfoTitle(globalize.translate('DirectPlaying')); setPlaybackInfoDesc(globalize.translate('DirectPlayHelp')); break; case 'Transcode': { const transcodeReasons = device.TranscodingInfo?.TranscodeReasons as string[] | undefined; const localizedTranscodeReasons = transcodeReasons?.map(transcodeReason => globalize.translate(transcodeReason)) || []; setPlaybackInfoTitle(globalize.translate('Transcoding')); setPlaybackInfoDesc( globalize.translate('MediaIsBeingConverted') + '\n\n' + getSessionNowPlayingStreamInfo(device) + '\n\n' + globalize.translate('LabelReasonForTranscoding') + '\n' + localizedTranscodeReasons.join('\n') ); break; } } setIsPlaybackInfoOpen(true); }, [ device ]); const nowPlayingName = useMemo(() => ( getNowPlayingName(device) ), [ device ]); const nowPlayingImage = useMemo(() => ( device.NowPlayingItem && getNowPlayingImageUrl(device.NowPlayingItem) ), [device]); const runningTime = useMemo(() => ( getSessionNowPlayingTime(device) ), [ device ]); const deviceIcon = useMemo(() => ( getDeviceIcon(device) ), [ device ]); const canControl = device.ServerId && device.SupportsRemoteControl; const isPlayingMedia = !!device.NowPlayingItem; return ( {device.DeviceName {device.DeviceName} {device.Client + ' ' + device.ApplicationVersion} {nowPlayingName.image ? ( Media Icon ) : ( {nowPlayingName.topText} )} {nowPlayingName.bottomText} {device.NowPlayingItem && ( {runningTime.start} / {runningTime.end} )} {(device.PlayState?.PositionTicks != null && device.NowPlayingItem?.RunTimeTicks != null) && ( )} {canControl && isPlayingMedia && ( <> {device.PlayState?.IsPaused ? : } )} {isPlayingMedia && ( )} {canControl && ( )} {device.UserName && ( {device.UserName} )} ); }; export default DeviceCard;