1
Fork 0
mirror of https://github.com/diced/zipline.git synced 2025-04-11 23:31:17 -05:00

fix: my own mistake of breaking embeds with sites. Images should have their links hidden with discord. Videos can embed and play. Others? Good luck

This commit is contained in:
Jay 2025-02-11 18:39:04 -08:00
parent 233324b6c5
commit c8b340cedf
No known key found for this signature in database
GPG key ID: 97C2E533F17AF0EB

View file

@ -17,43 +17,52 @@ export default function EmbeddedFile({
user,
prismRender,
host,
compress,
mediaType,
}: {
file: Omit<Partial<File>, 'password'> & {
file: Omit<File, 'password'> & {
password: boolean;
imageProps?: HTMLImageElement;
thumbnail: Thumbnail;
mediaProps?: {
width: number;
height: number;
};
thumbnail?: Pick<Thumbnail, 'name'>;
};
user: UserExtended;
prismRender: boolean;
host: string;
compress?: boolean;
mediaType: 'image' | 'video' | 'audio' | 'other';
}) {
const dataURL = (route: string, pass?: string) =>
`${route}/${encodeURIComponent(file.name)}?compress=${compress ?? false}${
pass ? `&password=${encodeURIComponent(pass)}` : ''
}`;
const router = useRouter();
const {
password: provPassword,
compress,
embed,
} = router.query as {
password?: string;
compress?: string;
embed?: string;
};
const dataURL = (route: string, opts?: { withHost?: boolean; useThumb?: boolean; pass?: string }) =>
`${opts?.withHost ? host : ''}${route}/${encodeURIComponent(
(opts?.useThumb && !!file.thumbnail && file.thumbnail.name) || file.name,
)}?compress=${compress ?? false}${opts?.pass ? `&password=${encodeURIComponent(opts?.pass)}` : ''}`;
const [opened, setOpened] = useState(file.password);
const [password, setPassword] = useState('');
const [password, setPassword] = useState(provPassword || '');
const [error, setError] = useState('');
const [scale, setScale] = useState(2);
const [downloadWPass, setDownloadWPass] = useState(false);
const mimeMatch = new RegExp(/^((?<img>image)|(?<vid>video)|(?<aud>audio))/).exec(file.mimetype);
// reapply date from workaround
file.createdAt = new Date(file ? file.createdAt : 0);
const check = async () => {
const res = await fetch(dataURL('/r', password));
const res = await fetch(dataURL('/r', { pass: password }));
if (res.ok) {
setError('');
if (prismRender) return router.push(`/code/${file.name}?password=${password}`);
updateFile(dataURL('/r', password));
if (prismRender) return router.push(`/code/${file.name}?password=${encodeURIComponent(password)}`);
updateMedia(dataURL('/r', { pass: password }));
setOpened(false);
setDownloadWPass(true);
} else {
@ -61,107 +70,219 @@ export default function EmbeddedFile({
}
};
const updateFile = async (url?: string) => {
if (!mimeMatch) return;
const updateMedia: (url?: string) => void = function (url?: string) {
if (mediaType === 'other') return;
const imageEl = document.getElementById('image_content') as HTMLImageElement,
videoEl = document.getElementById('video_content') as HTMLVideoElement,
audioEl = document.getElementById('audio_content') as HTMLAudioElement;
const mediaContent = document.getElementById(`${mediaType}_content`) as
| HTMLImageElement
| HTMLVideoElement
| HTMLAudioElement;
if (url) {
if (mimeMatch?.groups?.img) imageEl.src = url;
if (mimeMatch?.groups?.vid) videoEl.src = url;
if (mimeMatch?.groups?.aud) audioEl.src = url;
if (mediaType === 'image') {
if (document.getElementsByClassName('dynamic').length !== 0) return;
const img = new Image();
img.onload = function () {
if (document.getElementsByClassName('dynamic').length !== 0) return;
file.mediaProps = {
width: img.naturalWidth,
height: img.naturalHeight,
};
const metas: HTMLMetaElement[] = [];
for (let i = 0; i !== 2; i++) {
const metaW = document.createElement('meta');
const metaH = document.createElement('meta');
metaW.setAttribute('name', i % 2 ? 'twitter:image:width' : 'og:image:width');
metaH.setAttribute('name', i % 2 ? 'twitter:image:height' : 'og:image:height');
metaW.setAttribute('content', file.mediaProps.width.toString());
metaH.setAttribute('content', file.mediaProps.width.toString());
metaW.className = 'dynamic';
metaH.className = 'dynamic';
metas.push(...[metaW, metaH]);
}
for (const meta of metas) document.head.appendChild(meta);
img.remove();
};
img.src = dataURL('/r', { pass: password.length !== 0 ? password : undefined });
}
if (mediaType === 'video') {
if (document.getElementsByClassName('dynamic').length !== 0) return;
const vid = document.createElement('video');
vid.onloadedmetadata = function () {
if (document.getElementsByClassName('dynamic').length !== 0) return;
file.mediaProps = {
width: vid.videoWidth,
height: vid.videoHeight,
};
const metas: HTMLMetaElement[] = [];
for (let i = 0; i !== 2; i++) {
const metaW = document.createElement('meta');
const metaH = document.createElement('meta');
metaW.setAttribute('name', i % 2 ? 'twitter:player:width' : 'og:video:width');
metaH.setAttribute('name', i % 2 ? 'twitter:player:height' : 'og:video:height');
metaW.setAttribute('content', file.mediaProps.width.toString());
metaH.setAttribute('content', file.mediaProps.width.toString());
metaW.className = 'dynamic';
metaH.className = 'dynamic';
metas.push(...[metaW, metaH]);
}
for (const meta of metas) document.head.appendChild(meta);
vid.remove();
};
vid.src = dataURL('/r', { pass: password.length !== 0 ? password : undefined });
vid.load();
}
if (url) mediaContent.src = url;
};
useEffect(() => {
if (file.password) {
setOpened(true);
if (password) check();
else setOpened(true);
}
}, []);
useEffect(() => {
if (!mimeMatch) return;
updateFile();
if (mediaType === 'other') return;
updateMedia();
return () => {
const metas = document.head.getElementsByClassName('dynamic');
for (const meta of metas) meta.remove();
};
}, []);
return (
<>
<Head>
<meta
property='og:url'
content={dataURL(router.asPath.replace(('/' + router.query['id']) as string, ''), {
withHost: true,
})}
/>
{!embed && !file.embed && mediaType === 'image' && (
<link rel='alternate' type='application/json+oembed' href={`${host}/api/oembed/${file.id}`} />
)}
{user.embed.title && file.embed && (
<meta property='og:title' content={parseString(user.embed.title, { file: file, user })} />
)}
{user.embed.description && file.embed && (
<meta
property='og:description'
content={parseString(user.embed.description, { file: file, user })}
/>
)}
{user.embed.siteName && file.embed && (
<meta property='og:site_name' content={parseString(user.embed.siteName, { file: file, user })} />
)}
{user.embed.color && file.embed && (
<meta property='theme-color' content={parseString(user.embed.color, { file: file, user })} />
)}
{mimeMatch?.groups?.img && (
{embed?.toLowerCase() === 'true' && !file.embed && (
<>
<meta property='og:type' content='image' />
<meta property='og:image' itemProp='image' content={`${host}/r/${file.name}`} />
<meta property='og:url' content={`${host}/r/${file.name}`} />
<meta property='og:image:width' content={file.imageProps?.naturalWidth.toString()} />
<meta property='og:image:height' content={file.imageProps?.naturalHeight.toString()} />
<meta property='twitter:card' content='summary_large_image' />
<meta property='twitter:image' content={`${host}/r/${file.name}`} />
<meta name='og:title' content={file.name} />
<meta property='twitter:title' content={file.name} />
</>
)}
{mimeMatch?.groups?.vid && (
<>
<meta name='twitter:card' content='player' />
<meta name='twitter:player' content={`${host}/r/${file.name}`} />
<meta name='twitter:player:stream' content={`${host}/r/${file.name}`} />
<meta name='twitter:player:stream:content_type' content={file.mimetype} />
<meta name='twitter:title' content={file.name} />
{file.thumbnail && (
<>
<meta name='twitter:image' content={`${host}/r/${file.thumbnail.name}`} />
<meta property='og:image' content={`${host}/r/${file.thumbnail.name}`} />
</>
{mediaType === 'image' && (
<meta
name='twitter:image'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>
)}
<meta property='og:type' content={'video.other'} />
<meta property='og:url' content={`${host}/r/${file.name}`} />
<meta property='og:video' content={`${host}/r/${file.name}`} />
<meta property='og:video:url' content={`${host}/r/${file.name}`} />
<meta property='og:video:secure_url' content={`${host}/r/${file.name}`} />
<meta property='og:video:type' content={file.mimetype} />
{mediaType === 'image' && <meta property='twitter:card' content='summary_large_image' />}
</>
)}
{mimeMatch?.groups?.aud && (
{mediaType === 'image' && (
<>
<meta
property='og:image'
itemProp='image'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>
<meta
property='og:image:secure_url'
content={dataURL('/r', {
withHost: true,
useThumb: true,
pass: password.length == 0 ? undefined : password,
})}
/>
<meta property='og:image:alt' content={file.name} />
<meta property='og:image:type' content={file.mimetype} />
</>
)}
{mediaType === 'video' && [
...(!!file.thumbnail
? [
<meta
property='og:image:url'
key='og:image:url'
content={dataURL('/r', {
withHost: true,
useThumb: true,
pass: password.length == 0 ? undefined : password,
})}
/>,
<meta
property='og:image:secure_url'
key='og:image:secure_url'
content={dataURL('/r', {
withHost: true,
useThumb: true,
pass: password.length == 0 ? undefined : password,
})}
/>,
<meta property='og:image:type' key='og:image:type' content='image/jpeg' />,
<meta
name='twitter:image'
key='twitter:image'
content={dataURL('/r', {
withHost: true,
useThumb: true,
pass: password.length == 0 ? undefined : password,
})}
/>,
]
: []),
<meta name='twitter:card' key='twitter:card' content='player' />,
<meta
name='twitter:player'
key='twitter:player'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>,
<meta
name='twitter:player:stream'
key='twitter:player:stream'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>,
<meta
name='twitter:player:stream:content_type'
key='twitter:player:stream:content_type'
content={file.mimetype}
/>,
<meta property='og:type' key='og:type' content='video.movie' />,
<meta
property='og:video'
key='og:video'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>,
<meta
property='og:video:secure_url'
key='og:video:secure_url'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>,
<meta property='og:video:type' key='og:video:type' content={file.mimetype} />,
]}
{mediaType === 'audio' && (
<>
<meta name='twitter:card' content='player' />
<meta name='twitter:player' content={`${host}/r/${file.name}`} />
<meta name='twitter:player:stream' content={`${host}/r/${file.name}`} />
<meta name='twitter:player:stream:content_type' content={file.mimetype} />
<meta name='twitter:title' content={file.name} />
<meta name='twitter:player:width' content='720' />
<meta name='twitter:player:height' content='480' />
<meta property='og:type' content='music.song' />
<meta property='og:url' content={`${host}/r/${file.name}`} />
<meta property='og:audio' content={`${host}/r/${file.name}`} />
<meta property='og:audio:secure_url' content={`${host}/r/${file.name}`} />
<meta
property='og:audio'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>
<meta
property='og:audio:secure_url'
content={dataURL('/r', { withHost: true, pass: password.length == 0 ? undefined : password })}
/>
<meta property='og:audio:type' content={file.mimetype} />
</>
)}
{!mimeMatch && <meta property='og:url' content={`${host}/r/${file.name}`} />}
<title>{file.name}</title>
</Head>
<Modal
@ -192,7 +313,7 @@ export default function EmbeddedFile({
overflow: 'hidden',
}}
onMouseDown={(e) => {
if (!mimeMatch?.groups?.img || e.button !== 0) return;
if (mediaType !== 'image' || e.button !== 0) return;
if (e.button !== 0) return;
e.preventDefault();
@ -206,7 +327,7 @@ export default function EmbeddedFile({
return true;
}}
onMouseUp={(e) => {
if (!mimeMatch?.groups?.img || e.button !== 0) return;
if (mediaType !== 'image' || e.button !== 0) return;
const imageEl = document.getElementById('image_content') as HTMLImageElement;
if (!imageEl.style.transform.startsWith('translate')) return;
@ -215,7 +336,7 @@ export default function EmbeddedFile({
return true;
}}
onMouseMove={(e) => {
if (!mimeMatch?.groups?.img || e.button !== 0) return;
if (mediaType !== 'image' || e.button !== 0) return;
if (e.button !== 0) return;
const imageEl = document.getElementById('image_content') as HTMLImageElement,
@ -227,7 +348,7 @@ export default function EmbeddedFile({
return true;
}}
onWheel={(e) => {
if (!mimeMatch?.groups?.img || e.button !== 0) return;
if (mediaType !== 'image' || e.button !== 0) return;
const imageEl = document.getElementById('image_content') as HTMLImageElement,
posX = e.pageX - (imageEl.x + imageEl.width / 2),
@ -242,7 +363,7 @@ export default function EmbeddedFile({
}px) scale(${newScale})`;
}}
>
{mimeMatch?.groups?.img && (
{mediaType === 'image' && (
<img
src={dataURL('/r')}
alt={dataURL('/r')}
@ -251,11 +372,12 @@ export default function EmbeddedFile({
transition: 'transform 0.25s ease',
maxHeight: '100vh',
maxWidth: '100vw',
objectFit: 'contain',
}}
/>
)}
{mimeMatch?.groups?.vid && (
{mediaType === 'video' && (
<video
style={{
maxHeight: '100vh',
@ -269,10 +391,10 @@ export default function EmbeddedFile({
/>
)}
{mimeMatch?.groups?.aud && <audio src={dataURL('/r')} controls autoPlay muted id='audio_content' />}
{mediaType === 'audio' && <audio src={dataURL('/r')} controls autoPlay muted id='audio_content' />}
{!mimeMatch && (
<AnchorNext component={Link} href={dataURL('/r', downloadWPass ? password : undefined)}>
{mediaType === 'other' && (
<AnchorNext component={Link} href={dataURL('/r', { pass: downloadWPass ? password : undefined })}>
Can&#39;t preview this file. Click here to download it.
</AnchorNext>
)}
@ -283,22 +405,23 @@ export default function EmbeddedFile({
export const getServerSideProps: GetServerSideProps = async (context) => {
const { id } = context.params as { id: string };
const { compress = null } = context.query as {
compress?: string;
};
const file = await prisma.file.findFirst({
where: {
OR: [{ name: id }, { invisible: { invis: decodeURI(encodeURI(id)) } }],
},
include: {
thumbnail: true,
thumbnail: {
select: {
name: true,
},
},
},
});
let host = context.req.headers.host;
if (!file) return { notFound: true };
// @ts-ignore
file.size = Number(file.size);
file.size = parseInt(file.size);
const proto = context.req.headers['x-forwarded-proto'];
try {
@ -314,6 +437,12 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
else host = `http://${host}`;
}
const mediaType: 'image' | 'video' | 'audio' | 'other' =
(new RegExp(/^(?<type>image|video|audio)/).exec(file.mimetype)?.groups?.type as
| 'image'
| 'video'
| 'audio') || 'other';
const user = await prisma.user.findFirst({
where: {
id: file.userId,
@ -354,7 +483,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
file,
user,
host,
compress,
mediaType,
},
};
};