2023-11-06 23:02:12 +08:00
|
|
|
import React from 'react';
|
|
|
|
import { defineMessages, useIntl } from 'react-intl';
|
2024-01-19 21:44:27 +08:00
|
|
|
import { useMutation } from '@apollo/client';
|
2023-11-06 23:02:12 +08:00
|
|
|
import Styled from './styles';
|
2024-05-29 21:26:11 +08:00
|
|
|
import { getSettingsSingletonInstance } from '/imports/ui/services/settings';
|
2024-01-19 21:44:27 +08:00
|
|
|
import { isUrlValid } from './service';
|
|
|
|
import { EXTERNAL_VIDEO_START } from '../../mutations';
|
2023-11-06 23:02:12 +08:00
|
|
|
|
|
|
|
const intlMessages = defineMessages({
|
|
|
|
start: {
|
|
|
|
id: 'app.externalVideo.start',
|
|
|
|
description: 'Share external video',
|
|
|
|
},
|
|
|
|
urlError: {
|
|
|
|
id: 'app.externalVideo.urlError',
|
|
|
|
description: 'Not a video URL error',
|
|
|
|
},
|
|
|
|
input: {
|
|
|
|
id: 'app.externalVideo.input',
|
|
|
|
description: 'Video URL',
|
|
|
|
},
|
|
|
|
urlInput: {
|
|
|
|
id: 'app.externalVideo.urlInput',
|
|
|
|
description: 'URL input field placeholder',
|
|
|
|
},
|
|
|
|
title: {
|
|
|
|
id: 'app.externalVideo.title',
|
|
|
|
description: 'Modal title',
|
|
|
|
},
|
|
|
|
close: {
|
|
|
|
id: 'app.externalVideo.close',
|
|
|
|
description: 'Close',
|
|
|
|
},
|
|
|
|
note: {
|
|
|
|
id: 'app.externalVideo.noteLabel',
|
|
|
|
description: 'provides hint about Shared External videos',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2024-01-19 21:44:27 +08:00
|
|
|
const YOUTUBE_SHORTS_REGEX = new RegExp(/^(?:https?:\/\/)?(?:www\.)?(youtube\.com\/shorts)\/.+$/);
|
|
|
|
const PANOPTO_MATCH_URL = /https?:\/\/([^/]+\/Panopto)(\/Pages\/Viewer\.aspx\?id=)([-a-zA-Z0-9]+)/;
|
|
|
|
|
2023-11-06 23:02:12 +08:00
|
|
|
interface ExternalVideoPlayerModalProps {
|
|
|
|
onRequestClose: () => void,
|
|
|
|
priority: string,
|
|
|
|
setIsOpen: (isOpen: boolean) => void,
|
|
|
|
isOpen: boolean,
|
|
|
|
}
|
|
|
|
|
|
|
|
const ExternalVideoPlayerModal: React.FC<ExternalVideoPlayerModalProps> = ({
|
|
|
|
isOpen,
|
|
|
|
setIsOpen,
|
|
|
|
onRequestClose,
|
|
|
|
priority,
|
|
|
|
}) => {
|
|
|
|
const intl = useIntl();
|
2024-05-29 21:26:11 +08:00
|
|
|
const Settings = getSettingsSingletonInstance();
|
2023-11-06 23:02:12 +08:00
|
|
|
// @ts-ignore - settings is a js singleton
|
2024-05-29 21:26:11 +08:00
|
|
|
const { animations } = Settings.application;
|
2023-11-06 23:02:12 +08:00
|
|
|
const [videoUrl, setVideoUrl] = React.useState('');
|
2024-01-19 21:44:27 +08:00
|
|
|
const [startExternalVideo] = useMutation(EXTERNAL_VIDEO_START);
|
|
|
|
|
|
|
|
const startWatching = (url: string) => {
|
|
|
|
let externalVideoUrl = url;
|
|
|
|
|
|
|
|
if (YOUTUBE_SHORTS_REGEX.test(url)) {
|
|
|
|
const shortsUrl = url.replace('shorts/', 'watch?v=');
|
|
|
|
externalVideoUrl = shortsUrl;
|
|
|
|
} else if (PANOPTO_MATCH_URL.test(url)) {
|
|
|
|
const m = url.match(PANOPTO_MATCH_URL);
|
|
|
|
if (m && m.length >= 4) {
|
|
|
|
externalVideoUrl = `https://${m[1]}/Podcast/Social/${m[3]}.mp4`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
startExternalVideo({ variables: { externalVideoUrl } });
|
|
|
|
};
|
2023-11-06 23:02:12 +08:00
|
|
|
|
2023-11-08 04:55:17 +08:00
|
|
|
const valid = isUrlValid(videoUrl);
|
2023-11-06 23:02:12 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<Styled.ExternalVideoModal
|
|
|
|
onRequestClose={onRequestClose}
|
|
|
|
contentLabel={intl.formatMessage(intlMessages.title)}
|
|
|
|
title={intl.formatMessage(intlMessages.title)}
|
|
|
|
isOpen={isOpen}
|
|
|
|
setIsOpen={setIsOpen}
|
|
|
|
priority={priority}
|
|
|
|
>
|
|
|
|
<Styled.Content>
|
|
|
|
<Styled.VideoUrl animations={animations}>
|
|
|
|
<label htmlFor="video-modal-input">
|
|
|
|
{intl.formatMessage(intlMessages.input)}
|
|
|
|
<input
|
|
|
|
id="video-modal-input"
|
|
|
|
onChange={(e) => setVideoUrl(e.target.value)}
|
|
|
|
name="video-modal-input"
|
|
|
|
placeholder={intl.formatMessage(intlMessages.urlInput)}
|
|
|
|
aria-describedby="exernal-video-note"
|
|
|
|
onPaste={(e) => { e.stopPropagation(); }}
|
|
|
|
onCut={(e) => { e.stopPropagation(); }}
|
|
|
|
onCopy={(e) => { e.stopPropagation(); }}
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
<Styled.ExternalVideoNote id="external-video-note">
|
|
|
|
{intl.formatMessage(intlMessages.note)}
|
|
|
|
</Styled.ExternalVideoNote>
|
|
|
|
</Styled.VideoUrl>
|
|
|
|
<div>
|
|
|
|
{
|
2023-11-08 04:55:17 +08:00
|
|
|
!valid && videoUrl
|
2023-11-06 23:02:12 +08:00
|
|
|
? (
|
|
|
|
<Styled.UrlError animations={animations}>
|
|
|
|
{intl.formatMessage(intlMessages.urlError)}
|
|
|
|
</Styled.UrlError>
|
|
|
|
)
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<Styled.StartButton
|
|
|
|
label={intl.formatMessage(intlMessages.start)}
|
2023-11-08 04:55:17 +08:00
|
|
|
disabled={!valid || !videoUrl}
|
2023-11-06 23:02:12 +08:00
|
|
|
onClick={() => {
|
|
|
|
startWatching(videoUrl);
|
|
|
|
onRequestClose();
|
|
|
|
}}
|
|
|
|
data-test="startNewVideo"
|
|
|
|
color="primary"
|
|
|
|
/>
|
|
|
|
</Styled.Content>
|
|
|
|
</Styled.ExternalVideoModal>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ExternalVideoPlayerModal;
|