feat(media): images and recordings in backups, exports and imports (M6)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m52s

- Backup ZIP (download and automatic per-user server backups) carries the
  files of the user's own notes as media/<id><ext>; restoring creates
  them with new IDs and rewrites the blocks.
- Markdown archive puts them under attachments/ and embeds them relative
  to each note (![caption](../attachments/…)); re-importing turns them
  back into image/audio blocks.
- Obsidian import takes images and audio a note embeds on its own
  (![[file.png]], ![](path/file.png)); unused or invalid files appear as
  skipped in the preview instead of vanishing.
- Format detection and file paths moved into storage for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 23:41:26 +01:00
1 parent 3f2bc96732
commit 1f63e08a73
13 files changed
+608 -82

No files matched your search

+5
View File
@@ -19,6 +19,8 @@ import (
type Store struct {
db *sql.DB
initMu sync.Mutex
// mediaRoot holds the files of images and audio in notes ($DATA_DIR/media), see media.go
mediaRoot string
// OnTaskCreated is told about tasks the store creates by itself (next occurrence of a repeating
// task), so the server can push them to connected clients.
@@ -50,6 +52,9 @@ func NewStore(dbPath string) (*Store, error) {
db.SetMaxIdleConns(4)
store := &Store{db: db}
if dbPath != ":memory:" && !strings.HasPrefix(dbPath, "file:") {
store.mediaRoot = filepath.Join(filepath.Dir(dbPath), "media")
}
if err := store.migrate(); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}