2 changed files with 72 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||
/** 与 `upload` 返回及静态路径一致,无前导 host */ |
|||
export const POST_MEDIA_PUBLIC_PREFIX = "/public/assets/"; |
|||
|
|||
/** 从未引用:created_at 起算;曾引用:dereferenced_at 起算 */ |
|||
export const MEDIA_ORPHAN_GRACE_HOURS_NEVER_REF = 24; |
|||
export const MEDIA_ORPHAN_GRACE_HOURS_AFTER_DEREF = 24; |
|||
|
|||
export const MEDIA_IMAGE_MAX_WIDTH_PX = 1920; |
|||
export const MEDIA_WEBP_QUALITY = 82; |
|||
|
|||
export const RELATIVE_ASSETS_DIR = "public/assets"; |
|||
@ -0,0 +1,61 @@ |
|||
import { POST_MEDIA_PUBLIC_PREFIX } from "#server/constants/media"; |
|||
|
|||
const MD_IMG_RE = /!\[[^\]]*]\(([^)]+)\)/g; |
|||
|
|||
function normalizeUrl(raw: string): string { |
|||
const t = raw.trim().replace(/^<|>$/g, "").split(/\s+/)[0] ?? ""; |
|||
if (t.startsWith(POST_MEDIA_PUBLIC_PREFIX)) { |
|||
return t; |
|||
} |
|||
return ""; |
|||
} |
|||
|
|||
/** 从 markdown 中提取本站图片 URL(去重,顺序稳定) */ |
|||
export function extractMediaUrlsFromMarkdown(markdown: string): string[] { |
|||
const out: string[] = []; |
|||
const seen = new Set<string>(); |
|||
let m: RegExpExecArray | null; |
|||
const re = new RegExp(MD_IMG_RE.source, MD_IMG_RE.flags); |
|||
while ((m = re.exec(markdown)) !== null) { |
|||
const u = normalizeUrl(m[1] ?? ""); |
|||
if (u && !seen.has(u)) { |
|||
seen.add(u); |
|||
out.push(u); |
|||
} |
|||
} |
|||
return out; |
|||
} |
|||
|
|||
export function extractMediaUrlsFromCover(coverUrl: string | null | undefined): string[] { |
|||
if (!coverUrl) { |
|||
return []; |
|||
} |
|||
const u = normalizeUrl(coverUrl); |
|||
return u ? [u] : []; |
|||
} |
|||
|
|||
export function mergePostMediaUrls(bodyMarkdown: string, coverUrl: string | null | undefined): string[] { |
|||
const a = extractMediaUrlsFromMarkdown(bodyMarkdown); |
|||
const b = extractMediaUrlsFromCover(coverUrl); |
|||
const seen = new Set<string>(a); |
|||
for (const u of b) { |
|||
if (!seen.has(u)) { |
|||
seen.add(u); |
|||
a.push(u); |
|||
} |
|||
} |
|||
return a; |
|||
} |
|||
|
|||
/** `/public/assets/foo.webp` → `foo.webp` */ |
|||
export function publicAssetUrlToStorageKey(url: string): string | null { |
|||
const t = url.trim(); |
|||
if (!t.startsWith(POST_MEDIA_PUBLIC_PREFIX)) { |
|||
return null; |
|||
} |
|||
const key = t.slice(POST_MEDIA_PUBLIC_PREFIX.length).replace(/^\/+/, ""); |
|||
if (!key || key.includes("..") || key.includes("/") || key.includes("\\")) { |
|||
return null; |
|||
} |
|||
return key; |
|||
} |
|||
Loading…
Reference in new issue