如何用TypeScript读取textbundle文件并导入Obsidian(浏览器端,无HTML)
浏览器端读取TextBundle并提取内容导入Obsidian的实现方案
TextBundle是遵循特定目录结构的资源包,核心包含content.md文本文件和assets/目录下的图片附件。以下是浏览器端用JavaScript/TypeScript实现读取、提取并适配Obsidian导入的步骤和代码:
核心处理逻辑
- 接收用户上传的TextBundle(支持文件夹或打包后的ZIP包)
- 解析包内结构,提取
content.md文本和所有图片文件 - 修正Markdown中的图片引用路径,适配Obsidian的相对路径规则
- 生成可直接导入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, ''); // 生成可下载的文件包 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, '')); // 复制图片到输出包 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的步骤
- 下载生成的
obsidian-note.zip - 在Obsidian中打开目标库,执行
文件 > 导入 - 选择下载的ZIP文件,Obsidian会自动解析Markdown和图片,完成导入
注:如果你的Obsidian设置了单独的附件文件夹(如
_attachments),可修改代码中将图片放入对应目录,并调整Markdown中的路径为
内容的提问来源于stack exchange,提问作者Olivier
相关产品推荐
相关产品推荐

