add embed, media utils, time utils, url utils

This commit is contained in:
plebeius.eth
2024-03-26 13:17:55 +01:00
parent 97e5c17c4d
commit 5620a68337
4 changed files with 147 additions and 106 deletions
+68 -89
View File
@@ -2,6 +2,7 @@ import { Comment } from '@plebbit/plebbit-react-hooks';
import extName from 'ext-name';
import { canEmbed } from '../../components/embed';
import memoize from 'memoizee';
import { isValidURL } from './url-utils';
export interface CommentMediaInfo {
url: string;
@@ -16,106 +17,84 @@ export const getHasThumbnail = (commentMediaInfo: CommentMediaInfo | undefined,
commentMediaInfo &&
(commentMediaInfo.type === 'image' ||
commentMediaInfo.type === 'video' ||
commentMediaInfo.type === 'gif' ||
(commentMediaInfo.type === 'webpage' && commentMediaInfo.thumbnail) ||
(commentMediaInfo.type === 'iframe' && iframeThumbnail))
? true
: false;
};
const getCommentMediaInfo = (comment: Comment) => {
const getYouTubeVideoId = (url: URL): string | null => {
if (url.host.includes('youtu.be')) {
return url.pathname.slice(1);
} else if (url.searchParams.has('v')) {
return url.searchParams.get('v');
} else if (url.host.startsWith('yt.')) {
return url.searchParams.get('v');
}
return null;
};
const getPatternThumbnailUrl = (url: URL): string | undefined => {
const videoId = getYouTubeVideoId(url);
if (videoId) {
return `https://img.youtube.com/vi/${videoId}/0.jpg`;
}
if (url.host.includes('streamable.com')) {
const videoId = url.pathname.split('/')[1];
return `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`;
}
};
const getLinkMediaInfo = (link: string): CommentMediaInfo | undefined => {
if (!isValidURL(link)) {
return;
}
const url = new URL(link);
let patternThumbnailUrl: string | undefined;
let type: string = 'webpage';
let mime: string | undefined;
// Check for common dynamic image URL patterns
if (link.includes('/_next/image?')) {
// Next.js Image component
return { url: link, type: 'image' };
}
try {
mime = extName(url.pathname.slice(url.pathname.lastIndexOf('/') + 1))[0]?.mime;
if (mime) {
if (mime.startsWith('image')) {
type = mime === 'image/gif' ? 'gif' : 'image';
} else if (mime.startsWith('video')) {
type = 'video';
} else if (mime.startsWith('audio')) {
type = 'audio';
}
}
if (canEmbed(url) || url.host.startsWith('yt.')) {
type = 'iframe';
patternThumbnailUrl = getPatternThumbnailUrl(url);
}
} catch (e) {
console.error(e);
}
return { url: link, type, patternThumbnailUrl };
};
const getCommentMediaInfo = (comment: Comment): CommentMediaInfo | undefined => {
if (!comment?.thumbnailUrl && !comment?.link) {
return;
}
if (comment?.link) {
let mime: string | undefined;
try {
mime = extName(new URL(comment?.link).pathname.toLowerCase().replace('/', ''))[0]?.mime;
} catch (e) {
return;
}
const url = new URL(comment.link);
const host = url.hostname;
let patternThumbnailUrl;
if (['youtube.com', 'www.youtube.com', 'youtu.be', 'www.youtu.be', 'm.youtube.com'].includes(host)) {
const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
patternThumbnailUrl = `https://img.youtube.com/vi/${videoId}/0.jpg`;
} else if (host.includes('streamable.com')) {
const videoId = url.pathname.split('/')[1];
patternThumbnailUrl = `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`;
}
if (canEmbed(url)) {
return {
url: comment.link,
type: 'iframe',
thumbnail: comment.thumbnailUrl,
patternThumbnailUrl,
};
}
if (mime?.startsWith('image')) {
return { url: comment.link, type: 'image' };
}
if (mime?.startsWith('video')) {
return { url: comment.link, type: 'video', thumbnail: comment.thumbnailUrl };
}
if (mime?.startsWith('audio')) {
return { url: comment.link, type: 'audio' };
}
if (comment?.thumbnailUrl && comment?.thumbnailUrl !== comment?.link) {
return { url: comment.link, type: 'webpage', thumbnail: comment.thumbnailUrl };
}
if (comment?.link) {
return { url: comment.link, type: 'webpage' };
}
const linkInfo = comment.link ? getLinkMediaInfo(comment.link) : undefined;
if (linkInfo) {
linkInfo.thumbnail = comment.thumbnailUrl || linkInfo.thumbnail;
return linkInfo;
}
return;
};
export const getCommentMediaInfoMemoized = memoize(getCommentMediaInfo, { max: 1000 });
const getLinkMediaInfo = (link: string) => {
let mime: string | undefined;
try {
mime = extName(new URL(link).pathname.toLowerCase().replace('/', ''))[0]?.mime;
} catch (e) {
return;
}
const url = new URL(link);
const host = url.hostname;
let patternThumbnailUrl;
if (['youtube.com', 'www.youtube.com', 'youtu.be', 'www.youtu.be', 'm.youtube.com'].includes(host)) {
const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
patternThumbnailUrl = `https://img.youtube.com/vi/${videoId}/0.jpg`;
} else if (host.includes('streamable.com')) {
const videoId = url.pathname.split('/')[1];
patternThumbnailUrl = `https://cdn-cf-east.streamable.com/image/${videoId}.jpg`;
}
if (canEmbed(url)) {
return {
url: link,
type: 'iframe',
patternThumbnailUrl,
};
}
if (mime?.startsWith('image')) {
return { url: link, type: 'image' };
}
if (mime?.startsWith('video')) {
return { url: link, type: 'video' };
}
if (mime?.startsWith('audio')) {
return { url: link, type: 'audio' };
}
return { url: link, type: 'webpage' };
};
export const getLinkMediaInfoMemoized = memoize(getLinkMediaInfo, { max: 1000 });