You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TypeScript读取textbundle文件并导入Obsidian(浏览器端,无HTML)

浏览器端读取TextBundle并提取内容导入Obsidian的实现方案

TextBundle是遵循特定目录结构的资源包,核心包含content.md文本文件和assets/目录下的图片附件。以下是浏览器端用JavaScript/TypeScript实现读取、提取并适配Obsidian导入的步骤和代码:

核心处理逻辑

  1. 接收用户上传的TextBundle(支持文件夹或打包后的ZIP包)
  2. 解析包内结构,提取content.md文本和所有图片文件
  3. 修正Markdown中的图片引用路径,适配Obsidian的相对路径规则
  4. 生成可直接导入Obsidian的文件包

实现代码

1. 处理文件夹形式的TextBundle上传

利用浏览器的webkitdirectory属性读取用户选择的TextBundle文件夹:

// HTML部分
<input type="file" id="folderInput" webkitdirectory multiple>
<button onclick="processTextBundle()">处理并导出</button>

// TypeScript逻辑
async function processTextBundle() {
  const input = document.getElementById('folderInput') as HTMLInputElement;
  const files = Array.from(input.files || []);
  
  // 筛选核心文件
  const mdFile = files.find(f => f.name === 'content.md');
  const imageFiles = files.filter(f => f.webkitRelativePath.startsWith('assets/'));
  
  if (!mdFile) {
    alert('未找到content.md文件');
    return;
  }

  // 读取Markdown内容并修正图片路径
  const mdContent = await readFileAsText(mdFile);
  // 将assets/xxx.png替换为xxx.png,适配Obsidian同目录附件规则
  const adjustedMdContent = mdContent.replace(/!\[(.*?)\]\(assets\/(.*?)\)/g, '![$1]($2)');

  // 生成可下载的文件包
  const zip = new JSZip();
  zip.file('note.md', adjustedMdContent);
  // 添加图片到zip根目录
  for (const img of imageFiles) {
    const imgBlob = await readFileAsBlob(img);
    zip.file(img.name, imgBlob);
  }

  // 导出ZIP文件
  const zipBlob = await zip.generateAsync({ type: 'blob' });
  downloadBlob(zipBlob, 'obsidian-note.zip');
}

// 工具函数
function readFileAsText(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = reject;
    reader.readAsText(file);
  });
}

function readFileAsBlob(file: File): Promise<Blob> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(new Blob([reader.result as ArrayBuffer]));
    reader.onerror = reject;
    reader.readAsArrayBuffer(file);
  });
}

function downloadBlob(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}

2. 处理ZIP格式的TextPack上传

如果用户上传的是打包后的TextPack(ZIP文件),用JSZip解析:

// HTML部分
<input type="file" id="zipInput" accept=".zip,.textpack">
<button onclick="processTextPack()">处理并导出</button>

// TypeScript逻辑
async function processTextPack() {
  const input = document.getElementById('zipInput') as HTMLInputElement;
  const zipFile = input.files?.[0];
  if (!zipFile) return;

  const zip = await JSZip.loadAsync(zipFile);
  
  // 读取content.md
  const mdFile = zip.file('content.md');
  if (!mdFile) {
    alert('TextPack中未找到content.md');
    return;
  }
  let mdContent = await mdFile.async('text');
  
  // 提取assets下的图片
  const imageEntries = zip.folder('assets')?.files || {};
  const outputZip = new JSZip();
  outputZip.file('note.md', mdContent.replace(/!\[(.*?)\]\(assets\/(.*?)\)/g, '![$1]($2)'));

  // 复制图片到输出包
  for (const [path, file] of Object.entries(imageEntries)) {
    if (!file.dir) {
      const imgData = await file.async('blob');
      const imgName = path.split('/').pop() || '';
      outputZip.file(imgName, imgData);
    }
  }

  // 导出适配Obsidian的ZIP
  const outputBlob = await outputZip.generateAsync({ type: 'blob' });
  downloadBlob(outputBlob, 'obsidian-note.zip');
}

导入Obsidian的步骤

  1. 下载生成的obsidian-note.zip
  2. 在Obsidian中打开目标库,执行文件 > 导入
  3. 选择下载的ZIP文件,Obsidian会自动解析Markdown和图片,完成导入

注:如果你的Obsidian设置了单独的附件文件夹(如_attachments),可修改代码中将图片放入对应目录,并调整Markdown中的路径为![alt](_attachments/image.png)

内容的提问来源于stack exchange,提问作者Olivier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 02:20:53