Managing Media Import and Indexing with Progress Tracking in Palmier Pro

Palmier Pro handles media import as a multi-stage, undo-aware pipeline that runs off the main actor, updates a project-wide manifest, and feeds a per-project search index with real-time progress tracking.

According to the palmier-io/palmier-pro source code, the entire flow is isolated from the main actor to preserve UI responsiveness, and every stage—from Finder drop to search index—is observable and reversible. Understanding how the EditorViewModel, MediaImportScanner, and SearchIndexCoordinator interact is essential for customizing imports or debugging ingestion workflows.

The Media Import and Indexing Pipeline in Palmier Pro

The import system spans four logical layers: user entry, scanning, plan application, and finalization. Each layer is implemented in dedicated source files under the Sources/PalmierPro/ directory and communicates through explicit async boundaries that comply with the project’s strict concurrency guidelines.

User Entry Points

Imports begin in the media panel UI. Tapping the Import Media button in Sources/PalmierPro/MediaPanel/MediaTab/MediaTab.swift at line 298 triggers the pipeline. Alternatively, dragging files from Finder into the media panel is handled by Sources/PalmierPro/MediaPanel/MediaTab/MediaTab+Drag.swift at line 144. Both paths converge on the same async method:

await editor.importFinderItems(
    urls,
    into: mediaPanelCurrentFolderId,
    finalize: true
)

Scanning and Building the Import Plan

Before any asset is written, MediaImportScanner.scan(roots:) in Sources/PalmierPro/Editor/ViewModel/EditorViewModel+MediaLibrary.swift (lines 57-84) evaluates the incoming URLs. It returns a MediaImportPlan that catalogs valid folders, files, and rejected items such as unsupported types or non-Lottie files. This stage runs inside a Task.detached(priority: .userInitiated) to avoid blocking the main thread.

Applying the Import Plan with Undo Support

The applyMediaImportPlan(_:restoringFrom:finalize:) method in EditorViewModel+MediaLibrary.swift (lines 11-68) executes the plan. It creates the folder hierarchy, appends MediaAsset objects to the editor’s mediaAssets array, updates the mediaManifest, and registers a single undo step. Because the undo action captures the pre-import state, an entire batch can be rolled back with one command. If finalize is true, the method also invokes finalizeImportedAsset for each accepted asset.

Finalization and Search Indexing

finalizeImportedAsset(_:batchManifestUpdate:) at lines 99-143 performs heavy lifting: loading metadata, generating thumbnails and waveforms via prepareMediaVisuals, updating the manifest, and enqueueing the asset in the SearchIndexCoordinator. The coordinator, defined in Sources/PalmierPro/Search/SearchIndexCoordinator.swift (lines 3-55), maintains an indexingActive flag, an indexingProgress value, and a queue of assets awaiting re-indexing.

Progress Tracking for Media Import and Indexing

Both the import and indexing stages expose observable state so the UI can display accurate feedback without polling the filesystem.

Import Progress and UI Feedback

While MediaImportScanner runs on its detached task, the media panel presents a busy spinner. Once applyMediaImportPlan completes, warning toasts—for example, unsupported file alerts surfaced at lines 46-50—are delivered through mediaPanelToast. The pipeline respects cancellation via Task.checkCancellation at each async boundary.

Indexing Progress Monitoring

SearchIndexCoordinator.indexingProgress is a Double calculated as batchCompleted / batchTotal. The Settings interface in Sources/PalmierPro/Settings/StoragePane.swift (lines 60-89) binds to this property to render a progress bar, and it displays the current disk usage via indexBytes. Users can reset the index entirely by triggering the Clear index button, which calls:

await SearchIndexCoordinator.shared.clearIndex()

Programmatic Control Over Media Import and Indexing

Developers can drive the pipeline outside the standard UI. The following examples reproduce the internal flow for batch scripts or custom integrations.

Importing Finder Items from a Drag-and-Drop

// Inside a view-model method
await editor.importFinderItems(
    urls,                     // URLs dragged from Finder
    into: mediaPanelCurrentFolderId,
    finalize: true
)

Running a Custom Import Plan

let roots = [MediaImportScanner.Root(url: sourceURL, parentFolderId: nil)]
let plan  = MediaImportScanner.scan(roots: roots)

// Apply without UI interaction
let summary = editor.applyMediaImportPlan(
    plan,
    restoringFrom: editor.mediaLibraryUndoSnapshot(),
    finalize: true
)

Clearing the Search Index

// Called from Settings → “Clear index”
await SearchIndexCoordinator.shared.clearIndex()

Key Source Files

Summary

  • Palmier Pro uses a four-stage pipeline—entry, scan, apply, finalize—to ingest media off the main actor and keep the UI responsive.
  • MediaImportScanner.scan(roots:) builds a deterministic MediaImportPlan that separates accepted files from rejected items before any disk mutation occurs.
  • applyMediaImportPlan(_:restoringFrom:finalize:) provides atomic undo support by registering a single undo step that reverses the entire batch.
  • finalizeImportedAsset(_:batchManifestUpdate:) generates visuals and enqueues assets into the SearchIndexCoordinator.
  • SearchIndexCoordinator exposes indexingProgress and indexingActive to drive UI progress bars, and its state can be reset via clearIndex().

Frequently Asked Questions

How does Palmier Pro keep the UI responsive during large media imports?

All scanning work runs in a Task.detached(priority: .userInitiated) inside MediaImportScanner.scan(roots:). The actual plan application and finalization also occur off the main actor, so the interface remains fluid even while processing hundreds of files.

Can an entire import batch be undone?

Yes. applyMediaImportPlan(_:restoringFrom:finalize:) in EditorViewModel+MediaLibrary.swift registers a single undo step that captures the pre-import mediaLibraryUndoSnapshot(). Invoking undo reverts the folder hierarchy, mediaAssets array, and mediaManifest in one action.

What happens to unsupported files dropped into the media panel?

The scanner filters them out during the planning phase and records them as rejected items. After the plan is applied, the UI surfaces warnings—such as unsupported type alerts—through the mediaPanelToast mechanism between lines 46-50 of the editor extension.

How is search indexing progress calculated?

SearchIndexCoordinator derives indexingProgress as the ratio of batchCompleted to batchTotal. Settings views like StoragePane.swift observe this Double alongside the indexingActive flag to render a live progress bar and report indexBytes consumed on disk.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →