mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Extracted Series and Movie components
This commit is contained in:
parent
36ec2fb1b0
commit
4c60ce0c28
1 changed files with 146 additions and 138 deletions
|
|
@ -6,8 +6,11 @@ import useVideoStore from '../../store/useVideoStore.jsx';
|
|||
import { notifications } from '@mantine/notifications';
|
||||
import {
|
||||
deleteRecordingById,
|
||||
getPosterUrl, getRecordingUrl,
|
||||
getSeasonLabel, getShowVideoUrl, runComSkip,
|
||||
getPosterUrl,
|
||||
getRecordingUrl,
|
||||
getSeasonLabel,
|
||||
getShowVideoUrl,
|
||||
runComSkip,
|
||||
} from '../../utils/cards/RecordingCardUtils.js';
|
||||
import {
|
||||
getRating,
|
||||
|
|
@ -68,6 +71,50 @@ export const RecordingDetailsModal = ({
|
|||
userNow,
|
||||
]);
|
||||
|
||||
const handleOnWatchLive = () => {
|
||||
const rec = childRec;
|
||||
const now = userNow();
|
||||
const s = toUserTime(rec.start_time);
|
||||
const e = toUserTime(rec.end_time);
|
||||
|
||||
if (now.isAfter(s) && now.isBefore(e)) {
|
||||
if (!channelMap[rec.channel]) return;
|
||||
useVideoStore.getState().showVideo(getShowVideoUrl(channelMap[rec.channel], env_mode), 'live');
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnWatchRecording = () => {
|
||||
let fileUrl = getRecordingUrl(childRec.custom_properties, env_mode)
|
||||
if (!fileUrl) return;
|
||||
|
||||
useVideoStore.getState().showVideo(fileUrl, 'vod', {
|
||||
name:
|
||||
childRec.custom_properties?.program?.title || 'Recording',
|
||||
logo: {
|
||||
url: getPosterUrl(
|
||||
childRec.custom_properties?.poster_logo_id,
|
||||
undefined,
|
||||
channelMap[childRec.channel]?.logo?.cache_url
|
||||
)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const handleRunComskip = async (e) => {
|
||||
e.stopPropagation?.();
|
||||
try {
|
||||
await runComSkip(recording)
|
||||
notifications.show({
|
||||
title: 'Removing commercials',
|
||||
message: 'Queued comskip for this recording',
|
||||
color: 'blue.5',
|
||||
autoClose: 2000,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to run comskip', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!recording) return null;
|
||||
|
||||
const EpisodeRow = ({ rec }) => {
|
||||
|
|
@ -149,35 +196,6 @@ export const RecordingDetailsModal = ({
|
|||
);
|
||||
};
|
||||
|
||||
const handleOnWatchLive = () => {
|
||||
const rec = childRec;
|
||||
const now = userNow();
|
||||
const s = toUserTime(rec.start_time);
|
||||
const e = toUserTime(rec.end_time);
|
||||
|
||||
if (now.isAfter(s) && now.isBefore(e)) {
|
||||
if (!channelMap[rec.channel]) return;
|
||||
useVideoStore.getState().showVideo(getShowVideoUrl(channelMap[rec.channel], env_mode), 'live');
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnWatchRecording = () => {
|
||||
let fileUrl = getRecordingUrl(childRec.custom_properties, env_mode)
|
||||
if (!fileUrl) return;
|
||||
|
||||
useVideoStore.getState().showVideo(fileUrl, 'vod', {
|
||||
name:
|
||||
childRec.custom_properties?.program?.title || 'Recording',
|
||||
logo: {
|
||||
url: getPosterUrl(
|
||||
childRec.custom_properties?.poster_logo_id,
|
||||
undefined,
|
||||
channelMap[childRec.channel]?.logo?.cache_url
|
||||
)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const WatchLive = () => {
|
||||
return <Button
|
||||
size="xs"
|
||||
|
|
@ -219,20 +237,103 @@ export const RecordingDetailsModal = ({
|
|||
</Button>;
|
||||
}
|
||||
|
||||
const handleRunComskip = async (e) => {
|
||||
e.stopPropagation?.();
|
||||
try {
|
||||
await runComSkip(recording)
|
||||
notifications.show({
|
||||
title: 'Removing commercials',
|
||||
message: 'Queued comskip for this recording',
|
||||
color: 'blue.5',
|
||||
autoClose: 2000,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to run comskip', error);
|
||||
}
|
||||
const Series = () => {
|
||||
return <Stack gap={10}>
|
||||
{upcomingEpisodes.length === 0 && (
|
||||
<Text size="sm" c="dimmed">
|
||||
No upcoming episodes found
|
||||
</Text>
|
||||
)}
|
||||
{upcomingEpisodes.map((ep) => (
|
||||
<EpisodeRow key={`ep-${ep.id}`} rec={ep} />
|
||||
))}
|
||||
{childOpen && childRec && (
|
||||
<RecordingDetailsModal
|
||||
opened={childOpen}
|
||||
onClose={() => setChildOpen(false)}
|
||||
recording={childRec}
|
||||
channel={channelMap[childRec.channel]}
|
||||
posterUrl={getPosterUrl(
|
||||
childRec.custom_properties?.poster_logo_id,
|
||||
childRec.custom_properties,
|
||||
channelMap[childRec.channel]?.logo?.cache_url
|
||||
)}
|
||||
env_mode={env_mode}
|
||||
onWatchLive={handleOnWatchLive}
|
||||
onWatchRecording={handleOnWatchRecording}
|
||||
/>
|
||||
)}
|
||||
</Stack>;
|
||||
}
|
||||
|
||||
const Movie = () => {
|
||||
return <Flex gap="lg" align="flex-start">
|
||||
<Image
|
||||
src={posterUrl}
|
||||
w={180}
|
||||
h={240}
|
||||
fit="contain"
|
||||
radius="sm"
|
||||
alt={recordingName}
|
||||
fallbackSrc="/logo.png"
|
||||
/>
|
||||
<Stack gap={8} style={{ flex: 1 }}>
|
||||
<Group justify="space-between" align="center">
|
||||
<Text c="dimmed" size="sm">
|
||||
{channel ? `${channel.channel_number} • ${channel.name}` : '—'}
|
||||
</Text>
|
||||
<Group gap={8}>
|
||||
{onWatchLive && <WatchLive />}
|
||||
{onWatchRecording && <WatchRecording />}
|
||||
{onEdit && start.isAfter(userNow()) && <Edit />}
|
||||
{customProps.status === 'completed' &&
|
||||
(!customProps?.comskip ||
|
||||
customProps?.comskip?.status !== 'completed') && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="teal"
|
||||
onClick={handleRunComskip}
|
||||
>
|
||||
Remove commercials
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
</Group>
|
||||
<Text size="sm">
|
||||
{start.format(`${dateformat}, YYYY ${timeformat}`)} – {end.format(timeformat)}
|
||||
</Text>
|
||||
{rating && (
|
||||
<Group gap={8}>
|
||||
<Badge color="yellow" title={ratingSystem}>
|
||||
{rating}
|
||||
</Badge>
|
||||
</Group>
|
||||
)}
|
||||
{description && (
|
||||
<Text size="sm" style={{ whiteSpace: 'pre-wrap' }}>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
{statRows.length > 0 && (
|
||||
<Stack gap={4} pt={6}>
|
||||
<Text fw={600} size="sm">
|
||||
Stream Stats
|
||||
</Text>
|
||||
{statRows.map(([k, v]) => (
|
||||
<Group key={k} justify="space-between">
|
||||
<Text size="xs" c="dimmed">
|
||||
{k}
|
||||
</Text>
|
||||
<Text size="xs">{v}</Text>
|
||||
</Group>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Flex>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
opened={opened}
|
||||
|
|
@ -253,100 +354,7 @@ export const RecordingDetailsModal = ({
|
|||
title: { color: 'white' },
|
||||
}}
|
||||
>
|
||||
{isSeriesGroup ? (
|
||||
<Stack gap={10}>
|
||||
{upcomingEpisodes.length === 0 && (
|
||||
<Text size="sm" c="dimmed">
|
||||
No upcoming episodes found
|
||||
</Text>
|
||||
)}
|
||||
{upcomingEpisodes.map((ep) => (
|
||||
<EpisodeRow key={`ep-${ep.id}`} rec={ep} />
|
||||
))}
|
||||
{childOpen && childRec && (
|
||||
<RecordingDetailsModal
|
||||
opened={childOpen}
|
||||
onClose={() => setChildOpen(false)}
|
||||
recording={childRec}
|
||||
channel={channelMap[childRec.channel]}
|
||||
posterUrl={getPosterUrl(
|
||||
childRec.custom_properties?.poster_logo_id,
|
||||
childRec.custom_properties,
|
||||
channelMap[childRec.channel]?.logo?.cache_url
|
||||
)}
|
||||
env_mode={env_mode}
|
||||
onWatchLive={handleOnWatchLive}
|
||||
onWatchRecording={handleOnWatchRecording}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
) : (
|
||||
<Flex gap="lg" align="flex-start">
|
||||
<Image
|
||||
src={posterUrl}
|
||||
w={180}
|
||||
h={240}
|
||||
fit="contain"
|
||||
radius="sm"
|
||||
alt={recordingName}
|
||||
fallbackSrc="/logo.png"
|
||||
/>
|
||||
<Stack gap={8} style={{ flex: 1 }}>
|
||||
<Group justify="space-between" align="center">
|
||||
<Text c="dimmed" size="sm">
|
||||
{channel ? `${channel.channel_number} • ${channel.name}` : '—'}
|
||||
</Text>
|
||||
<Group gap={8}>
|
||||
{onWatchLive && <WatchLive />}
|
||||
{onWatchRecording && <WatchRecording />}
|
||||
{onEdit && start.isAfter(userNow()) && <Edit />}
|
||||
{customProps.status === 'completed' &&
|
||||
(!customProps?.comskip ||
|
||||
customProps?.comskip?.status !== 'completed') && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="teal"
|
||||
onClick={handleRunComskip}
|
||||
>
|
||||
Remove commercials
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
</Group>
|
||||
<Text size="sm">
|
||||
{start.format(`${dateformat}, YYYY ${timeformat}`)} – {end.format(timeformat)}
|
||||
</Text>
|
||||
{rating && (
|
||||
<Group gap={8}>
|
||||
<Badge color="yellow" title={ratingSystem}>
|
||||
{rating}
|
||||
</Badge>
|
||||
</Group>
|
||||
)}
|
||||
{description && (
|
||||
<Text size="sm" style={{ whiteSpace: 'pre-wrap' }}>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
{statRows.length > 0 && (
|
||||
<Stack gap={4} pt={6}>
|
||||
<Text fw={600} size="sm">
|
||||
Stream Stats
|
||||
</Text>
|
||||
{statRows.map(([k, v]) => (
|
||||
<Group key={k} justify="space-between">
|
||||
<Text size="xs" c="dimmed">
|
||||
{k}
|
||||
</Text>
|
||||
<Text size="xs">{v}</Text>
|
||||
</Group>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Flex>
|
||||
)}
|
||||
{isSeriesGroup ? <Series /> : <Movie />}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue