Last active
June 24, 2025 11:46
-
-
Save geosmart/2d47df6206bc9943da6590829badb599 to your computer and use it in GitHub Desktop.
我写了一个简单的 `QuickAdd` 脚本 `MyBrainImport.js`,用于将 `MyBrain` 导出的 JSON 文件转换成 Obsidian 的 Markdown 文件。只需将此脚本放在你的 Obsidian 脚本目录下,然后在 `QuickAdd` 中添加一个 Macro,选择这个脚本即可一键导入。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = async (params) => { | |
const { quickAddApi: { inputPrompt }, app } = params; | |
const adapter = app.vault.adapter; | |
// 配置常量 | |
const CONFIG = { | |
SOURCE_FOLDER: "未归档/MyBrain", | |
IMPORT_BASE: "未归档/已导入", | |
SUB_FOLDERS: { | |
NOTES: "notes", | |
DIARY: "diary" | |
}, | |
FILES: { | |
TASKS: "tasks.md", | |
BOOKMARKS: "bookmarks.md" | |
} | |
}; | |
// 工具函数 | |
const utils = { | |
// 格式化日期 | |
formatDate: (timestamp) => { | |
if (!timestamp) return ''; | |
const date = new Date(timestamp); | |
return date.toISOString(); | |
}, | |
// 确保目录存在 | |
ensureFolder: async (folderPath) => { | |
try { | |
const folder = app.vault.getAbstractFileByPath(folderPath); | |
if (!folder) { | |
await app.vault.createFolder(folderPath); | |
console.log(`Created folder: ${folderPath}`); | |
} | |
return true; | |
} catch (error) { | |
console.error(`Error ensuring folder ${folderPath}:`, error); | |
throw error; | |
} | |
}, | |
// 处理文件写入 | |
writeFile: async (filePath, content) => { | |
try { | |
await adapter.write(filePath, content); | |
console.log(`File written: ${filePath}`); | |
return true; | |
} catch (error) { | |
console.error(`Error writing file ${filePath}:`, error); | |
throw error; | |
} | |
}, | |
// 显示通知 | |
showNotice: (message, isError = false) => { | |
new Notice(message); | |
if (isError) { | |
console.error(message); | |
} else { | |
console.log(message); | |
} | |
} | |
}; | |
// 处理器函数 | |
const processors = { | |
// 处理笔记 | |
processNotes: async (notes, basePath) => { | |
if (!notes || notes.length === 0) return; | |
const notesFolder = `${basePath}/${CONFIG.SUB_FOLDERS.NOTES}`; | |
await utils.ensureFolder(notesFolder); | |
for (const note of notes) { | |
const fileName = `${notesFolder}/${note.title}.md`; | |
const frontmatter = `--- | |
created: ${utils.formatDate(note.createdDate)} | |
updated: ${utils.formatDate(note.updatedDate)} | |
--- | |
`; | |
const content = frontmatter + (note.content || ''); | |
try { | |
await utils.writeFile(fileName, content); | |
} catch (error) { | |
utils.showNotice(`Failed to create note: ${note.title}`, true); | |
} | |
} | |
}, | |
// 处理日记 | |
processDiary: async (diaryEntries, basePath) => { | |
if (!diaryEntries || diaryEntries.length === 0) return; | |
const diaryFolder = `${basePath}/${CONFIG.SUB_FOLDERS.DIARY}`; | |
await utils.ensureFolder(diaryFolder); | |
for (const entry of diaryEntries) { | |
const fileName = `${diaryFolder}/${entry.title}.md`; | |
const frontmatter = `--- | |
created: ${utils.formatDate(entry.createdDate)} | |
updated: ${utils.formatDate(entry.updatedDate)} | |
mood: ${entry.mood || ''} | |
--- | |
`; | |
const content = frontmatter + (entry.content || ''); | |
try { | |
await utils.writeFile(fileName, content); | |
} catch (error) { | |
utils.showNotice(`Failed to create diary entry: ${entry.title}`, true); | |
} | |
} | |
}, | |
// 处理任务 | |
processTasks: async (tasks, basePath) => { | |
if (!tasks || tasks.length === 0) return; | |
const fileName = `${basePath}/${CONFIG.FILES.TASKS}`; | |
let taskContent = '# 任务列表\n\n'; | |
for (const task of tasks) { | |
taskContent += `- #task ${task.title} ${task.description || ''} ➕ ${utils.formatDate(task.createdDate)} 📅 ${utils.formatDate(task.dueDate)}\n`; | |
} | |
try { | |
await utils.writeFile(fileName, taskContent); | |
} catch (error) { | |
utils.showNotice('Failed to process tasks', true); | |
} | |
}, | |
// 处理书签 | |
processBookmarks: async (bookmarks, basePath) => { | |
if (!bookmarks || bookmarks.length === 0) return; | |
const fileName = `${basePath}/${CONFIG.FILES.BOOKMARKS}`; | |
let bookmarkContent = '# 书签\n\n'; | |
for (const bookmark of bookmarks) { | |
bookmarkContent += `- [${bookmark.title}](${bookmark.url})\n`; | |
} | |
try { | |
await utils.writeFile(fileName, bookmarkContent); | |
} catch (error) { | |
utils.showNotice('Failed to process bookmarks', true); | |
} | |
} | |
}; | |
// 主执行函数 | |
const main = async () => { | |
try { | |
// 检查源文件夹 | |
const folder = app.vault.getAbstractFileByPath(CONFIG.SOURCE_FOLDER); | |
if (!folder || !folder.children) { | |
throw new Error(`Directory not found or inaccessible: ${CONFIG.SOURCE_FOLDER}`); | |
} | |
// 确保导入目录存在 | |
await utils.ensureFolder(CONFIG.IMPORT_BASE); | |
await utils.ensureFolder(`${CONFIG.IMPORT_BASE}/${CONFIG.SUB_FOLDERS.NOTES}`); | |
await utils.ensureFolder(`${CONFIG.IMPORT_BASE}/${CONFIG.SUB_FOLDERS.DIARY}`); | |
// 获取并排序JSON文件 | |
const jsonFiles = folder.children | |
.filter(file => file.extension === 'json') | |
.sort((a, b) => b.stat.mtime - a.stat.mtime); | |
if (jsonFiles.length === 0) { | |
throw new Error(`No JSON files found in ${CONFIG.SOURCE_FOLDER}`); | |
} | |
// 处理最新文件 | |
const latestJsonFile = jsonFiles[0]; | |
console.log(`Processing file: ${latestJsonFile.path}`); | |
const jsonContent = await app.vault.read(latestJsonFile); | |
const data = JSON.parse(jsonContent); | |
console.log('File content:', data); | |
// 处理各种数据类型 | |
await processors.processNotes(data.notes, CONFIG.IMPORT_BASE); | |
await processors.processDiary(data.diary, CONFIG.IMPORT_BASE); | |
await processors.processTasks(data.tasks, CONFIG.IMPORT_BASE); | |
await processors.processBookmarks(data.bookmarks, CONFIG.IMPORT_BASE); | |
utils.showNotice(`Successfully imported MyBrain data from: ${latestJsonFile.name}`); | |
} catch (error) { | |
utils.showNotice(`Import failed: ${error.message}`, true); | |
console.error('Import error:', error); | |
} | |
}; | |
// 执行主函数 | |
await main(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
大概逻辑如下: