mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
Merge branch 'development' into master
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
const Embed = ({url}) => {
|
||||
const parsedUrl = new URL(url);
|
||||
|
||||
if (youtubeHosts.has(parsedUrl.host)) {
|
||||
return <YoutubeEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (twitterHosts.has(parsedUrl.host)) {
|
||||
return <TwitterEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (redditHosts.has(parsedUrl.host)) {
|
||||
return <RedditEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (twitchHosts.has(parsedUrl.host)) {
|
||||
return <TwitchEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (tiktokHosts.has(parsedUrl.host)) {
|
||||
return <TiktokEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (instagramHosts.has(parsedUrl.host)) {
|
||||
return <InstagramEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (odyseeHosts.has(parsedUrl.host)) {
|
||||
return <OdyseeEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (bitchuteHosts.has(parsedUrl.host)) {
|
||||
return <BitchuteEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (streamableHosts.has(parsedUrl.host)) {
|
||||
return <StreamableEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
if (spotifyHosts.has(parsedUrl.host)) {
|
||||
return <SpotifyEmbed parsedUrl={parsedUrl} />;
|
||||
}
|
||||
};
|
||||
|
||||
const youtubeHosts = new Set(['youtube.com', 'www.youtube.com', 'youtu.be', 'www.youtu.be']);
|
||||
|
||||
const YoutubeEmbed = ({parsedUrl}) => {
|
||||
let youtubeId;
|
||||
if (parsedUrl.host.endsWith('youtu.be')) {
|
||||
youtubeId = parsedUrl.pathname.replaceAll('/', '');
|
||||
}
|
||||
else {
|
||||
youtubeId = parsedUrl.searchParams.get('v');
|
||||
}
|
||||
return <iframe
|
||||
className='enlarged youtube-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
title={parsedUrl.href}
|
||||
src={`https://www.youtube.com/embed/${youtubeId}`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const twitterHosts = new Set(['twitter.com', 'www.twitter.com', 'x.com', 'www.x.com']);
|
||||
|
||||
const TwitterEmbed = ({parsedUrl}) => {
|
||||
return <iframe
|
||||
className='enlarged twitter-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
title={parsedUrl.href}
|
||||
srcdoc={`
|
||||
<blockquote class="twitter-tweet" data-theme="dark">
|
||||
<a href="${parsedUrl.href}"></a>
|
||||
</blockquote>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const redditHosts = new Set(['reddit.com', 'www.reddit.com', 'old.reddit.com']);
|
||||
|
||||
const RedditEmbed = ({parsedUrl}) => {
|
||||
return <iframe
|
||||
className='enlarged reddit-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
title={parsedUrl.href}
|
||||
srcdoc={`
|
||||
<style>
|
||||
/* fix reddit iframe being centered */
|
||||
iframe {
|
||||
margin: 0!important;
|
||||
}
|
||||
</style>
|
||||
<blockquote class="reddit-embed-bq" style="height:240px" data-embed-theme="dark">
|
||||
<a href="${parsedUrl.href}"></a>
|
||||
</blockquote>
|
||||
<script async src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>
|
||||
`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const twitchHosts = new Set(['twitch.tv', 'www.twitch.tv']);
|
||||
|
||||
const TwitchEmbed = ({parsedUrl}) => {
|
||||
let iframeUrl;
|
||||
if (parsedUrl.pathname.startsWith('/videos/')) {
|
||||
const videoId = parsedUrl.pathname.replace('/videos/', '');
|
||||
iframeUrl = `https://player.twitch.tv/?video=${videoId}&parent=${window.location.hostname}`;
|
||||
}
|
||||
else {
|
||||
const channel = parsedUrl.pathname.replaceAll('/', '');
|
||||
iframeUrl = `https://player.twitch.tv/?channel=${channel}&parent=${window.location.hostname}`;
|
||||
}
|
||||
return <iframe
|
||||
className='enlarged twitch-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
title={parsedUrl.href}
|
||||
src={iframeUrl}
|
||||
/>;
|
||||
};
|
||||
|
||||
const tiktokHosts = new Set(['tiktok.com', 'www.tiktok.com']);
|
||||
|
||||
const TiktokEmbed = ({parsedUrl}) => {
|
||||
const videoId = parsedUrl.pathname.replace(/.+\/video\//, '').replaceAll('/', '');
|
||||
return <iframe
|
||||
className='enlarged tiktok-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
title={parsedUrl.href}
|
||||
srcdoc={`
|
||||
<blockquote class="tiktok-embed" data-video-id="${videoId}">
|
||||
<a></a>
|
||||
</blockquote>
|
||||
<script async src="https://www.tiktok.com/embed.js"></script>
|
||||
`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const instagramHosts = new Set(['instagram.com', 'www.instagram.com']);
|
||||
|
||||
const InstagramEmbed = ({parsedUrl}) => {
|
||||
const pathNames = parsedUrl.pathname.replace(/\/+$/, '').split('/');
|
||||
const id = pathNames[pathNames.length - 1];
|
||||
return <iframe
|
||||
className='enlarged instagram-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
title={parsedUrl.href}
|
||||
srcdoc={`
|
||||
<blockquote class="instagram-media">
|
||||
<a href="https://www.instagram.com/p/${id}/"></a>
|
||||
</blockquote>
|
||||
<script async src="//www.instagram.com/embed.js"></script>
|
||||
`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const odyseeHosts = new Set(['odysee.com', 'www.odysee.com']);
|
||||
|
||||
const OdyseeEmbed = ({parsedUrl}) => {
|
||||
const iframeUrl = `https://odysee.com/$/embed${parsedUrl.pathname}`;
|
||||
return <iframe
|
||||
className='enlarged odysee-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
title={parsedUrl.href}
|
||||
src={iframeUrl}
|
||||
/>;
|
||||
};
|
||||
|
||||
const bitchuteHosts = new Set(['bitchute.com', 'www.bitchute.com']);
|
||||
|
||||
const BitchuteEmbed = ({parsedUrl}) => {
|
||||
const videoId = parsedUrl.pathname.replace(/\/video\//, '').replaceAll('/', '');
|
||||
return <iframe
|
||||
className='enlarged bitchute-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
title={parsedUrl.href}
|
||||
src={`https://www.bitchute.com/embed/${videoId}/`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const streamableHosts = new Set(['streamable.com', 'www.streamable.com']);
|
||||
|
||||
const StreamableEmbed = ({parsedUrl}) => {
|
||||
const videoId = parsedUrl.pathname.replaceAll('/', '');
|
||||
return <iframe
|
||||
className='enlarged streamable-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
title={parsedUrl.href}
|
||||
src={`https://streamable.com/e/${videoId}`}
|
||||
/>;
|
||||
};
|
||||
|
||||
const spotifyHosts = new Set(['spotify.com', 'www.spotify.com', 'open.spotify.com']);
|
||||
|
||||
const SpotifyEmbed = ({parsedUrl}) => {
|
||||
const iframeUrl = `https://open.spotify.com/embed${parsedUrl.pathname}?theme=0`
|
||||
return <iframe
|
||||
className='enlarged spotify-embed'
|
||||
height="100%"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
credentialless
|
||||
referrerpolicy='no-referrer'
|
||||
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
title={parsedUrl.href}
|
||||
src={iframeUrl}
|
||||
/>;
|
||||
};
|
||||
|
||||
const canEmbedHosts = new Set([
|
||||
...youtubeHosts, ...twitterHosts, ...redditHosts, ...twitchHosts,
|
||||
...tiktokHosts, ...instagramHosts, ...odyseeHosts, ...bitchuteHosts,
|
||||
...streamableHosts, ...spotifyHosts
|
||||
]);
|
||||
|
||||
export const canEmbed = (parsedUrl) => canEmbedHosts.has(parsedUrl.host);
|
||||
|
||||
export default Embed;
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from 'react';
|
||||
import {useComment, useAuthorAddress} from '@plebbit/plebbit-react-hooks';
|
||||
|
||||
function VerifiedAuthor({ commentCid, children }) {
|
||||
@@ -7,4 +8,4 @@ function VerifiedAuthor({ commentCid, children }) {
|
||||
return children({ authorAddress, shortAuthorAddress });
|
||||
}
|
||||
|
||||
export default VerifiedAuthor;
|
||||
export default React.memo(VerifiedAuthor);
|
||||
@@ -42,10 +42,47 @@ export const GlobalStyle = createGlobalStyle`
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.enlarged {
|
||||
display: block;
|
||||
max-width: 100% !important;
|
||||
max-height: 100% !important;
|
||||
@media (min-width: 480px) {
|
||||
.enlarged {
|
||||
display: block;
|
||||
max-width: 100% !important;
|
||||
max-height: 100% !important;
|
||||
}
|
||||
|
||||
.instagram-embed {
|
||||
height: 420px;
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
.streamable-embed,
|
||||
.bitchute-embed,
|
||||
.odysee-embed,
|
||||
.youtube-embed,
|
||||
.rumble-embed,
|
||||
.twitch-embed {
|
||||
height: 450px;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
.spotify-embed {
|
||||
height: 240px;
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
.tiktok-embed {
|
||||
width: 400px;
|
||||
height: 780px;
|
||||
}
|
||||
|
||||
.twitter-embed {
|
||||
width: 400px;
|
||||
height: 580px;
|
||||
}
|
||||
|
||||
.reddit-embed {
|
||||
width: 500px;
|
||||
height: 260px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
|
||||
+126
-88
@@ -18,6 +18,7 @@ import ModerationModal from '../modals/ModerationModal';
|
||||
import BoardSettings from '../BoardSettings';
|
||||
import BoardStats from '../BoardStats';
|
||||
import EditLabel from '../EditLabel';
|
||||
import Embed from '../Embed';
|
||||
import ImageBanner from '../ImageBanner';
|
||||
import OfflineIndicator from '../OfflineIndicator';
|
||||
import PendingLabel from '../PendingLabel';
|
||||
@@ -1413,33 +1414,29 @@ const Board = () => {
|
||||
commentMediaInfo?.url.length > 30 ?
|
||||
commentMediaInfo?.url.slice(0, 30) + "(...)" :
|
||||
commentMediaInfo?.url
|
||||
}</a> ({commentMediaInfo?.type === "iframe" ? "video" : commentMediaInfo?.type})
|
||||
{isThreadThumbnailClicked[index] && commentMediaInfo.type !== "image" ? (
|
||||
}</a> {commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
|
||||
{ (isThreadThumbnailClicked[index] || (commentMediaInfo.type === 'iframe' && !commentMediaInfo.thumbnail)) && (
|
||||
<span>
|
||||
-[
|
||||
[
|
||||
<span className='reply-link'
|
||||
style={{textDecoration: 'underline', cursor: 'pointer'}}
|
||||
onClick={() => {handleThumbnailClick(index, 'thread')}}>Close</span>
|
||||
onClick={() => {handleThumbnailClick(index, 'thread')}}>
|
||||
{isThreadThumbnailClicked[index] ? 'Close' : 'Embed'}
|
||||
</span>
|
||||
]
|
||||
</span>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
{commentMediaInfo?.type === 'iframe' && (
|
||||
<div key={`enlarge-${index}`}
|
||||
className={`img-container ${isThreadThumbnailClicked[index] ? 'expanded-container' : ''}`}>
|
||||
<span key={`fta-${index}`} className="file-thumb" style={isThreadThumbnailClicked[index] ? {} : {width: displayWidth, height: displayHeight}}>
|
||||
{(isThreadThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
|
||||
<iframe
|
||||
className='enlarged'
|
||||
key={`fti-${index}`}
|
||||
src={commentMediaInfo.embedUrl}
|
||||
width={commentMediaInfo.thumbnail ? "560" : "250"}
|
||||
height="315"
|
||||
style={{border: "none"}}
|
||||
title="Embedded content"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen />
|
||||
) : (
|
||||
<span key={`fta-${index}`} className="file-thumb" style={
|
||||
isThreadThumbnailClicked[index] || !commentMediaInfo.thumbnail ?
|
||||
{} : {width: displayWidth, height: displayHeight
|
||||
}}>
|
||||
{isThreadThumbnailClicked[index] && commentMediaInfo.url ? (
|
||||
<Embed url={commentMediaInfo.url} key={`fti-${index}`} />
|
||||
) : commentMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`fti-${index}`}
|
||||
src={commentMediaInfo.thumbnail}
|
||||
@@ -1447,7 +1444,7 @@ const Board = () => {
|
||||
onClick={() => {handleThumbnailClick(index, 'thread')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
)}
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -2113,33 +2110,53 @@ const Board = () => {
|
||||
</div>
|
||||
</div>
|
||||
{replyMediaInfo?.url ? (
|
||||
<div key={`f-${index}`} className="file"
|
||||
style={{marginBottom: "5px"}}>
|
||||
<div key={`ft-${index}`} className="reply-file-text">
|
||||
<div key={`f-${index}`} className="file" style={{marginBottom: "5px"}}>
|
||||
<div key={`ft-${index}`} className="file-text">
|
||||
Link:
|
||||
<a key={`fa-${index}`} href={replyMediaInfo.url} target="_blank"
|
||||
rel="noopener noreferrer">{
|
||||
replyMediaInfo?.url.length > 30 ?
|
||||
replyMediaInfo?.url.slice(0, 30) + "(...)" :
|
||||
replyMediaInfo?.url
|
||||
}</a> ({replyMediaInfo?.type})
|
||||
{replyMediaInfo?.type === "video" || replyMediaInfo?.type === "iframe" ? (
|
||||
isReplyThumbnailClicked[index] && commentMediaInfo.type !== "image" ? (
|
||||
<span>
|
||||
-[
|
||||
<span className='reply-link'
|
||||
style={{textDecoration: 'underline', cursor: 'pointer'}}
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}>Close</span>
|
||||
]
|
||||
</span>)
|
||||
: null)
|
||||
: null}
|
||||
}</a> {replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
|
||||
{ (isReplyThumbnailClicked[index] || (replyMediaInfo.type === 'iframe' && !replyMediaInfo.thumbnail)) && (
|
||||
<span>
|
||||
[
|
||||
<span className='reply-link'
|
||||
style={{textDecoration: 'underline', cursor: 'pointer'}}
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}>
|
||||
{isReplyThumbnailClicked[index] ? 'Close' : 'Embed'}
|
||||
</span>
|
||||
]
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{replyMediaInfo?.type === "webpage" ? (
|
||||
<div key={`enlarge-reply-${index}`} className="img-container">
|
||||
{replyMediaInfo?.type === 'iframe' && (
|
||||
<div key={`enlarge-${index}`}
|
||||
className={`img-container ${isReplyThumbnailClicked[index] ? 'expanded-container' : ''}`}>
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={
|
||||
isReplyThumbnailClicked[index] || !replyMediaInfo.thumbnail ?
|
||||
{} : {width: replyDisplayWidth, height: replyDisplayHeight
|
||||
}}>
|
||||
{isReplyThumbnailClicked[index] && replyMediaInfo.url ? (
|
||||
<Embed url={replyMediaInfo.url} key={`fti-${index}`} />
|
||||
) : replyMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.thumbnail}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{replyMediaInfo?.type === "webpage" && (
|
||||
<div key={`enlarge-${index}`} className="img-container">
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={isReplyThumbnailClicked[index] || !reply.thumbnailUrl ? {} : {width: replyDisplayWidth, height: replyDisplayHeight}}>
|
||||
{reply.thumbnailUrl ? (
|
||||
<img key={`fti-${index}`}
|
||||
<img key={`fti-${index}`}
|
||||
src={replyMediaInfo.thumbnail} alt={replyMediaInfo.type}
|
||||
onClick={(e) => {handleImageClick(e); handleThumbnailClick(index, 'reply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
@@ -2147,51 +2164,50 @@ const Board = () => {
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{replyMediaInfo?.type === "image" ? (
|
||||
<div key={`enlarge-reply-${index}`} className="img-container">
|
||||
)}
|
||||
{replyMediaInfo?.type === "image" && (
|
||||
<div key={`enlarge-${index}`} className="img-container">
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={isReplyThumbnailClicked[index] ? {} : {width: replyDisplayWidth, height: replyDisplayHeight}}>
|
||||
<img key={`fti-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
<img key={`fti-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
onClick={(e) => {handleImageClick(e); handleThumbnailClick(index, 'reply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{replyMediaInfo?.type === "video" ? (
|
||||
<div key={`enlarge-reply-${index}`} className={`img-container ${isReplyThumbnailClicked[index] ? 'expanded-container' : ''}`}>
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={isReplyThumbnailClicked[index] ? {} : {width: replyDisplayWidth, height: replyDisplayHeight}}>
|
||||
{isReplyThumbnailClicked[index] ? (
|
||||
<video controls
|
||||
className='enlarged'
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.url}
|
||||
alt={replyMediaInfo.type}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl}
|
||||
/>
|
||||
) : (
|
||||
<video
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.url}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{replyMediaInfo?.type === "audio" ? (
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={isReplyThumbnailClicked[index] ? {} : {width: replyDisplayWidth, height: replyDisplayHeight}}>
|
||||
<audio controls
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
)}
|
||||
{replyMediaInfo?.type === "video" && (
|
||||
<div key={`enlarge-${index}`} className={`img-container ${isReplyThumbnailClicked[index] ? 'expanded-container' : ''}`}>
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={isReplyThumbnailClicked[index] ? {} : {width: replyDisplayWidth, height: replyDisplayHeight}}>
|
||||
{isReplyThumbnailClicked[index] ? (
|
||||
<video
|
||||
className='enlarged'
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.url}
|
||||
controls
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl}
|
||||
/>
|
||||
) : (
|
||||
<video
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.url}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{replyMediaInfo?.type === "audio" && (
|
||||
<span key={`fta-${index}`} className="file-thumb-reply">
|
||||
<audio controls key={`fti-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
</span>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
{reply.content ? (
|
||||
@@ -2511,17 +2527,11 @@ const Board = () => {
|
||||
{commentMediaInfo?.type === 'iframe' && (
|
||||
<div key={`enlarge-mob-${index}`} className="img-container">
|
||||
<span key={`mob-fta-${index}`} className="file-thumb-mobile" style={isMobileThreadThumbnailClicked[index] ? {} : {marginBottom: '25px'}}>
|
||||
{(isMobileThreadThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
|
||||
{(isMobileThreadThumbnailClicked[index] && commentMediaInfo.url ? (
|
||||
<div style={{width: "92vw"}}>
|
||||
<iframe
|
||||
key={`mob-fti-${index}`}
|
||||
src={commentMediaInfo.embedUrl}
|
||||
style={{border: "none", height: "250px"}}
|
||||
title="Embedded content"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen />
|
||||
<Embed url={commentMediaInfo.url} key={`fti-mobile-${index}`} />
|
||||
</div>
|
||||
) : (
|
||||
) : commentMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`mob-fti-${index}`}
|
||||
src={commentMediaInfo.thumbnail}
|
||||
@@ -2529,7 +2539,7 @@ const Board = () => {
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileThread')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
)}
|
||||
) : <span onClick={() => {handleThumbnailClick(index, 'mobileThread')}}>Embed</span>)}
|
||||
{commentMediaInfo?.type === "video" || commentMediaInfo?.type === "iframe" ? (
|
||||
isMobileThreadThumbnailClicked[index] ? (
|
||||
<div style={{textAlign: "center", marginTop: "15px", marginBottom: "15px"}}>
|
||||
@@ -2538,8 +2548,8 @@ const Board = () => {
|
||||
>Close</span>
|
||||
</div>
|
||||
) : (
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">video</div>
|
||||
)) : <div key={`mob-fi-${index}`} className="file-info-mobile">video</div>}
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>
|
||||
)) : <div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -2744,7 +2754,35 @@ const Board = () => {
|
||||
{reply.link ? (
|
||||
<div key={`mob-f-${index}`} className="file-mobile">
|
||||
{replyMediaInfo?.url ? (
|
||||
replyMediaInfo.type === "webpage" ? (
|
||||
replyMediaInfo.type === "iframe" ? (
|
||||
<div key={`enlarge-mob-${index}`} className="img-container">
|
||||
<span key={`mob-fta-${index}`} className="file-thumb-mobile" style={isMobileReplyThumbnailClicked[index] ? {} : {marginBottom: '25px'}}>
|
||||
{(isMobileReplyThumbnailClicked[index] && replyMediaInfo.url ? (
|
||||
<div style={{width: "92vw"}}>
|
||||
<Embed url={replyMediaInfo.url} key={`fti-mobile-reply-${index}`} />
|
||||
</div>
|
||||
) : replyMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`mob-fti-${index}`}
|
||||
src={replyMediaInfo.thumbnail}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileReply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : <span onClick={() => {handleThumbnailClick(index, 'mobileReply')}}>Embed</span>)}
|
||||
{replyMediaInfo?.type === "video" || replyMediaInfo?.type === "iframe" ? (
|
||||
isMobileReplyThumbnailClicked[index] ? (
|
||||
<div style={{textAlign: "center", marginTop: "15px", marginBottom: "15px"}}>
|
||||
<span className='button-mobile' style={{float: "none", cursor: "pointer"}}
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileReply')}}
|
||||
>Close</span>
|
||||
</div>
|
||||
) : (
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>
|
||||
)) : <div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>}
|
||||
</span>
|
||||
</div>
|
||||
) : replyMediaInfo.type === "webpage" ? (
|
||||
<div key={`enlarge-mob-reply-${index}`} className="img-container">
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile" style={isMobileReplyThumbnailClicked[index] || !reply.thumbnailUrl ? {} : {width: displayWidthMobile, height: displayHeightMobile}}>
|
||||
{reply.thumbnailUrl ? (
|
||||
@@ -2769,7 +2807,7 @@ const Board = () => {
|
||||
</span>
|
||||
</div>
|
||||
) : replyMediaInfo.type === "video" ? (
|
||||
<span key={`mob-ft${thread.cid}`} className="file-thumb-mobile" style={isMobileReplyThumbnailClicked[index] ? {} : {marginBottom: '25px'}}>
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile" style={isMobileReplyThumbnailClicked[index] ? {} : {marginBottom: '25px'}}>
|
||||
{isMobileReplyThumbnailClicked[index] ? (
|
||||
<video key={`fti-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
|
||||
@@ -448,7 +448,7 @@ const CatalogPost = ({post}) => {
|
||||
</BoardForm>
|
||||
<Link style={{all: "unset", cursor: "pointer"}} to={`/p/${selectedAddress}/rules`}>
|
||||
<div className="teaser" style={{maxHeight: '312px'}}>
|
||||
<div style={{cursor: 'text'}}>
|
||||
<div style={{cursor: 'pointer'}}>
|
||||
<span ref={textRef}
|
||||
onMouseOver={() => {
|
||||
setIsHoveringOnThread('rules');
|
||||
@@ -621,7 +621,7 @@ const CatalogPost = ({post}) => {
|
||||
<Link style={{all: "unset", cursor: "pointer"}} to={`/p/${selectedAddress}/description`}
|
||||
onClick={() => setSelectedThread("description")}>
|
||||
<div className="teaser" style={{maxHeight: '170px'}}>
|
||||
<div style={{cursor: 'text'}}>
|
||||
<div style={{cursor: 'pointer'}}>
|
||||
<span ref={textRef}
|
||||
onMouseOver={() => {
|
||||
setIsHoveringOnThread('description');
|
||||
@@ -920,7 +920,7 @@ const CatalogPost = ({post}) => {
|
||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${selectedAddress}/c/${thread.cid}`}
|
||||
onClick={() => setSelectedThread(thread.cid)}>
|
||||
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}>
|
||||
<div style={{cursor:"text"}}>
|
||||
<div style={{cursor:"pointer"}}>
|
||||
<span key={`teaser-width${thread.cid}`} ref={textRef}
|
||||
onMouseOver={() => {
|
||||
setIsHoveringOnThread(thread.cid);
|
||||
|
||||
+153
-95
@@ -13,6 +13,7 @@ import { AlertModal } from '../styled/modals/AlertModal.styled';
|
||||
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
|
||||
import BoardStats from '../BoardStats';
|
||||
import EditLabel from '../EditLabel';
|
||||
import Embed from '../Embed';
|
||||
import ImageBanner from '../ImageBanner';
|
||||
import OfflineIndicator from '../OfflineIndicator';
|
||||
import PendingLabel from '../PendingLabel';
|
||||
@@ -121,6 +122,7 @@ const Thread = () => {
|
||||
const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({});
|
||||
const [isReplyThumbnailClicked, setIsReplyThumbnailClicked] = useState({});
|
||||
const [isMobileThreadThumbnailClicked, setIsMobileThreadThumbnailClicked] = useState({});
|
||||
const [isMobileReplyThumbnailClicked, setIsMobileReplyThumbnailClicked] = useState({});
|
||||
const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
|
||||
|
||||
|
||||
@@ -157,6 +159,12 @@ const Thread = () => {
|
||||
[index]: !prevState[index],
|
||||
}));
|
||||
break;
|
||||
case 'mobileReply':
|
||||
setIsMobileReplyThumbnailClicked(prevState => ({
|
||||
...prevState,
|
||||
[index]: !prevState[index],
|
||||
}));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -862,33 +870,26 @@ const Thread = () => {
|
||||
commentMediaInfo?.url.length > 30 ?
|
||||
commentMediaInfo?.url.slice(0, 30) + "(...)" :
|
||||
commentMediaInfo?.url
|
||||
}</a> ({commentMediaInfo?.type === "iframe" ? "video" : commentMediaInfo?.type})
|
||||
{isThreadThumbnailClicked[index] ? (
|
||||
}</a> {commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
|
||||
{ (isThreadThumbnailClicked[index] || (commentMediaInfo.type === 'iframe' && !commentMediaInfo.thumbnail)) && (
|
||||
<span>
|
||||
-[
|
||||
[
|
||||
<span className='reply-link'
|
||||
style={{textDecoration: 'underline', cursor: 'pointer'}}
|
||||
onClick={() => {handleThumbnailClick(index, 'thread')}}>Close</span>
|
||||
onClick={() => {handleThumbnailClick(index, 'thread')}}>
|
||||
{isThreadThumbnailClicked[index] ? 'Close' : 'Embed'}
|
||||
</span>
|
||||
]
|
||||
</span>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
{commentMediaInfo?.type === 'iframe' && (
|
||||
<div key={`enlarge-${index}`}
|
||||
className={`img-container ${isThreadThumbnailClicked[index] ? 'expanded-container' : ''}`}>
|
||||
<span key={`fta-${index}`} className="file-thumb">
|
||||
{(isThreadThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
|
||||
<iframe
|
||||
className='enlarged'
|
||||
key={`fti-${index}`}
|
||||
src={commentMediaInfo.embedUrl}
|
||||
width={commentMediaInfo.thumbnail ? "560" : "250"}
|
||||
height="315"
|
||||
style={{border: "none"}}
|
||||
title="Embedded content"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen />
|
||||
) : (
|
||||
{isThreadThumbnailClicked[index] && commentMediaInfo.url ? (
|
||||
<Embed url={commentMediaInfo.url} key={`fti-${index}`} />
|
||||
) : commentMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`fti-${index}`}
|
||||
src={commentMediaInfo.thumbnail}
|
||||
@@ -896,7 +897,7 @@ const Thread = () => {
|
||||
onClick={() => {handleThumbnailClick(index, 'thread')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
)}
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -1521,27 +1522,48 @@ const Thread = () => {
|
||||
</div>
|
||||
</div>
|
||||
{replyMediaInfo?.url ? (
|
||||
<div key={`f-${index}`} className="file"
|
||||
style={{marginBottom: "5px"}}>
|
||||
<div key={`ft-${index}`} className="reply-file-text">
|
||||
<div key={`f-${index}`} className="file" style={{marginBottom: "5px"}}>
|
||||
<div key={`ft-${index}`} className="file-text">
|
||||
Link:
|
||||
<a key={`fa-${index}`} href={replyMediaInfo.url} target="_blank"
|
||||
rel="noopener noreferrer">{
|
||||
replyMediaInfo?.url.length > 30 ?
|
||||
replyMediaInfo?.url.slice(0, 30) + "(...)" :
|
||||
replyMediaInfo?.url
|
||||
}</a> ({replyMediaInfo?.type})
|
||||
{replyMediaInfo?.type === "video" || replyMediaInfo?.type === "iframe" ? (
|
||||
isReplyThumbnailClicked[index] ? (
|
||||
<span>
|
||||
-[
|
||||
<span className='reply-link'
|
||||
style={{textDecoration: 'underline', cursor: 'pointer'}}
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}>Close</span>
|
||||
]
|
||||
</span>) : null)
|
||||
: null}
|
||||
}</a> {replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
|
||||
{ (isReplyThumbnailClicked[index] || (replyMediaInfo.type === 'iframe' && !replyMediaInfo.thumbnail)) && (
|
||||
<span>
|
||||
[
|
||||
<span className='reply-link'
|
||||
style={{textDecoration: 'underline', cursor: 'pointer'}}
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}>
|
||||
{isReplyThumbnailClicked[index] ? 'Close' : 'Embed'}
|
||||
</span>
|
||||
]
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{replyMediaInfo?.type === 'iframe' && (
|
||||
<div key={`enlarge-${index}`}
|
||||
className={`img-container ${isReplyThumbnailClicked[index] ? 'expanded-container' : ''}`}>
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={
|
||||
isReplyThumbnailClicked[index] || !replyMediaInfo.thumbnail ?
|
||||
{} : {width: replyDisplayWidth, height: replyDisplayHeight
|
||||
}}>
|
||||
{isReplyThumbnailClicked[index] && replyMediaInfo.url ? (
|
||||
<Embed url={replyMediaInfo.url} key={`fti-${index}`} />
|
||||
) : replyMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.thumbnail}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'reply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{replyMediaInfo?.type === "webpage" ? (
|
||||
<div key={`enlarge-reply-${index}`} className="img-container">
|
||||
<span key={`fta-${index}`} className="file-thumb-reply" style={isReplyThumbnailClicked[index] ? {} : {width: replyDisplayWidth, height: replyDisplayHeight}}>
|
||||
@@ -1796,39 +1818,33 @@ const Thread = () => {
|
||||
<div key={`mob-f-${index}`} className="file-mobile">
|
||||
{commentMediaInfo?.type === 'iframe' && (
|
||||
<div key={`enlarge-mob-${index}`} className="img-container">
|
||||
<span key={`mob-fta-${index}`} className="file-thumb-mobile">
|
||||
{(isMobileThreadThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
|
||||
<div style={{width: "92vw"}}>
|
||||
<iframe
|
||||
key={`mob-fti-${index}`}
|
||||
src={commentMediaInfo.embedUrl}
|
||||
style={{border: "none", height: "250px"}}
|
||||
title="Embedded content"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen />
|
||||
<span key={`mob-fta-${index}`} className="file-thumb-mobile" style={isMobileThreadThumbnailClicked[index] ? {} : {marginBottom: '25px'}}>
|
||||
{(isMobileThreadThumbnailClicked[index] && commentMediaInfo.url ? (
|
||||
<div style={{width: "92vw"}}>
|
||||
<Embed url={commentMediaInfo.url} key={`fti-mobile-${index}`} />
|
||||
</div>
|
||||
) : commentMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`mob-fti-${index}`}
|
||||
src={commentMediaInfo.thumbnail}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileThread')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : <span onClick={() => {handleThumbnailClick(index, 'mobileThread')}}>Embed</span>)}
|
||||
{commentMediaInfo?.type === "video" || commentMediaInfo?.type === "iframe" ? (
|
||||
isMobileThreadThumbnailClicked[index] ? (
|
||||
<div style={{textAlign: "center", marginTop: "15px", marginBottom: "15px"}}>
|
||||
<span className='button-mobile' style={{float: "none", cursor: "pointer"}}
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileThread')}}
|
||||
>Close</span>
|
||||
</div>
|
||||
) : (
|
||||
<img
|
||||
key={`mob-fti-${index}`}
|
||||
src={commentMediaInfo.thumbnail}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileThread')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
)}
|
||||
{commentMediaInfo?.type === "video" || commentMediaInfo?.type === "iframe" ? (
|
||||
isMobileThreadThumbnailClicked[index] ? (
|
||||
<div style={{textAlign: "center", marginTop: "15px", marginBottom: "15px"}}>
|
||||
<span className='button-mobile' style={{float: "none", cursor: "pointer"}}
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileThread')}}
|
||||
>Close</span>
|
||||
</div>
|
||||
) : (
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">video</div>
|
||||
)) : <div key={`mob-fi-${index}`} className="file-info-mobile">video</div>}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>
|
||||
)) : <div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{commentMediaInfo?.url ? (
|
||||
commentMediaInfo.type === "webpage" ? (
|
||||
<div key={`enlarge-mob-${index}`} className="img-container">
|
||||
@@ -1996,47 +2012,89 @@ const Thread = () => {
|
||||
{reply.link ? (
|
||||
<div key={`mob-f-${reply.cid}`} className="file-mobile">
|
||||
{replyMediaInfo?.url ? (
|
||||
replyMediaInfo.type === "webpage" ? (
|
||||
<div key="enlarge-reply-mob" className="img-container">
|
||||
replyMediaInfo.type === "iframe" ? (
|
||||
<div key={`enlarge-mob-${index}`} className="img-container">
|
||||
<span key={`mob-fta-${index}`} className="file-thumb-mobile" style={isMobileReplyThumbnailClicked[index] ? {} : {marginBottom: '25px'}}>
|
||||
{(isMobileReplyThumbnailClicked[index] && replyMediaInfo.url ? (
|
||||
<div style={{width: "92vw"}}>
|
||||
<Embed url={replyMediaInfo.url} key={`fti-mobile-reply-${index}`} />
|
||||
</div>
|
||||
) : replyMediaInfo.thumbnail ? (
|
||||
<img
|
||||
key={`mob-fti-${index}`}
|
||||
src={replyMediaInfo.thumbnail}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileReply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : <span onClick={() => {handleThumbnailClick(index, 'mobileReply')}}>Embed</span>)}
|
||||
{replyMediaInfo?.type === "video" || replyMediaInfo?.type === "iframe" ? (
|
||||
isMobileReplyThumbnailClicked[index] ? (
|
||||
<div style={{textAlign: "center", marginTop: "15px", marginBottom: "15px"}}>
|
||||
<span className='button-mobile' style={{float: "none", cursor: "pointer",
|
||||
borderRadius: '3px', padding: '6px 10px 5px',}}
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileReply')}}
|
||||
>Close</span>
|
||||
</div>
|
||||
) : (
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>
|
||||
)) : <div key={`mob-fi-${index}`} className="file-info-mobile">webpage</div>}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
) : replyMediaInfo.type === "webpage" ? (
|
||||
<div key={`enlarge-mob-reply-${index}`} className="img-container">
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile">
|
||||
{reply.thumbnailUrl ? (
|
||||
<img key={`mob-img-${reply.cid}`}
|
||||
src={replyMediaInfo.thumbnail} alt={replyMediaInfo.type}
|
||||
onClick={handleImageClick}
|
||||
<img key={`mob-img-${index}`}
|
||||
src={replyMediaInfo.thumbnail} alt="thumbnail"
|
||||
onClick={(e) => {handleImageClick(e); handleThumbnailClick(index, 'mobileReply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : null}
|
||||
<div key={`mob-fi-${reply.cid}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
</span>
|
||||
</div>
|
||||
) : replyMediaInfo.type === "image" ? (
|
||||
<div key="enlarge-reply-mob" className="img-container">
|
||||
) : replyMediaInfo.type === "image" ? (
|
||||
<div key={`enlarge-mob-reply-${index}`} className="img-container">
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile">
|
||||
<img key={`mob-img-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
onClick={(e) => {handleImageClick(e); handleThumbnailClick(index, 'mobileReply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
</span>
|
||||
</div>
|
||||
) : replyMediaInfo.type === "video" ? (
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile">
|
||||
<img key={`mob-img-${reply.cid}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
onClick={handleImageClick}
|
||||
style={{cursor: "pointer"}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
<div key={`mob-fi-${reply.cid}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
{isMobileReplyThumbnailClicked[index] ? (
|
||||
<video key={`fti-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
controls
|
||||
style={{ all: 'unset', width: '100%', height: '100%', cursor: 'pointer'}}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
) : (
|
||||
<video
|
||||
key={`fti-${index}`}
|
||||
src={replyMediaInfo.url}
|
||||
alt="thumbnail"
|
||||
onClick={() => {handleThumbnailClick(index, 'mobileReply')}}
|
||||
style={{cursor: "pointer"}}
|
||||
id="video-thumbnail-mobile"
|
||||
onError={(e) => e.target.src = fallbackImgUrl}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
) : replyMediaInfo.type === "video" ? (
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile">
|
||||
<video key={`fti-${reply.cid}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
style={{ pointerEvents: "none" }}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
<div key={`mob-fi-${reply.cid}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
</span>
|
||||
) : replyMediaInfo.type === "audio" ? (
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile">
|
||||
<audio key={`mob-img-${reply.cid}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
<div key={`mob-fi-${reply.cid}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
</span>
|
||||
) : null
|
||||
) : null}
|
||||
) : replyMediaInfo.type === "audio" ? (
|
||||
<span key={`mob-ft${reply.cid}`} className="file-thumb-mobile">
|
||||
<audio key={`mob-img-${index}`}
|
||||
src={replyMediaInfo.url} alt={replyMediaInfo.type}
|
||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||
<div key={`mob-fi-${index}`} className="file-info-mobile">{replyMediaInfo.type}</div>
|
||||
</span>
|
||||
) : null
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<blockquote key={`mob-pm-${index}`} className="post-message-mobile">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import extName from 'ext-name';
|
||||
import { canEmbed } from '../components/Embed';
|
||||
|
||||
const getCommentMediaInfo = (comment) => {
|
||||
if (!comment?.thumbnailUrl && !comment?.link) {
|
||||
@@ -9,56 +10,26 @@ const getCommentMediaInfo = (comment) => {
|
||||
try {
|
||||
const url = new URL(comment.link);
|
||||
const host = url.hostname;
|
||||
let embedUrl = null;
|
||||
let scrapedThumbnailUrl;
|
||||
|
||||
if (['youtube.com', 'www.youtube.com', 'youtu.be'].includes(host)) {
|
||||
const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
|
||||
embedUrl = `https://www.youtube-nocookie.com/embed/${videoId}`;
|
||||
const thumbnailUrl = `https://img.youtube.com/vi/${videoId}/sddefault.jpg`;
|
||||
return {
|
||||
url: comment.link,
|
||||
embedUrl,
|
||||
type: 'iframe',
|
||||
thumbnail: comment.thumbnailUrl || thumbnailUrl,
|
||||
};
|
||||
} else if (host.includes('odysee.com')) {
|
||||
const pathComponents = url.pathname.split('/');
|
||||
const channelAndId = pathComponents[1];
|
||||
const videoAndId = pathComponents[2];
|
||||
embedUrl = `https://odysee.com/$/embed/${channelAndId}/${videoAndId}`;
|
||||
|
||||
// TODO: add support for Rumble, video id is dynamic
|
||||
|
||||
// } else if (host.includes('rumble.com')) {
|
||||
// const regex = /(\/v.+?)-/;
|
||||
// const match = regex.exec(url.pathname);
|
||||
// if (match) {
|
||||
// const videoId = match[1].slice(1);
|
||||
// embedUrl = `https://rumble.com/embed/${videoId}/?pub=4`;
|
||||
// }
|
||||
|
||||
scrapedThumbnailUrl = `https://img.youtube.com/vi/${videoId}/sddefault.jpg`;
|
||||
|
||||
} else if (host.includes('bitchute.com')) {
|
||||
const videoId = url.pathname.split('/')[2];
|
||||
embedUrl = `https://www.bitchute.com/embed/${videoId}/`;
|
||||
scrapedThumbnailUrl = `https://static-3.bitchute.com/live/cover_images/F61vWF4shy8s/${videoId}_640x360.jpg`;
|
||||
|
||||
} else if (host.includes('streamable.com')) {
|
||||
const videoId = url.pathname.split('/')[1];
|
||||
embedUrl = `https://streamable.com/e/${videoId}?quality=highest`;
|
||||
|
||||
// TODO: Add support for Giphy (doesn't have thumbnails, size is variable)
|
||||
|
||||
// } else if (host.includes('giphy.com')) {
|
||||
// const hyphenComponents = url.pathname.split('-');
|
||||
// const gifId = hyphenComponents[hyphenComponents.length - 1];
|
||||
// embedUrl = `https://giphy.com/embed/${gifId}`;
|
||||
scrapedThumbnailUrl = `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`;
|
||||
}
|
||||
|
||||
if (embedUrl) {
|
||||
if (canEmbed(url)) {
|
||||
return {
|
||||
url: comment.link,
|
||||
embedUrl,
|
||||
type: 'iframe',
|
||||
thumbnail: comment.thumbnailUrl,
|
||||
thumbnail: comment.thumbnailUrl || scrapedThumbnailUrl,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user