# Managing Media Offline/Missing State and Relinking Workflows in Palmier Pro

> Master offline media management in Palmier Pro. Discover automatic detection, preview overlays, and efficient bulk relinking with the relinkOfflineAssets API.

- Repository: [Palmier/palmier-pro](https://github.com/palmier-io/palmier-pro)
- Tags: how-to-guide
- Published: 2026-07-27

---

**Palmier Pro tracks offline media through three distinct reference sets maintained in [`EditorViewModel.swift`](https://github.com/palmier-io/palmier-pro/blob/main/EditorViewModel.swift), providing automatic detection, real-time preview overlays, and bulk relinking capabilities via the `relinkOfflineAssets(fromFolder:)` API.**

Managing media offline/missing state and relinking workflows in Palmier Pro centers on a robust asset verification system that treats every imported file as a managed resource. The palmier-io/palmier-pro repository implements deterministic state tracking across the editor, preview, and export pipelines to ensure projects remain functional even when source files move or become corrupted. All offline state lives as a single source of truth in the view model, with dedicated resolution paths for both individual asset relinking and bulk folder reconciliation.

## Understanding Offline Media States

Palmier Pro categorizes problematic assets into three complementary sets stored in [`EditorViewModel.swift`](https://github.com/palmier-io/palmier-pro/blob/main/EditorViewModel.swift):

- **`offlineMediaRefs`**: Asset IDs whose source files cannot be found on disk or are inaccessible.
- **`unprocessableMediaRefs`**: Asset IDs whose files exist but cannot be decoded (e.g., unsupported codec).
- **`missingMediaRefs`**: Asset IDs referenced in a project but never scanned (used for lazy-loading).

These sets drive all downstream decisions in the preview renderer and export pipeline. When the app launches or the user opens the Media panel, `showMediaPanelMediaTab()` triggers `refreshMissingMediaCache()`, which walks the filesystem off the main thread to populate `offlineMediaRefs` and `unprocessableMediaRefs`.

## Real-Time Detection and Refresh Cycles

The editor registers an observer for `NSApplication.didBecomeActiveNotification` that automatically calls `refreshMissingMediaCache()` whenever Palmier Pro regains focus. This design ensures that external file system changes—such as a user moving assets in Finder while the app is backgrounded—are immediately reflected in the UI and any pending export jobs.

## Visual Feedback and Preview Handling

The preview system reads offline state directly from `EditorViewModel` and renders appropriate placeholders. In [`PreviewContainerView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/PreviewContainerView.swift), the `offlineOverlay(timelineState:)` helper extracts offline clips, while `offlinePreview(assetId:path:isUnprocessable:)` draws the semi-transparent overlay. When all offline references are cleared, the preview automatically recovers without requiring a manual refresh.

`CompositionBuilder` receives the complete set of offline references via `ctx.offlineMediaRefs` and omits those clips from the render graph. It also tags the builder’s context with `offlineMediaRefs` so downstream exporters can report missing assets accurately.

## Relinking Workflows and APIs

The relinking logic resides in `EditorViewModel+Relink.swift`, exposing two primary APIs for restoring broken references:

**Single Asset Relinking**

```swift
// Repoint a specific asset to a new URL and refresh its state
func relinkAsset(id: String, to newURL: URL)

```

**Bulk Folder Relinking**

```swift
// Recursively scan a folder, match filenames (case-insensitive) to offline assets,
// and rewire them in bulk. Returns (relinked, total) for UI feedback.
@discardableResult
func relinkOfflineAssets(fromFolder folder: URL) -> (relinked: Int, total: Int)

```

Both functions delegate to `applyRelink(id:to:)`, which performs five atomic operations:

1. Updates the asset’s `url` property.
2. Clears cached denoise results (`denoiseFailed`, `denoiseBaked`).
3. Invalidates the visual cache via `mediaVisualCache.invalidate(id)`.
4. Updates the manifest entry to keep the project file synchronized.
5. Triggers `finalizeImportedAsset` to re-run import-time analyses (e.g., speaker identification).

The bulk relink algorithm walks the target folder once to build a dictionary of lower-cased filename-to-URL mappings, then attempts to match each offline asset’s original filename. This guarantees **O(N)** complexity for the folder scan plus **O(M)** for the offline asset list, where *N* is the number of files in the folder and *M* is the number of offline assets.

## Export Pipeline Safety

`ExportService` and `ExportQueue` include offline media sets in their status reports. The queue adds `offlineMediaRefs.count + unprocessableMediaRefs.count` to its work-item validation, causing export jobs to fail early if required media is missing. The UI surfaces a concise "X media files are offline" toast, preventing wasted rendering time.

Graceful degradation ensures that when a manifest cannot be parsed, the project degrades to "media offline" rather than being lost entirely, as implemented in [`VideoProject.swift`](https://github.com/palmier-io/palmier-pro/blob/main/VideoProject.swift).

## Practical Code Examples

Relink a single clip selected in the Media panel:

```swift
let clipID = "a1b2c3"
let newLocation = URL(fileURLWithPath: "/Volumes/ExternalDrive/Clips/scene-01.mov")
editorViewModel.relinkAsset(id: clipID, to: newLocation)

```

Bulk-relink all offline clips by pointing to a folder containing the originals:

```swift
let folder = URL(fileURLWithPath: "/Users/me/Projects/Project-Assets")
let result = editorViewModel.relinkOfflineAssets(fromFolder: folder)
print("Re-linked \(result.relinked) of \(result.total) offline assets")

```

Force a refresh of offline status after external file moves:

```swift
editorViewModel.refreshMissingMediaCache()

```

Export while respecting offline media—the exporter automatically aborts if any required asset remains offline:

```swift
let exportOptions = ExportOptions(preset: .highQuality)
exportService.startExport(projectID: editorViewModel.projectId ?? "", options: exportOptions) { status in
    switch status {
    case .completed: print("Export succeeded")
    case .failed(let error): print("Export failed: \(error)")
    }
}

```

## Summary

- Palmier Pro maintains three distinct reference sets (`offlineMediaRefs`, `unprocessableMediaRefs`, `missingMediaRefs`) in [`EditorViewModel.swift`](https://github.com/palmier-io/palmier-pro/blob/main/EditorViewModel.swift) as the single source of truth for media state.
- Automatic detection occurs via `refreshMissingMediaCache()`, triggered on app activation and Media panel access.
- The preview pipeline in [`PreviewContainerView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/PreviewContainerView.swift) renders semi-transparent overlays for offline assets, while `CompositionBuilder` excludes them from the render graph.
- Relinking supports both single-asset updates (`relinkAsset`) and bulk reconciliation (`relinkOfflineAssets`) with deterministic O(N+M) performance.
- The export pipeline validates offline state before processing, failing early with clear user feedback when source files are unavailable.

## Frequently Asked Questions

### How does Palmier Pro detect when media goes offline?

Palmier Pro detects offline media by calling `refreshMissingMediaCache()` in [`EditorViewModel.swift`](https://github.com/palmier-io/palmier-pro/blob/main/EditorViewModel.swift), which runs off the main thread to verify file existence for all managed assets. This method populates `offlineMediaRefs` when files are missing and `unprocessableMediaRefs` when files exist but cannot be decoded. The system also listens for `NSApplication.didBecomeActiveNotification` to automatically refresh state when the app returns to the foreground.

### What is the difference between offline and unprocessable media in Palmier Pro?

**Offline media** refers to assets whose source files cannot be found at their recorded URLs, typically due to files being moved, renamed, or deleted. **Unprocessable media** refers to assets whose files exist on disk but cannot be decoded by the pipeline, such as those with unsupported codecs or corruption. These states are tracked separately in `offlineMediaRefs` and `unprocessableMediaRefs` to allow different UI treatments and relinking strategies.

### Can I relink multiple offline files at once in Palmier Pro?

Yes. The `relinkOfflineAssets(fromFolder:)` method in `EditorViewModel+Relink.swift` performs bulk relinking by scanning a folder recursively and matching filenames (case-insensitive) to offline asset references. This operation returns a tuple of `(relinked: Int, total: Int)` for UI feedback and operates with O(N+M) efficiency by indexing the folder contents before attempting matches.

### What happens if I try to export a project with offline media?

The export pipeline in `ExportService` and `ExportQueue` validates the `offlineMediaRefs` and `unprocessableMediaRefs` sets before rendering begins. If any required assets are offline, the export job fails immediately with a status report indicating the number of missing files. This prevents wasted processing time and allows the UI to display a "X media files are offline" toast directing the user to relink before retrying.