import { extname } from "path"; import type { ImageRef, ThreadItem } from "../types"; export function imageExtFromUrl(url: string): string { const clean = url.split("?")[0] ?? url; const ext = extname(clean).toLowerCase(); if (ext && [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp"].includes(ext)) return ext; return ".img"; } export function parseImagesFromMarkdown(md: string): Array<{ url: string; alt?: string }> { const out: Array<{ url: string; alt?: string }> = []; const markdownImage = /!\[([^\]]*)\]\((\S+?)(?:\s+"[^"]*")?\)/g; for (const match of md.matchAll(markdownImage)) { const alt = match[1] ?? ""; const url = (match[2] ?? "").replace(/[)>]+$/, "").trim(); if (url) out.push({ url, alt }); } const htmlImage = /]*src=["']([^"']+)["'][^>]*>/gi; for (const match of md.matchAll(htmlImage)) { const url = (match[1] ?? "").trim(); if (url) out.push({ url }); } const bareImageUrl = /(https?:\/\/\S+\.(?:png|jpe?g|gif|webp|svg|bmp)(?:\?[^\s"')<>]+)?)/gi; for (const match of md.matchAll(bareImageUrl)) { const url = (match[1] ?? "").trim(); if (url) out.push({ url }); } return out; } export function collectImages(items: ThreadItem[]): ImageRef[] { const seen = new Map(); let id = 1; for (const item of items) { const images = parseImagesFromMarkdown(item.body); for (const image of images) { if (!seen.has(image.url)) { seen.set(image.url, { id, url: image.url, alt: image.alt }); id += 1; } } } return [...seen.values()].sort((a, b) => a.id - b.id); } export function replaceImagesWithTags(md: string, images: ImageRef[]): string { if (!md) return md; const byUrl = new Map(images.map((image) => [image.url, image.id])); let next = md.replace(/!\[([^\]]*)\]\((\S+?)(?:\s+"[^"]*")?\)/g, (full, _alt, rawUrl) => { const url = String(rawUrl ?? "").replace(/[)>]+$/, "").trim(); const id = byUrl.get(url); return id ? `[image #${id}]` : full; }); next = next.replace(/]*src=["']([^"']+)["'][^>]*>/gi, (full, rawUrl) => { const url = String(rawUrl ?? "").trim(); const id = byUrl.get(url); return id ? `[image #${id}]` : full; }); next = next.replace(/(https?:\/\/\S+\.(?:png|jpe?g|gif|webp|svg|bmp)(?:\?[^\s"')<>]+)?)/gi, (full, rawUrl) => { const url = String(rawUrl ?? "").trim(); const id = byUrl.get(url); return id ? `[image #${id}]` : full; }); return next; }