Pubcopy

by canartuc
5
4
3
2
1
Score: 51/100

Description

Obsidian Plugin for Medium and Substack Copy

Reviews

No reviews yet.

Stats

1
stars
361
downloads
0
forks
97
days
9
days
9
days
8
total PRs
0
open PRs
0
closed PRs
8
merged PRs
0
total issues
0
open issues
0
closed issues
40
commits

Latest Version

9 days ago

Changelog

Tells you to restart after an update, instead of silently copying nothing

Updating a plugin while Obsidian is running leaves the previous build partly alive. Menus and commands still register and the copy still reports success, but nothing reaches the clipboard. You paste and get whatever you copied last, which looks like a broken release rather than a stale process. Restarting Obsidian clears it.

Pubcopy now notices when its files changed underneath a running Obsidian and says so:

Pubcopy updated from 1.6.1 to 1.6.2. Restart Obsidian, or disable and re-enable the plugin, before copying. Until then copying may do nothing.

It appears once per update, not on every load.

What it deliberately does not do

No warning on a cold start. If you update with Obsidian closed, the new build is read fresh from disk and nothing is stale, so no notice appears. Telling you to restart the app you just opened would be wrong.

It cannot break the plugin. The check runs after everything else is registered and ignores its own failure to save. On a read-only vault, a full disk, or with a sync client holding the settings file open, you keep your commands, menus, and settings tab.

Nothing about conversion changed.

README file from

Github

Pubcopy

Tests License: MIT

Obsidian plugin that copies your notes as platform-optimized HTML to clipboard for pasting into Medium and Substack without formatting loss.

Install

Settings > Community plugins > Browse > Search "Pubcopy" > Install > Enable

Manual

  1. Download main.js, manifest.json, styles.css from the latest release
  2. Create folder: <your-vault>/.obsidian/plugins/pubcopy/
  3. Copy the 3 files into that folder
  4. Restart Obsidian
  5. Settings > Community plugins > Enable "Pubcopy"

Usage

Three ways to trigger:

Method Behavior
Command Palette (Cmd/Ctrl+P) > "Pubcopy" Copies entire note
Right-click in editor > Pubcopy submenu Copies selected text (or entire note if no selection)
Three-dot menu (top-right of note) > Pubcopy submenu Copies entire note

Each method offers three options:

  • Copy for Medium
  • Copy for Substack
  • Copy as Markdown — clean markdown (Obsidian syntax stripped), for anywhere else

After copying, paste (Cmd/Ctrl+V) into the target editor.

What gets converted

56 Obsidian markdown elements are handled:

Medium and Substack receive HTML. "Copy as Markdown" returns cleaned markdown instead, so the HTML-specific rows below do not apply to it.

Element Medium Substack
Bold, italic, strikethrough, inline code Yes Yes
Highlights ==text== Converted to bold Converted to bold
Headers H1-H4 Yes Yes
Headers H5-H6 Flattened to H4 Yes
Lists (ordered, unordered, nested) Max 2 levels Unlimited
Task lists - [ ] Unicode checkboxes Unicode checkboxes
Callouts > [!note] Styled blockquote with label Styled blockquote with label
Code blocks (with language) <pre><code> <pre>
Tables Bulleted list or code block (setting) HTML table (with alignment)
Images (local) Base64 embedded Base64 embedded
Images (remote URL) URL passthrough URL passthrough
Image captions Italic text below image <figcaption>
Footnotes Superscript + Notes section Native
Math (LaTeX) Rendered via KaTeX Rendered via KaTeX
Mermaid diagrams Stripped (not supported) Stripped (not supported)
Wikilinks, tags, comments, frontmatter Stripped Stripped
Embeds ![[note]] Resolved and inlined Resolved and inlined

Settings

Settings > Community plugins > Pubcopy > Settings

Setting Default Description
Strip frontmatter On Remove YAML frontmatter
Strip tags On Remove #tag references
Strip wikilinks On Convert [[links]] to plain text
Image handling Auto Auto: base64 for local, URL for remote
Table handling Bulleted list How tables are converted for Medium: bulleted list or monospace code block
Show notification On Display notice after copying

Privacy & permissions

The Obsidian community store shows a "Clipboard Access" label for Pubcopy. That label is a generic notice applied to any plugin that touches the clipboard. Here is exactly what Pubcopy does:

  • Writes only, never reads. Pubcopy calls navigator.clipboard.write() to place your converted note on the clipboard. It never reads the clipboard, so the label's "may expose content copied from outside Obsidian" warning does not apply. That warning concerns plugins that read clipboard contents.
  • Only your note is copied. The clipboard payload is built solely from the note (or selection) you choose to copy, as text/html plus a text/plain fallback.
  • Stays on your device. Pubcopy makes no network requests. Conversion, including math rendering and local image embedding, runs entirely on your machine. Remote image URLs are passed through untouched, never fetched.

Pubcopy is MIT-licensed open source. You don't have to take these claims on trust: the full source is in this repository, so anyone can read it and verify exactly what the plugin does.

Development

Prerequisites

  • Node.js 24+
  • npm

Setup

git clone https://github.com/canartuc/pubcopy.git
cd pubcopy
npm install

Build

# Development (watch mode, rebuilds on file change)
npm run dev

# Production build
npm run build

Test

# Run all tests
npm test

# Watch mode
npm run test:watch

Deploy to your vault

First run asks for your vault path and saves it to .deploy.json (gitignored):

npm run deploy
# > Obsidian vault path: /path/to/your/vault
# > Saved to .deploy.json
# > Deployed to .../plugins/pubcopy

Every subsequent run just builds and copies:

npm run deploy

After deploying, restart Obsidian or reload the plugin.

Project structure

src/
├── main.ts                    # Plugin entry, commands, menus
├── settings.ts                # Settings interface and tab
├── converter/
│   ├── index.ts               # Conversion pipeline orchestrator
│   ├── preprocessor.ts        # Strip frontmatter, tags, wikilinks, etc.
│   ├── html-converter.ts      # Markdown to HTML via remark/rehype
│   ├── image-handler.ts       # Local base64, remote URL, captions
│   ├── embed-resolver.ts      # Resolve ![[note]] embeds
│   ├── footnote-processor.ts  # Platform-specific footnotes
│   └── math-renderer.ts       # LaTeX via KaTeX
├── platforms/
│   ├── index.ts               # PlatformProfile interface
│   ├── medium.ts              # Medium-specific rules
│   └── substack.ts            # Substack-specific rules
├── clipboard/
│   └── writer.ts              # Clipboard API (text/html + text/plain)
└── utils/
    ├── errors.ts              # PubcopyError, WarningCollector
    └── notifications.ts       # Obsidian Notice wrappers

Release

Push a tag to trigger a GitHub Actions release:

# Update version in manifest.json and package.json first
git tag X.Y.Z
git push origin X.Y.Z

GitHub Actions runs tests, builds, and creates a release with main.js, manifest.json, and styles.css.

License

MIT