/** * @fileoverview URL Utilities for Rantii * @author retoor * @description URL parsing and detection utilities * @keywords url, link, youtube, image, detection */ const URL_REGEX = /https?:\/\/[^\s<]+[^<.,:;"')\]\s]/gi; const YOUTUBE_REGEX = /(?:youtube\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/i; const IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp']; function extractUrls(text) { const matches = text.match(URL_REGEX); return matches || []; } function isYoutubeUrl(url) { return YOUTUBE_REGEX.test(url); } function getYoutubeVideoId(url) { const match = url.match(YOUTUBE_REGEX); return match ? match[1] : null; } function getYoutubeThumbnail(videoId) { return `/api/proxy-image?url=${encodeURIComponent(`https://img.youtube.com/vi/${videoId}/hqdefault.jpg`)}`; } function getYoutubeEmbedUrl(videoId) { return `https://www.youtube-nocookie.com/embed/${videoId}`; } function isImageUrl(url) { const lower = url.toLowerCase(); return IMAGE_EXTENSIONS.some(ext => lower.includes(ext)); } function isGifUrl(url) { return url.toLowerCase().includes('.gif'); } function extractImageUrls(text) { return extractUrls(text).filter(isImageUrl); } function extractYoutubeUrls(text) { return extractUrls(text).filter(isYoutubeUrl); } function extractNonMediaUrls(text) { return extractUrls(text).filter(url => !isImageUrl(url) && !isYoutubeUrl(url)); } function sanitizeUrl(url) { try { const parsed = new URL(url); if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') { return null; } return parsed.href; } catch { return null; } } function getDomain(url) { try { const parsed = new URL(url); return parsed.hostname; } catch { return null; } } function makeAbsoluteUrl(url, base) { try { return new URL(url, base).href; } catch { return url; } } function isDevrantImageUrl(url) { return url.includes('devrant.com') || url.includes('devrant.io'); } function buildDevrantImageUrl(imagePath) { if (!imagePath) return null; if (imagePath.startsWith('http')) { return `/api/proxy-image?url=${encodeURIComponent(imagePath)}`; } return `/api/proxy-image?url=${encodeURIComponent(`https://img.devrant.com/${imagePath}`)}`; } function buildAvatarUrl(avatar) { if (!avatar || !avatar.i) { return null; } return `/api/proxy-image?url=${encodeURIComponent(`https://avatars.devrant.com/${avatar.i}`)}`; } export { extractUrls, isYoutubeUrl, getYoutubeVideoId, getYoutubeThumbnail, getYoutubeEmbedUrl, isImageUrl, isGifUrl, extractImageUrls, extractYoutubeUrls, extractNonMediaUrls, sanitizeUrl, getDomain, makeAbsoluteUrl, isDevrantImageUrl, buildDevrantImageUrl, buildAvatarUrl };