Skip to content

Instantly share code, notes, and snippets.

@geosmart
Last active June 24, 2025 11:46
Show Gist options
  • Save geosmart/2d47df6206bc9943da6590829badb599 to your computer and use it in GitHub Desktop.
Save geosmart/2d47df6206bc9943da6590829badb599 to your computer and use it in GitHub Desktop.
我写了一个简单的 `QuickAdd` 脚本 `MyBrainImport.js`,用于将 `MyBrain` 导出的 JSON 文件转换成 Obsidian 的 Markdown 文件。只需将此脚本放在你的 Obsidian 脚本目录下,然后在 `QuickAdd` 中添加一个 Macro,选择这个脚本即可一键导入。
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();
};
@geosmart
Copy link
Author

大概逻辑如下:

开始
├─ 检查源目录MyBrain是否存在
├─ 获取最新 JSON 文件
├─ 创建目标目录已导入/notes, diary)
├─ 解析 JSON 数据
├─ 分发处理:
│  ├─ 笔记生成 notes/标题.md
│  ├─ 日记生成 diary/标题.md
│  ├─ 任务覆盖写入 tasks.md
│  └─ 书签覆盖写入 bookmarks.md
└─ 显示导入结果

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment