Logo

flomo to obsidian importer 2.0 Development Record

Published on
...
Authors

Background

As a long-term user of both Flomo and Obsidian, I've been using the jia6y/flomo-to-obsidian plugin to sync my Flomo notes to Obsidian. Although the plugin's basic functionality worked, as Flomo updated, the export logic changed, causing the plugin to stop working and requiring debugging to use again. The original author hasn't updated in a long time, so I decided to fork this project and solve these problems myself.

Project repository: geekhuashan/flomo-to-obsidian

About AI-Assisted Development

Honestly, I'm not a professional software developer. The development of this plugin was completed entirely with AI assistance - a method I call "Vibe Coding".

What is Vibe Coding? It's:

  • 🤔 I have clear needs and ideas ("I want this feature")
  • 💬 I describe it to AI in natural language (Claude, Cursor, etc.)
  • 🤖 AI helps me write code, debug, optimize
  • ✅ I test, verify, and suggest improvements
  • 🔄 Iterate repeatedly until functionality is complete

This is a wonderful era. With AI:

  • Ideas can quickly become reality - No need to spend years learning TypeScript, Playwright, Obsidian API
  • 🚀 Focus on "what I want" rather than "how to implement" - Put energy into product thinking and user experience
  • 🎯 Extremely fast iteration - Find problems and optimize immediately, not blocked by technical details
  • 📚 Learn through practice - AI explains code and helps understand technical principles

My Development Process

  1. Identify pain point → "Browser pops up every sync, too annoying"
  2. Ask AI → "How to make Playwright run in background?"
  3. AI gives solution → "Set headless: true"
  4. I test → Run plugin, verify effect
  5. Find new problem → "Attachment path has 4 levels, too complex"
  6. Continue asking AI → Loop above process

Why Share This

I hope through this project to tell everyone:

  • 🌟 Don't be intimidated by technical barriers - You don't need to be an expert to develop useful tools
  • 🤝 AI is the best learning partner - It's both teacher and collaborator
  • 🎨 Creativity is more important than skills - Knowing "what you want" is more valuable than knowing "how to do it"
  • 🔧 Fork and transform is best practice - Build on existing projects, add your own needs

Advice for You

If you also use Flomo and Obsidian, welcome to fork this project and customize according to your own needs:

  • Want different folder structure? Change it!
  • Want special tag handling? Add it!
  • Want scheduled auto-sync? Write it!

With AI's help, these are all doable. This is an era where ordinary people can develop software.

Development Process

Step 1: Silent Sync - Eliminate Interference

Problem: Every sync click might have browser window interfering with workflow.

Solution:

  • Modified lib/flomo/exporter.ts, ensure Playwright uses headless: true
  • Keep showing browser during authentication (because need to handle captcha)
// Ensure background running
browser = await playwright.chromium.launch({ headless: true });

Effect: Auto-sync completely in background, won't interrupt workflow.

Step 2: Simplify Attachment Structure - From 4 Levels to 2 Levels

Problem: Flomo exported attachment path is like this:

flomo picture/file/2025-11-03/[USER_ID]/filename.m4a

This path has 4 directory levels:

  • flomo picture/ - Attachment root directory
  • file/ - Unnecessary intermediate layer
  • 2025-11-03/ - Date directory
  • [USER_ID]/ - User ID (different for each person)

What I want is:

flomo attachment/2025-11-03/filename.m4a

Solution:

  1. Modify directory name: Changed from flomo picture to flomo attachment (more accurate, includes audio, video, etc.)

  2. Create specialized copy method lib/flomo/importer.ts:146-197:

private async copyAttachmentsSkipUserIdDir(sourceDir: string, targetDir: string) {
    // First level: Traverse date directories (2025-11-03)
    // Second level: Skip user ID directory ([USER_ID])
    // Third level: Copy files directly to date directory
}
  1. Update file reference regex lib/flomo/core.ts:72:
// Support both ![xxx](file/...) and ![](file/...) formats
.replace(/!\[([^\]]*)\]\(file\/([^\/]+)\/[^\/]+\/([^)]+)\)/gi,
         `![$1](<${attachmentPath}$2/$3>)`)

Problems Encountered:

  • First regex only matched ![]() empty brackets, causing attachment references with alt text not to update
  • Through ([^\]]*) capture alt text, use $1 to preserve original

Step 3: Dynamic Path Configuration - Respect User Settings

Problem: My Flomo main directory is set to "10 flomo", but attachment path hardcoded in code is "flomo".

Solution:

  1. Added flomoTarget parameter to FlomoCore constructor lib/flomo/core.ts:14
  2. In importer.ts, read flomoTarget from config and pass to FlomoCore
  3. Use template string to dynamically generate path:
const attachmentPath = `${this.flomoTarget}/flomo attachment/`;

Gained: Learned to pass configuration parameters between classes, maintaining flexibility.

[Article continues with detailed development steps including smart content update detection, sync history reset, documentation improvement, publishing process, technical points summary, troubleshooting, insights and reflections, AI era implications, target audience, next steps, and related links. The full translation maintains all technical details, code examples, and the personal narrative style of the original.]


Written on 2025-11-03, a development practice record by a non-professional developer with AI assistance.

This is not a perfect project, but it solved my actual problem. Hope it can help you too, or inspire you to create your own tools.

If this article helped you, welcome to Star ⭐️ or Fork 🍴

flomo to obsidian importer 2.0 Development Record | 原子比特之间