czhhbp55 downloadsCache remote attachments on demand. Downloads files only when you open a note, then serves the local copy instead of the network file while keeping your original links unchanged.
On-demand persistent cache for remote attachments (images, videos, audio, documents). Downloads files only when you open a note, then transparently serves the local copy instead of the network file while keeping your original links unchanged.
https://... URLs remain exactly as you wrote them; the plugin only swaps in the local file at render time..cache folder and stay there, so reopening a note is instant and works offline.https://...) in your notes stay untouched. Syncing only syncs the link text, never the actual files..cache folder (excluded from syncing, so they are never synced).Most similar plugins permanently rewrite the links in your notes (changing https://... to a local path). This plugin never modifies your note content — it only temporarily uses local files at render time, keeping the original network links intact. As a result:
Link extraction: When a note is opened, all network links are extracted from the Markdown content using regex, supporting Markdown images , Markdown links [text](url), HTML tags <img>/<audio>/<video>/<source>, and bare URLs.
Cache decision: Each link is checked against whether it should be cached — already cached, has a file extension, matches the whitelist/blacklist, and is within the size limit.
Download & dedup: Files are downloaded via requestUrl, deduplicated by content hash (identical content is stored only once), written to the .cache folder, and recorded in the cache index cache-index.json.
Render replacement: A Markdown post-processor combined with a global MutationObserver replaces the src of <img> and other tags from the network link to a local app:// resource path (getResourcePath) at render time, enabling offline display.
Cleanup: On startup, all notes are scanned and cache files no longer referenced by any note are deleted.
FileSystemAdapter.getResourcePath encodes the absolute file path directly into an app:// resource-proxy URL, which Obsidian's renderer resolves by reading the file from disk. It does not depend on the vault's file index, so a hidden directory such as .cache works fine. The default is therefore .cache.This plugin is available in the Obsidian community plugin store.
From the store (recommended):
Manual installation:
main.js and manifest.json from the latest release..obsidian/plugins/on-demand-cache/ in your vault.Cache on open: When you open a note containing remote attachments, the plugin automatically downloads them to the local cache. After that, the note can be read fully offline — the remote links resolve to the local cache instead of the network, so images and media display normally even with no internet connection.
⚠️ Important: Caching is triggered only when a note is opened. If you insert a new remote attachment while editing (for example, pasting a network image link), the plugin will not cache it immediately. You need to reopen the note (or switch to another note and back) for the plugin to detect and cache the newly inserted attachment. Until it is cached, that particular attachment still requires a network connection to display.
Configure in Obsidian Settings → Community plugins → On-Demand Cache (the UI language switches between English and Chinese automatically based on Obsidian's language):
| Setting | Description |
|---|---|
| Filter mode | Whitelist / Blacklist |
| File extensions | Comma-separated, e.g. png,jpg,mp4,pdf,docx |
| Max size | In MB, 0 means no limit |
| Cache folder | Default .cache |
| Auto-clean | Toggle |
| Use cache | Toggle |
| Diagnostic logging | Enable for troubleshooting, off by default |
Cache files are stored in the .cache folder. This folder should be excluded from syncing so the actual files are never uploaded:
.cache/ to your .gitignore..cache/ folder.Note: The cache folder may start with
.(a hidden directory). Becauseapp://resource paths are resolved directly from disk rather than through the vault index, hidden directories such as.cacheload images correctly.
[text](https://...)![[https://...]], [[https://...]], [[https://...|alias]]<img src="https://...">, <audio>, <video>, <source>https://...npm install
npm run build # build
npm run dev # dev mode (watch)