import Button from '@app/components/Common/Button'; import ConfirmButton from '@app/components/Common/ConfirmButton'; import SlideOver from '@app/components/Common/SlideOver'; import Tooltip from '@app/components/Common/Tooltip'; import DownloadBlock from '@app/components/DownloadBlock'; import IssueBlock from '@app/components/IssueBlock'; import RequestBlock from '@app/components/RequestBlock'; import useSettings from '@app/hooks/useSettings'; import { Permission, useUser } from '@app/hooks/useUser'; import globalMessages from '@app/i18n/globalMessages'; import { Bars4Icon, ServerIcon } from '@heroicons/react/24/outline'; import { CheckCircleIcon, DocumentMinusIcon, TrashIcon, } from '@heroicons/react/24/solid'; import { IssueStatus } from '@server/constants/issue'; import { MediaRequestStatus, MediaStatus, MediaType, } from '@server/constants/media'; import { MediaServerType } from '@server/constants/server'; import type { MediaWatchDataResponse } from '@server/interfaces/api/mediaInterfaces'; import type { RadarrSettings, SonarrSettings } from '@server/lib/settings'; import type { MovieDetails } from '@server/models/Movie'; import type { TvDetails } from '@server/models/Tv'; import axios from 'axios'; import getConfig from 'next/config'; import Link from 'next/link'; import { defineMessages, useIntl } from 'react-intl'; import useSWR from 'swr'; const messages = defineMessages({ manageModalTitle: 'Manage {mediaType}', manageModalIssues: 'Open Issues', manageModalRequests: 'Requests', manageModalMedia: 'Media', manageModalMedia4k: '4K Media', manageModalAdvanced: 'Advanced', manageModalNoRequests: 'No requests.', manageModalClearMedia: 'Clear Data', manageModalClearMediaWarning: '* This will irreversibly remove all data for this {mediaType}, including any requests. If this item exists in your {mediaServerName} library, the media information will be recreated during the next scan.', manageModalRemoveMediaWarning: '* This will irreversibly remove this {mediaType} from {arr}, including all files.', openarr: 'Open in {arr}', removearr: 'Remove from {arr}', openarr4k: 'Open in 4K {arr}', removearr4k: 'Remove from 4K {arr}', downloadstatus: 'Downloads', markavailable: 'Mark as Available', mark4kavailable: 'Mark as Available in 4K', markallseasonsavailable: 'Mark All Seasons as Available', markallseasons4kavailable: 'Mark All Seasons as Available in 4K', opentautulli: 'Open in Tautulli', plays: '{playCount, number} {playCount, plural, one {play} other {plays}}', pastdays: 'Past {days, number} Days', alltime: 'All Time', playedby: 'Played By', movie: 'movie', tvshow: 'series', }); const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { return (movie as MovieDetails).title !== undefined; }; interface ManageSlideOverProps { // mediaType: 'movie' | 'tv'; show?: boolean; onClose: () => void; revalidate: () => void; } interface ManageSlideOverMovieProps extends ManageSlideOverProps { mediaType: 'movie'; data: MovieDetails; } interface ManageSlideOverTvProps extends ManageSlideOverProps { mediaType: 'tv'; data: TvDetails; } const ManageSlideOver = ({ show, mediaType, onClose, data, revalidate, }: ManageSlideOverMovieProps | ManageSlideOverTvProps) => { const { user: currentUser, hasPermission } = useUser(); const intl = useIntl(); const settings = useSettings(); const { publicRuntimeConfig } = getConfig(); const { data: watchData } = useSWR( settings.currentSettings.mediaServerType === MediaServerType.PLEX && data.mediaInfo && hasPermission(Permission.ADMIN) ? `/api/v1/media/${data.mediaInfo.id}/watch_data` : null ); const { data: radarrData } = useSWR( hasPermission(Permission.ADMIN) ? '/api/v1/settings/radarr' : null ); const { data: sonarrData } = useSWR( hasPermission(Permission.ADMIN) ? '/api/v1/settings/sonarr' : null ); const deleteMedia = async () => { if (data.mediaInfo) { await axios.delete(`/api/v1/media/${data.mediaInfo.id}`); revalidate(); } }; const deleteMediaFile = async () => { if (data.mediaInfo) { await axios.delete(`/api/v1/media/${data.mediaInfo.id}/file`); await axios.delete(`/api/v1/media/${data.mediaInfo.id}`); revalidate(); } }; const isDefaultService = () => { if (data.mediaInfo) { if (data.mediaInfo.mediaType === MediaType.MOVIE) { return ( radarrData?.find( (radarr) => radarr.isDefault && radarr.id === data.mediaInfo?.serviceId ) !== undefined ); } else { return ( sonarrData?.find( (sonarr) => sonarr.isDefault && sonarr.id === data.mediaInfo?.serviceId ) !== undefined ); } } return false; }; const markAvailable = async (is4k = false) => { if (data.mediaInfo) { await axios.post(`/api/v1/media/${data.mediaInfo?.id}/available`, { is4k, }); revalidate(); } }; const requests = data.mediaInfo?.requests?.filter( (request) => request.status !== MediaRequestStatus.DECLINED ) ?? []; const openIssues = data.mediaInfo?.issues?.filter( (issue) => issue.status === IssueStatus.OPEN ) ?? []; const styledPlayCount = (playCount: number): JSX.Element => { return ( <> {intl.formatMessage(messages.plays, { playCount, strong: (msg: React.ReactNode) => ( {msg} ), })} ); }; return ( onClose()} subText={isMovie(data) ? data.title : data.name} >
{((data?.mediaInfo?.downloadStatus ?? []).length > 0 || (data?.mediaInfo?.downloadStatus4k ?? []).length > 0) && (

{intl.formatMessage(messages.downloadstatus)}

    {data.mediaInfo?.downloadStatus?.map((status, index) => (
  • ))} {data.mediaInfo?.downloadStatus4k?.map((status, index) => (
  • ))}
)} {hasPermission([Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES], { type: 'or', }) && openIssues.length > 0 && (

{intl.formatMessage(messages.manageModalIssues)}

    {openIssues.map((issue) => (
  • ))}
)} {requests.length > 0 && (

{intl.formatMessage(messages.manageModalRequests)}

    {requests.map((request) => (
  • revalidate()} />
  • ))}
)} {hasPermission(Permission.ADMIN) && (data.mediaInfo?.serviceUrl || data.mediaInfo?.tautulliUrl || watchData?.data) && (

{intl.formatMessage(messages.manageModalMedia)}

{(watchData?.data || data.mediaInfo?.tautulliUrl) && (
{!!watchData?.data && (
{intl.formatMessage(messages.pastdays, { days: 7, })}
{styledPlayCount(watchData.data.playCount7Days)}
{intl.formatMessage(messages.pastdays, { days: 30, })}
{styledPlayCount(watchData.data.playCount30Days)}
{intl.formatMessage(messages.alltime)}
{styledPlayCount(watchData.data.playCount)}
{!!watchData.data.users.length && (
{intl.formatMessage(messages.playedby)} {watchData.data.users.map((user) => ( {user.displayName} ))}
)}
)} {data.mediaInfo?.tautulliUrl && ( )}
)} {data.mediaInfo?.serviceUrl && ( )} {hasPermission(Permission.ADMIN) && data?.mediaInfo?.serviceUrl && isDefaultService() && (
deleteMediaFile()} confirmText={intl.formatMessage( globalMessages.areyousure )} className="w-full" > {intl.formatMessage(messages.removearr, { arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr', })}
{intl.formatMessage( messages.manageModalRemoveMediaWarning, { mediaType: intl.formatMessage( mediaType === 'movie' ? messages.movie : messages.tvshow ), arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr', } )}
)}
)} {hasPermission(Permission.ADMIN) && (data.mediaInfo?.serviceUrl4k || data.mediaInfo?.tautulliUrl4k || watchData?.data4k) && (

{intl.formatMessage(messages.manageModalMedia4k)}

{(watchData?.data4k || data.mediaInfo?.tautulliUrl4k) && (
{watchData?.data4k && (
{intl.formatMessage(messages.pastdays, { days: 7, })}
{styledPlayCount(watchData.data4k.playCount7Days)}
{intl.formatMessage(messages.pastdays, { days: 30, })}
{styledPlayCount( watchData.data4k.playCount30Days )}
{intl.formatMessage(messages.alltime)}
{styledPlayCount(watchData.data4k.playCount)}
{!!watchData.data4k.users.length && (
{intl.formatMessage(messages.playedby)} {watchData.data4k.users.map((user) => ( {user.displayName} ))}
)}
)} {data.mediaInfo?.tautulliUrl4k && ( )}
)} {data?.mediaInfo?.serviceUrl4k && ( <> {isDefaultService() && (
deleteMediaFile()} confirmText={intl.formatMessage( globalMessages.areyousure )} className="w-full" > {intl.formatMessage(messages.removearr4k, { arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr', })}
{intl.formatMessage( messages.manageModalRemoveMediaWarning, { mediaType: intl.formatMessage( mediaType === 'movie' ? messages.movie : messages.tvshow ), arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr', } )}
)} )}
)} {hasPermission(Permission.ADMIN) && data?.mediaInfo && (

{intl.formatMessage(messages.manageModalAdvanced)}

{data?.mediaInfo.status !== MediaStatus.AVAILABLE && ( )} {data?.mediaInfo.status4k !== MediaStatus.AVAILABLE && settings.currentSettings.series4kEnabled && ( )}
deleteMedia()} confirmText={intl.formatMessage(globalMessages.areyousure)} className="w-full" > {intl.formatMessage(messages.manageModalClearMedia)}
{intl.formatMessage(messages.manageModalClearMediaWarning, { mediaType: intl.formatMessage( mediaType === 'movie' ? messages.movie : messages.tvshow ), mediaServerName: publicRuntimeConfig.JELLYFIN_TYPE == 'emby' ? 'Emby' : settings.currentSettings.mediaServerType === MediaServerType.PLEX ? 'Plex' : 'Jellyfin', })}
)}
); }; export default ManageSlideOver;