Files
Obsidian/obsidian-halo/src/utils/image.ts
T
Serendipity 7d332d3b8c feat(halo): 添加图片自动上传功能
- 新增图片处理工具模块 `src/utils/image.ts`,包含图片引用提取、绝对路径解析和路径替换功能
- 新增图片上传服务 `src/service/image-uploader.ts`,支持调用 Halo 媒体 API 上传图片并实现缓存机制
- 在设置界面添加图片上传开关和上传路径配置项
- 更新发布流程,在提交到 Halo 前自动检测并上传本地图片,替换为远程 URL
- 添加英文、简体中文和繁体中文的国际化文案
- 更新插件版本至 1.1.1 并完善相关配置文件
2026-04-26 16:11:11 +08:00

84 lines
2.0 KiB
TypeScript

import { TFile, type Vault } from "obsidian";
export interface ImageReference {
alt: string;
path: string;
fullMatch: string;
}
const IMAGE_PATTERN = /!\[([^\]]*)\]\(([^)]+)\)/g;
export function extractImageReferences(content: string): ImageReference[] {
const references: ImageReference[] = [];
const matches = content.matchAll(IMAGE_PATTERN);
for (const match of matches) {
const [, alt, path] = match;
if (isExternalUrl(path)) {
continue;
}
references.push({
alt,
path,
fullMatch: match[0],
});
}
return references;
}
export function getAbsolutePath(vault: Vault, filePath: string, currentFilePath: string): string | null {
let absolutePath: string;
if (filePath.startsWith("./") || filePath.startsWith("../")) {
absolutePath = resolveRelativePath(currentFilePath, filePath);
} else if (filePath.startsWith("/")) {
absolutePath = filePath.substring(1);
} else {
absolutePath = resolveRelativePath(currentFilePath, filePath);
}
const file = vault.getAbstractFileByPath(absolutePath);
if (file instanceof TFile) {
return absolutePath;
}
return null;
}
export function replaceImagePaths(content: string, pathMapping: Map<string, string>): string {
return content.replace(IMAGE_PATTERN, (fullMatch, alt, path) => {
const newPath = pathMapping.get(path);
if (newPath) {
return `![${alt}](${newPath})`;
}
return fullMatch;
});
}
function isExternalUrl(path: string): boolean {
return path.startsWith("http://") || path.startsWith("https://") || path.startsWith("data:");
}
function resolveRelativePath(currentFilePath: string, relativePath: string): string {
const currentParts = currentFilePath.split("/");
currentParts.pop();
const relativeParts = relativePath.split("/");
for (const part of relativeParts) {
if (part === "..") {
currentParts.pop();
} else if (part !== ".") {
currentParts.push(part);
}
}
return currentParts.join("/");
}