Enhancement: Add copy link functionality to SeriesModal and VODModal, allowing users to easily copy episode and VOD links to clipboard with notifications for success or failure.

This commit is contained in:
SergeantPanda 2025-11-14 20:13:40 -06:00
parent 2514528337
commit 0700cf29ea
2 changed files with 99 additions and 18 deletions

View file

@ -17,7 +17,9 @@ import {
Table,
Divider,
} from '@mantine/core';
import { Play } from 'lucide-react';
import { Play, Copy } from 'lucide-react';
import { notifications } from '@mantine/notifications';
import { copyToClipboard } from '../utils';
import useVODStore from '../store/useVODStore';
import useVideoStore from '../store/useVideoStore';
import useSettingsStore from '../store/settings';
@ -262,6 +264,39 @@ const SeriesModal = ({ series, opened, onClose }) => {
showVideo(streamUrl, 'vod', episode);
};
const getEpisodeStreamUrl = (episode) => {
let streamUrl = `/proxy/vod/episode/${episode.uuid}`;
// Add selected provider as query parameter if available
if (selectedProvider) {
// Use stream_id for most specific selection, fallback to account_id
if (selectedProvider.stream_id) {
streamUrl += `?stream_id=${encodeURIComponent(selectedProvider.stream_id)}`;
} else {
streamUrl += `?m3u_account_id=${selectedProvider.m3u_account.id}`;
}
}
if (env_mode === 'dev') {
streamUrl = `${window.location.protocol}//${window.location.hostname}:5656${streamUrl}`;
} else {
streamUrl = `${window.location.origin}${streamUrl}`;
}
return streamUrl;
};
const handleCopyEpisodeLink = async (episode) => {
const streamUrl = getEpisodeStreamUrl(episode);
const success = await copyToClipboard(streamUrl);
notifications.show({
title: success ? 'Link Copied!' : 'Copy Failed',
message: success
? 'Episode link copied to clipboard'
: 'Failed to copy link to clipboard',
color: success ? 'green' : 'red',
});
};
const handleEpisodeRowClick = (episode) => {
setExpandedEpisode(expandedEpisode === episode.id ? null : episode.id);
};
@ -611,20 +646,34 @@ const SeriesModal = ({ series, opened, onClose }) => {
</Text>
</Table.Td>
<Table.Td>
<ActionIcon
variant="filled"
color="blue"
size="sm"
disabled={
providers.length > 0 && !selectedProvider
}
onClick={(e) => {
e.stopPropagation();
handlePlayEpisode(episode);
}}
>
<Play size={12} />
</ActionIcon>
<Group spacing="xs">
<ActionIcon
variant="filled"
color="blue"
size="sm"
disabled={
providers.length > 0 &&
!selectedProvider
}
onClick={(e) => {
e.stopPropagation();
handlePlayEpisode(episode);
}}
>
<Play size={12} />
</ActionIcon>
<ActionIcon
variant="outline"
color="gray"
size="sm"
onClick={(e) => {
e.stopPropagation();
handleCopyEpisodeLink(episode);
}}
>
<Copy size={12} />
</ActionIcon>
</Group>
</Table.Td>
</Table.Tr>
{expandedEpisode === episode.id && (

View file

@ -13,7 +13,9 @@ import {
Stack,
Modal,
} from '@mantine/core';
import { Play } from 'lucide-react';
import { Play, Copy } from 'lucide-react';
import { notifications } from '@mantine/notifications';
import { copyToClipboard } from '../utils';
import useVODStore from '../store/useVODStore';
import useVideoStore from '../store/useVideoStore';
import useSettingsStore from '../store/settings';
@ -232,9 +234,9 @@ const VODModal = ({ vod, opened, onClose }) => {
}
}, [opened]);
const handlePlayVOD = () => {
const getStreamUrl = () => {
const vodToPlay = detailedVOD || vod;
if (!vodToPlay) return;
if (!vodToPlay) return null;
let streamUrl = `/proxy/vod/movie/${vod.uuid}`;
@ -253,9 +255,29 @@ const VODModal = ({ vod, opened, onClose }) => {
} else {
streamUrl = `${window.location.origin}${streamUrl}`;
}
return streamUrl;
};
const handlePlayVOD = () => {
const streamUrl = getStreamUrl();
if (!streamUrl) return;
const vodToPlay = detailedVOD || vod;
showVideo(streamUrl, 'vod', vodToPlay);
};
const handleCopyLink = async () => {
const streamUrl = getStreamUrl();
if (!streamUrl) return;
const success = await copyToClipboard(streamUrl);
notifications.show({
title: success ? 'Link Copied!' : 'Copy Failed',
message: success
? 'Stream link copied to clipboard'
: 'Failed to copy link to clipboard',
color: success ? 'green' : 'red',
});
};
// Helper to get embeddable YouTube URL
const getEmbedUrl = (url) => {
if (!url) return '';
@ -486,6 +508,16 @@ const VODModal = ({ vod, opened, onClose }) => {
Watch Trailer
</Button>
)}
<Button
leftSection={<Copy size={16} />}
variant="outline"
color="gray"
size="sm"
onClick={handleCopyLink}
style={{ alignSelf: 'flex-start' }}
>
Copy Link
</Button>
</Group>
</Stack>
</Flex>