Made compontent more generic and replaced link finder function

This commit is contained in:
Ayes 2022-10-10 17:28:13 +03:00
parent 522ca5beda
commit 7733baef00
2 changed files with 122 additions and 53 deletions

View file

@ -16,6 +16,7 @@ import PlaySVG from '../../../../public/res/ic/outlined/play.svg';
import { getBlobSafeMimeType } from '../../../util/mimetypes'; import { getBlobSafeMimeType } from '../../../util/mimetypes';
import initMatrix from '../../../client/initMatrix'; import initMatrix from '../../../client/initMatrix';
import settings from '../../../client/state/settings';
async function getDecryptedBlob(response, type, decryptData) { async function getDecryptedBlob(response, type, decryptData) {
const arrayBuffer = await response.arrayBuffer(); const arrayBuffer = await response.arrayBuffer();
@ -362,23 +363,106 @@ Video.propTypes = {
blurhash: PropTypes.string, blurhash: PropTypes.string,
}; };
function YoutubeEmbed({ link }) { function IframePlayer({
const url = new URL(link); children, link, sitename, title, thumbnail,
}) {
const [urlPreviewInfo, setUrlPreviewInfo] = useState(null);
const [videoStarted, setVideoStarted] = useState(false); const [videoStarted, setVideoStarted] = useState(false);
const mx = initMatrix.matrixClient;
const handlePlayVideo = () => { const handlePlayVideo = () => {
setVideoStarted(true); setVideoStarted(true);
}; };
return (
<div className="file-container">
<div className="file-header">
<Text className="file-name" variant="b3">{`${sitename} - ${title}`}</Text>
<IconButton
size="extra-small"
tooltip="Open in new tab"
src={ExternalSVG}
onClick={() => window.open(link)}
/>
</div>
<div
className="video-container"
>
{!videoStarted && <img src={thumbnail} alt={`${sitename} thumbnail`} />}
{!videoStarted && <IconButton onClick={handlePlayVideo} tooltip="Play video" src={PlaySVG} />}
{videoStarted && (
<div>
{children}
</div>
)}
</div>
</div>
);
}
IframePlayer.propTypes = {
children: PropTypes.node.isRequired,
link: PropTypes.string.isRequired,
sitename: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
thumbnail: PropTypes.string.isRequired,
};
function Embed({ link }) {
const url = new URL(link);
if (settings.showYoutubeEmbedPlayer && (((url.host === 'www.youtube.com' || url.host === 'youtube.com') && url.pathname === '/watch') || url.host === 'youtu.be' || url.host === 'www.youtu.be')) {
return <YoutubeEmbed link={link} />;
}
// TODO: url preview
// const [urlPreviewInfo, setUrlPreviewInfo] = useState(null);
// const mx = initMatrix.matrixClient;
// useEffect(() => {
// let unmounted = false;
// async function getThumbnail() {
// const info = await mx.getUrlPreview(link, 0);
// console.log('DEBUG', info);
// if (unmounted) return;
// setUrlPreviewInfo(info);
// }
// getThumbnail();
// return () => {
// unmounted = true;
// };
// });
// if (urlPreviewInfo !== null) {
// return <div>url preview here!/div>;
// }
return null;
}
Embed.propTypes = {
link: PropTypes.string.isRequired,
};
function YoutubeEmbed({ link }) {
const [urlPreviewInfo, setUrlPreviewInfo] = useState(null);
const mx = initMatrix.matrixClient;
const url = new URL(link);
// fix for no embed information on www.youtu.be
if (url.host === 'www.youtu.be') {
url.host = 'youtu.be';
}
useEffect(() => { useEffect(() => {
let unmounted = false; let unmounted = false;
async function getThumbnail() { async function getThumbnail() {
const info = await mx.getUrlPreview(link, 0); const info = await mx.getUrlPreview(url.toString(), 0);
if (unmounted) return; if (unmounted) return;
setUrlPreviewInfo(info); setUrlPreviewInfo(info);
@ -391,54 +475,38 @@ function YoutubeEmbed({ link }) {
}; };
}); });
let embedURL = `https://www.youtube-nocookie.com/embed/${url.searchParams.get('v')}?autoplay=1`; let videoID;
if (url.searchParams.has('t')) { if (url.host === 'youtu.be' || url.host === 'www.youtu.be') {
videoID = url.pathname.slice(1);
} else {
videoID = url.searchParams.get('v');
}
let embedURL = `https://www.youtube-nocookie.com/embed/${videoID}?autoplay=1`;
if (url.searchParams.has('t')) { // timestamp flag
embedURL += `&start=${url.searchParams.get('t')}`; embedURL += `&start=${url.searchParams.get('t')}`;
} }
return ( if (urlPreviewInfo !== null) {
<div className="file-container"> return (
{urlPreviewInfo !== null && ( <IframePlayer link={link} sitename="Youtube" title={urlPreviewInfo['og:title']} thumbnail={mx.mxcUrlToHttp(urlPreviewInfo['og:image'])}>
<div> <iframe
src={embedURL}
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</IframePlayer>
);
}
<div className="file-header"> return null;
<Text className="file-name" variant="b3">{`Youtube - ${urlPreviewInfo['og:title']}`}</Text>
<IconButton
size="extra-small"
tooltip="Open in new tab"
src={ExternalSVG}
onClick={() => window.open(link)}
/>
</div>
<div
className="video-container"
>
{!videoStarted && <img src={mx.mxcUrlToHttp(urlPreviewInfo['og:image'])} alt="Youtube thumbnail" />}
{!videoStarted && <IconButton onClick={handlePlayVideo} tooltip="Play video" src={PlaySVG} />}
{videoStarted && (
<iframe
src={embedURL}
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
)}
</div>
</div>
)}
</div>
);
} }
YoutubeEmbed.propTypes = { YoutubeEmbed.propTypes = {
link: PropTypes.string.isRequired, link: PropTypes.string.isRequired,
}; };
export { export {
File, Image, Sticker, Audio, Video, YoutubeEmbed, File, Image, Sticker, Audio, Video, YoutubeEmbed, Embed, IframePlayer,
}; };

View file

@ -5,6 +5,7 @@ import React, {
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './Message.scss'; import './Message.scss';
import { find } from 'linkifyjs';
import { twemojify } from '../../../util/twemojify'; import { twemojify } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix'; import initMatrix from '../../../client/initMatrix';
@ -29,7 +30,6 @@ import IconButton from '../../atoms/button/IconButton';
import Time from '../../atoms/time/Time'; import Time from '../../atoms/time/Time';
import ContextMenu, { MenuHeader, MenuItem, MenuBorder } from '../../atoms/context-menu/ContextMenu'; import ContextMenu, { MenuHeader, MenuItem, MenuBorder } from '../../atoms/context-menu/ContextMenu';
import * as Media from '../media/Media'; import * as Media from '../media/Media';
import settings from '../../../client/state/settings';
import ReplyArrowIC from '../../../../public/res/ic/outlined/reply-arrow.svg'; import ReplyArrowIC from '../../../../public/res/ic/outlined/reply-arrow.svg';
import EmojiAddIC from '../../../../public/res/ic/outlined/emoji-add.svg'; import EmojiAddIC from '../../../../public/res/ic/outlined/emoji-add.svg';
@ -42,7 +42,7 @@ import BinIC from '../../../../public/res/ic/outlined/bin.svg';
import { confirmDialog } from '../confirm-dialog/ConfirmDialog'; import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
import { getBlobSafeMimeType } from '../../../util/mimetypes'; import { getBlobSafeMimeType } from '../../../util/mimetypes';
import { html, plain } from '../../../util/markdown'; import { html, plain } from '../../../util/markdown';
import { YoutubeEmbed } from '../media/Media'; import { Embed } from '../media/Media';
function PlaceholderMessage() { function PlaceholderMessage() {
return ( return (
@ -718,8 +718,9 @@ function getEditedBody(editedMEvent) {
return [parsedContent.body, isCustomHTML, newContent.formatted_body ?? null]; return [parsedContent.body, isCustomHTML, newContent.formatted_body ?? null];
} }
function findYoutubeLinks(body) { function findLinks(body) {
return [...new Set(body.match(/https?:\/\/(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)[^ \n]+/g))] ?? []; return find(body, 'url')
.filter((v, i, a) => a.findIndex((v2) => (v2.href === v.href)) === i);
} }
function Message({ function Message({
@ -807,8 +808,8 @@ function Message({
isEdited={isEdited} isEdited={isEdited}
/> />
)} )}
{settings.showYoutubeEmbedPlayer && findYoutubeLinks(body).map((link) => ( {findLinks(body).map((link) => (
<YoutubeEmbed key={link} link={link} /> <Embed key={link.href} link={link.href} />
))} ))}
{isEdit && ( {isEdit && (
<MessageEdit <MessageEdit