Releases: atbeta/picfast-obsidian-plugin
Release list
v0.2.3 — Settings copy polish
Copy fixes
Three settings-tab polish fixes, i18n-only (no code change):
-
Dropped backticks around
picfastin Base URL and API token descriptions. Obsidian's settings tab doesn't render markdown — the backticks were showing up as literal ` characters in the UI. -
zh-CN dropdown: first option was 'Off(使用 Obsidian 默认行为)'. The English word 'Off' was sneaking into the Chinese UI. Now '关闭(Obsidian 默认行为)'.
-
zh-CN Upload behavior description: changed 'Ask 会弹一个 1-click 小菜单让你选择' (casual translation) to 'Ask 模式每次都会弹出一个简短菜单供你选择' (more idiomatic).
v0.2.2 — Trim settings hint copy
Cleanup
Settings tab copy edits (i18n only, no code change):
- Base URL description trimmed from 3 sentences to 2. Dropped the platform-specific path
~/.config/picfast/config.json(which is wrong on Windows anyway — Windows uses%APPDATA%\picfast\config.json). Dropped the nested parenthesis '(thepicfastnpm CLI config)' qualifier. - API token description: same trim + cleaned up the 'Also auto-filled' phrasing.
Before
Your PicFast instance root, e.g. https://picfast.example.com.
Leave empty to auto-fill from the PICFAST_URL env var or
~/.config/picfast/config.json (the `picfast` npm CLI config).
After
Your PicFast instance root, e.g. https://picfast.example.com.
Leave empty to auto-fill from PICFAST_URL env var or `picfast` CLI config.
(Chinese version likewise.)
v0.2.1 — Fix Ctrl+P TypeError + right-click menu + command prefix
Fixes
1. Ctrl+P TypeError (and silent right-click menu disappearance)
TypeError: Cannot read properties of undefined (reading 'trim')
at P (plugin:picfast-image-uploader:13:2837)
at Object.editorCheckCallback (plugin:picfast-image-uploader:14:6492)
Root cause: the shared matchAll helper assumed both regexes had m[1] and m[2] capture groups. The wikilink regex /![[path]]/g only has m[1], so every wikilink hit came back with path: undefined.
That caused two visible symptoms:
- Ctrl+P TypeError:
editorCheckCallbackcalledisRemotePath(match.rawPath)→undefined.trim()crashed. Obsidian builds the command palette list by calling every command'seditorCheckCallback(checking=true)at startup, so the crash prevented the command from appearing. - Right-click menu missing: the
editor-menuworkspace handler also calledisRemotePathon the same bad rawPath. When it threw, the menu flow aborted beforemenu.addItemwas reached, so the item never appeared in the menu.
Fix: split into matchMarkdown() (uses m[1]=alt, m[2]=path) and matchWikilink() (uses m[1]=path, no alt). Also hardened isRemotePath to return false on undefined input.
2. Command names prefixed with PicFast:
PicFast: Upload image from clipboardPicFast: Upload selected image filePicFast: Upload image at cursor
(Chinese: PicFast: 从剪贴板上传图片 / PicFast: 上传选中的图片文件 / PicFast: 上传光标处的图片)
This makes them group together in the command palette and visually separates them from similar commands in other plugins.
Install
Same path: download the 3 files from this release and overwrite the v0.2.0 files in .obsidian/plugins/picfast-image-uploader/. Settings forward-compatible.
v0.2.0 — Upload image at cursor
New: upload image that's already in your note
Three ways to invoke:
-
Command palette —
PicFast: Upload image at cursor to PicFast. Only appears when the cursor sits inside a markdown / wikilink image reference that points at a local file. -
Right-click menu — the same command shows up in the editor context menu when the cursor is over an image link.
-
Existing paste / drop handlers (unchanged from v0.1.4).
Recognised link forms
— standard markdown![[local-path]]/![[path|300]]— Obsidian wikilink (size / alt suffixes stripped)http:///https:///data:URLs — skipped, the plugin tells you it's already remote
Path resolution:
- URL-decoded (
%20→ space etc.) - Strips leading
./and chains of../ - Falls back to trying
.png/.jpg/.jpeg/.gif/.webp/.svg/.bmp/.avifwhen the wikilink omitted the extension
Failure handling
Every failure path surfaces a Notice and leaves the markdown untouched:
- Already a remote URL → Notice "this image is already remote"
- Can't resolve path → Notice with the resolved path search list
- Can't read file (permission, vault race) → Notice
- Upload error → existing performUpload Notice
Replacement
Always  regardless of whether the original was a markdown link or wikilink. Obsidian renders both identically for remote URLs.
Install
Same path: overwrite the 3 files in .obsidian/plugins/picfast-image-uploader/. Settings are forward-compatible — no migration needed.
v0.1.4 — No more double insert, i18n complete
Fixes
1. Double-insert (paste/drop created 2 images)
Root cause: evt.preventDefault() was called inside a .then() callback. By then the event had already finished propagating and Obsidian's default handler had already inserted ![[attachment.png]]. Our async upload then finished and inserted  next to it — you got two images per paste.
Fix: handleEditorImage() now decides synchronously inside the capture-phase listener and calls preventDefault() + stopPropagation() immediately when it commits to handling the image. The upload stays async — that's fine, what matters is that the event is swallowed before it reaches Obsidian's own listener.
Side effect for ask mode: when the user picks Save locally, Obsidian no longer creates the attachment for us (we already swallowed the event). So we emulate it: app.fileManager.getAvailablePathForAttachment + app.vault.createBinary + insert ![[name]]. Upload / Cancel paths unchanged.
2. Settings i18n gaps
- Upload-behavior dropdown options were hard-coded English ("Off (Obsidian default)" / "Ask each time (recommended)" / "Always upload"). Now sourced from the i18n module.
- API token placeholder "optional" was hard-coded English. Now sourced.
- 4 new i18n keys (
settingUploadBehaviorOption{Off,Ask,On}+settingApiTokenPlaceholder) added to both en and zh-CN.
Install
Same path: download the 3 files from this release and overwrite the v0.1.3 files in .obsidian/plugins/picfast-image-uploader/. Settings.json is forward-compatible (no schema changes).
v0.1.3 — Fix 400 on upload + simpler settings
Fixes
1. 400 'fail to parse multipart form' (the actual blocker)
requestUrl({ body }) only accepts string | ArrayBuffer. The previous build cast a FormData instance to ArrayBuffer, which compiled fine but sent garbage to the server (no Content-Type: multipart/form-data; boundary=... header → server couldn't parse the body).
Replaced with a hand-rolled multipart body builder: pick a boundary, encode Content-Disposition + Content-Type + filename as a header, append the raw image bytes, append the closing boundary, send as a single ArrayBuffer with the right Content-Type header. Same pattern as babarot/obsidian-image-uploader-to-api.
2. Endpoint: /api/v1/upload → /api/v1/flat/upload
The flat handler is built for external upload tools (PicGo, uPic, Dropshare) and returns a simpler JSON shape {url, markdown, html, bbcode, thumbnail_url} (no links wrapper). Both accept multipart, but flat is cleaner here.
3. Settings UI
- Removed the Insert format dropdown — Obsidian is markdown-native, no one needs HTML / BBCode insertion.
- Removed the standalone 'Auto-discover picfast CLI config' info block. The auto-discovery hint is now folded into the Base URL and API token descriptions inline where users actually look.
Install
Same path, new files: download main.js, manifest.json, styles.css from this release and overwrite the v0.1.2 files in .obsidian/plugins/picfast-image-uploader/. No settings migration needed (defaultFormat field is gone, so an existing defaultFormat key in your settings.json is silently ignored).
v0.1.2 — Default export fix
Fix (real root cause this time)
v0.1.1 patched paste/drop interception but the actual crash was on plugin load, before any handler ran. The minified bundle was:
module.exports = { PicFastImageUploaderPlugin: class, __esModule: true }Obsidian 1.x's plugin loader does const cls = require('./main.js').default and then new cls(app) — but there was no default field. new undefined(...) throws TypeError: h is not a constructor (h is the minified variable holding the default slot).
Switched export class → export default class in src/main.ts. Bundle now has { default: ..., __esModule: true } and the loader is happy.
Install
Same as before — download main.js, manifest.json, styles.css from the release and drop them into .obsidian/plugins/picfast-image-uploader/ (overwrite the v0.1.0 / v0.1.1 files).
v0.1.1 — Fix plugin load failure
Fix
- Plugin load failed with "TypeError: h is not a constructor" on startup
- Cause:
workspace.on('editor-paste', ...)andworkspace.on('editor-drop', ...)are not valid Obsidian events (those are VSCode-style). The workspace falls through to a code path that requires a constructor we don't have. - Fix: switch to
registerDomEvent(document, 'paste' | 'drop', cb, true)withuseCapture=trueso we run before Obsidian's default handler. We bail when the target is outside a CodeMirror editor (.cm-content/.CodeMirror), so global paste for the search box and settings dialog is untouched.
Install
Same as v0.1.0 — drop main.js, manifest.json, styles.css from the release assets into your vault's .obsidian/plugins/picfast-image-uploader/. No settings migration needed (version bumped in manifest).
v0.1.0 — Initial scaffold
PicFast Image Uploader v0.1.0
First public release. Upload pasted or dropped images to your PicFast instance — no PicGo middleman.
Features
- 📋 Upload from clipboard via ribbon icon or Ctrl/Cmd+Shift+V
- 🖱️ Paste / drop handlers with configurable behaviour (Off / Ask each time / Always upload)
- 🪄 Auto-discovers
~/.config/picfast/config.jsonandPICFAST_URL/PICFAST_TOKENenv vars - 🌐 No CORS pain — uses Obsidian's
requestUrl - 🌏 English + Simplified Chinese
Install
- BRAT (recommended for now): BRAT settings → Add Beta plugin → paste
atbeta/picfast-obsidian-plugin - Manual: download
main.js,manifest.json,styles.cssbelow and drop into.obsidian/plugins/picfast-image-uploader/
Notes
- This is a pre-release build for internal testing. PicFast Community Plugins submission pending.
- Non-image drops (PDF, etc.) fall through to Obsidian default behaviour.
- Image compression / format conversion are server-side; the plugin does not expose them.