crier 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crier-0.2.0/.github/workflows/docs.yml +30 -0
- crier-0.2.0/.github/workflows/publish.yml +90 -0
- crier-0.2.0/.gitignore +47 -0
- crier-0.2.0/CLAUDE.md +85 -0
- crier-0.2.0/PKG-INFO +227 -0
- crier-0.2.0/README.md +194 -0
- crier-0.2.0/docs/getting-started.md +107 -0
- crier-0.2.0/docs/guides/backfill.md +125 -0
- crier-0.2.0/docs/guides/configuration.md +122 -0
- crier-0.2.0/docs/guides/github-action.md +235 -0
- crier-0.2.0/docs/guides/tracking.md +82 -0
- crier-0.2.0/docs/index.md +65 -0
- crier-0.2.0/docs/platforms/bluesky.md +53 -0
- crier-0.2.0/docs/platforms/buttondown.md +16 -0
- crier-0.2.0/docs/platforms/devto.md +51 -0
- crier-0.2.0/docs/platforms/discord.md +16 -0
- crier-0.2.0/docs/platforms/ghost.md +16 -0
- crier-0.2.0/docs/platforms/hashnode.md +16 -0
- crier-0.2.0/docs/platforms/index.md +76 -0
- crier-0.2.0/docs/platforms/linkedin.md +16 -0
- crier-0.2.0/docs/platforms/mastodon.md +16 -0
- crier-0.2.0/docs/platforms/medium.md +16 -0
- crier-0.2.0/docs/platforms/telegram.md +16 -0
- crier-0.2.0/docs/platforms/threads.md +16 -0
- crier-0.2.0/docs/platforms/twitter.md +16 -0
- crier-0.2.0/docs/platforms/wordpress.md +16 -0
- crier-0.2.0/docs/reference/cli.md +336 -0
- crier-0.2.0/docs/reference/front-matter.md +110 -0
- crier-0.2.0/mkdocs.yml +55 -0
- crier-0.2.0/pyproject.toml +60 -0
- crier-0.2.0/src/crier/__init__.py +3 -0
- crier-0.2.0/src/crier/cli.py +1078 -0
- crier-0.2.0/src/crier/config.py +114 -0
- crier-0.2.0/src/crier/converters/__init__.py +5 -0
- crier-0.2.0/src/crier/converters/markdown.py +70 -0
- crier-0.2.0/src/crier/platforms/__init__.py +63 -0
- crier-0.2.0/src/crier/platforms/base.py +65 -0
- crier-0.2.0/src/crier/platforms/bluesky.py +196 -0
- crier-0.2.0/src/crier/platforms/buttondown.py +136 -0
- crier-0.2.0/src/crier/platforms/devto.py +130 -0
- crier-0.2.0/src/crier/platforms/discord.py +140 -0
- crier-0.2.0/src/crier/platforms/ghost.py +205 -0
- crier-0.2.0/src/crier/platforms/hashnode.py +245 -0
- crier-0.2.0/src/crier/platforms/linkedin.py +161 -0
- crier-0.2.0/src/crier/platforms/mastodon.py +173 -0
- crier-0.2.0/src/crier/platforms/medium.py +104 -0
- crier-0.2.0/src/crier/platforms/telegram.py +166 -0
- crier-0.2.0/src/crier/platforms/threads.py +175 -0
- crier-0.2.0/src/crier/platforms/twitter.py +97 -0
- crier-0.2.0/src/crier/platforms/wordpress.py +186 -0
- crier-0.2.0/src/crier/registry.py +219 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Deploy Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
paths:
|
|
7
|
+
- 'docs/**'
|
|
8
|
+
- 'mkdocs.yml'
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
deploy:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.12'
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: |
|
|
27
|
+
pip install mkdocs-material
|
|
28
|
+
|
|
29
|
+
- name: Deploy to GitHub Pages
|
|
30
|
+
run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Crier Auto-Publish Workflow
|
|
2
|
+
#
|
|
3
|
+
# Copy this to your content repo at .github/workflows/crier-publish.yml
|
|
4
|
+
# Then set up the required secrets in your repo settings.
|
|
5
|
+
#
|
|
6
|
+
# Required secrets (set in GitHub repo Settings > Secrets):
|
|
7
|
+
# CRIER_DEVTO_API_KEY - Your dev.to API key
|
|
8
|
+
# CRIER_BLUESKY_API_KEY - handle.bsky.social:app-password
|
|
9
|
+
# CRIER_MASTODON_API_KEY - instance.social:access-token
|
|
10
|
+
# (add others as needed)
|
|
11
|
+
|
|
12
|
+
name: Auto-Publish Content
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [main, master]
|
|
17
|
+
paths:
|
|
18
|
+
- 'posts/**/*.md'
|
|
19
|
+
- 'content/**/*.md'
|
|
20
|
+
workflow_dispatch: # Allow manual trigger
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
publish:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout repository
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0 # Full history for registry
|
|
31
|
+
|
|
32
|
+
- name: Set up Python
|
|
33
|
+
uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: '3.12'
|
|
36
|
+
|
|
37
|
+
- name: Install Crier
|
|
38
|
+
run: pip install crier
|
|
39
|
+
|
|
40
|
+
- name: Configure platforms
|
|
41
|
+
env:
|
|
42
|
+
CRIER_DEVTO_API_KEY: ${{ secrets.CRIER_DEVTO_API_KEY }}
|
|
43
|
+
CRIER_BLUESKY_API_KEY: ${{ secrets.CRIER_BLUESKY_API_KEY }}
|
|
44
|
+
CRIER_MASTODON_API_KEY: ${{ secrets.CRIER_MASTODON_API_KEY }}
|
|
45
|
+
CRIER_HASHNODE_API_KEY: ${{ secrets.CRIER_HASHNODE_API_KEY }}
|
|
46
|
+
run: |
|
|
47
|
+
echo "Configured platforms:"
|
|
48
|
+
crier platforms
|
|
49
|
+
|
|
50
|
+
- name: Audit content
|
|
51
|
+
env:
|
|
52
|
+
CRIER_DEVTO_API_KEY: ${{ secrets.CRIER_DEVTO_API_KEY }}
|
|
53
|
+
CRIER_BLUESKY_API_KEY: ${{ secrets.CRIER_BLUESKY_API_KEY }}
|
|
54
|
+
CRIER_MASTODON_API_KEY: ${{ secrets.CRIER_MASTODON_API_KEY }}
|
|
55
|
+
CRIER_HASHNODE_API_KEY: ${{ secrets.CRIER_HASHNODE_API_KEY }}
|
|
56
|
+
run: |
|
|
57
|
+
# Audit posts directory (adjust path as needed)
|
|
58
|
+
if [ -d "posts" ]; then
|
|
59
|
+
crier audit ./posts || true
|
|
60
|
+
elif [ -d "content" ]; then
|
|
61
|
+
crier audit ./content || true
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
- name: Publish missing content
|
|
65
|
+
env:
|
|
66
|
+
CRIER_DEVTO_API_KEY: ${{ secrets.CRIER_DEVTO_API_KEY }}
|
|
67
|
+
CRIER_BLUESKY_API_KEY: ${{ secrets.CRIER_BLUESKY_API_KEY }}
|
|
68
|
+
CRIER_MASTODON_API_KEY: ${{ secrets.CRIER_MASTODON_API_KEY }}
|
|
69
|
+
CRIER_HASHNODE_API_KEY: ${{ secrets.CRIER_HASHNODE_API_KEY }}
|
|
70
|
+
run: |
|
|
71
|
+
# Backfill any missing publications
|
|
72
|
+
if [ -d "posts" ]; then
|
|
73
|
+
crier backfill ./posts --yes || true
|
|
74
|
+
elif [ -d "content" ]; then
|
|
75
|
+
crier backfill ./content --yes || true
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
- name: Commit registry updates
|
|
79
|
+
run: |
|
|
80
|
+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
81
|
+
git config --local user.name "github-actions[bot]"
|
|
82
|
+
|
|
83
|
+
# Add registry if it exists
|
|
84
|
+
if [ -d ".crier" ]; then
|
|
85
|
+
git add .crier/
|
|
86
|
+
git diff --staged --quiet || git commit -m "Update crier publication registry
|
|
87
|
+
|
|
88
|
+
🤖 Auto-updated by Crier GitHub Action"
|
|
89
|
+
git push
|
|
90
|
+
fi
|
crier-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
.venv/
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
|
|
35
|
+
# Testing
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.coverage
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
|
|
42
|
+
# Distribution
|
|
43
|
+
*.tar.gz
|
|
44
|
+
*.whl
|
|
45
|
+
|
|
46
|
+
# Local config (contains API keys)
|
|
47
|
+
config.yaml
|
crier-0.2.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Crier is a CLI tool for cross-posting content to multiple platforms. It reads markdown files with YAML front matter and publishes them via platform APIs. Designed to be used with Claude Code for automated content distribution.
|
|
8
|
+
|
|
9
|
+
## Development Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install in development mode with dev dependencies
|
|
13
|
+
pip install -e ".[dev]"
|
|
14
|
+
|
|
15
|
+
# Run tests
|
|
16
|
+
pytest
|
|
17
|
+
|
|
18
|
+
# Run tests with coverage
|
|
19
|
+
pytest --cov=crier
|
|
20
|
+
|
|
21
|
+
# Run a single test
|
|
22
|
+
pytest tests/test_file.py::test_function -v
|
|
23
|
+
|
|
24
|
+
# Lint
|
|
25
|
+
ruff check src/
|
|
26
|
+
|
|
27
|
+
# Format check
|
|
28
|
+
ruff format --check src/
|
|
29
|
+
|
|
30
|
+
# Build and serve docs locally
|
|
31
|
+
mkdocs serve
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Architecture
|
|
35
|
+
|
|
36
|
+
**CLI Layer** (`cli.py`): Click-based commands that orchestrate the workflow:
|
|
37
|
+
- `publish` — Publish to platforms (supports `--dry-run`, `--profile`)
|
|
38
|
+
- `status` — Show publication status for files
|
|
39
|
+
- `audit` — Check what's missing from platforms
|
|
40
|
+
- `backfill` — Publish missing content
|
|
41
|
+
- `doctor` — Validate API keys
|
|
42
|
+
- `config` — Manage API keys and profiles
|
|
43
|
+
|
|
44
|
+
**Platform Abstraction** (`platforms/`):
|
|
45
|
+
- `base.py`: Abstract `Platform` class defining the interface (`publish`, `update`, `list_articles`, `get_article`, `delete`) and core data classes (`Article`, `PublishResult`)
|
|
46
|
+
- Each platform implements the `Platform` interface
|
|
47
|
+
- `PLATFORMS` registry in `__init__.py` maps platform names to classes
|
|
48
|
+
|
|
49
|
+
**Platform Categories** (13 total):
|
|
50
|
+
- Blog: devto, hashnode, medium, ghost, wordpress
|
|
51
|
+
- Newsletter: buttondown
|
|
52
|
+
- Social: bluesky, mastodon, linkedin, threads, twitter (copy-paste mode)
|
|
53
|
+
- Announcement: telegram, discord
|
|
54
|
+
|
|
55
|
+
**Config** (`config.py`): API keys and profiles stored in `~/.config/crier/config.yaml` or via `CRIER_{PLATFORM}_API_KEY` environment variables. Environment variables take precedence. Supports composable profiles.
|
|
56
|
+
|
|
57
|
+
**Registry** (`registry.py`): Tracks publications in `.crier/registry.yaml`. Records what's been published where, enables status checks, audit, and backfill.
|
|
58
|
+
|
|
59
|
+
**Converters** (`converters/markdown.py`): Parses markdown files with YAML front matter into `Article` objects.
|
|
60
|
+
|
|
61
|
+
## Key Features
|
|
62
|
+
|
|
63
|
+
- **Dry run mode**: Preview before publishing with `--dry-run`
|
|
64
|
+
- **Publishing profiles**: Group platforms (e.g., `--profile blogs`)
|
|
65
|
+
- **Publication tracking**: Registry tracks what's published where
|
|
66
|
+
- **Audit & backfill**: Find and publish missing content
|
|
67
|
+
- **Doctor**: Validate all API keys work
|
|
68
|
+
|
|
69
|
+
## Adding a New Platform
|
|
70
|
+
|
|
71
|
+
1. Create `platforms/newplatform.py` implementing the `Platform` abstract class
|
|
72
|
+
2. Register in `platforms/__init__.py` by adding to `PLATFORMS` dict
|
|
73
|
+
3. Add documentation in `docs/platforms/newplatform.md`
|
|
74
|
+
4. Update README.md with API key format
|
|
75
|
+
|
|
76
|
+
## Documentation
|
|
77
|
+
|
|
78
|
+
Documentation is in `docs/` using MkDocs with Material theme. Deployed to GitHub Pages via `.github/workflows/docs.yml`.
|
|
79
|
+
|
|
80
|
+
## Testing Notes
|
|
81
|
+
|
|
82
|
+
Tests directory exists but is currently empty. When adding tests:
|
|
83
|
+
- Use pytest fixtures for mocking API responses
|
|
84
|
+
- Test both success and failure paths for platform operations
|
|
85
|
+
- Mock `requests` calls rather than hitting real APIs
|
crier-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crier
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Cross-post your content to dev.to, Hashnode, Medium, and more
|
|
5
|
+
Project-URL: Homepage, https://github.com/queelius/crier
|
|
6
|
+
Project-URL: Repository, https://github.com/queelius/crier
|
|
7
|
+
Project-URL: Issues, https://github.com/queelius/crier/issues
|
|
8
|
+
Author-email: Alex Towell <lex@metafunctor.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: blogging,content,cross-posting,devto,hashnode,medium
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Internet
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: click>=8.0
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: requests>=2.28
|
|
26
|
+
Requires-Dist: rich>=13.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mkdocs-material>=9.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Crier
|
|
35
|
+
|
|
36
|
+
Cross-post your content to dev.to, Ghost, WordPress, Hashnode, Medium, Bluesky, Mastodon, Threads, Telegram, Discord, and more.
|
|
37
|
+
|
|
38
|
+
Like a town crier announcing your content to the world.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install crier
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Configure your API keys
|
|
50
|
+
crier config set devto.api_key YOUR_API_KEY
|
|
51
|
+
crier config set bluesky.api_key "handle.bsky.social:app-password"
|
|
52
|
+
crier config set mastodon.api_key "mastodon.social:access-token"
|
|
53
|
+
|
|
54
|
+
# Publish a markdown file
|
|
55
|
+
crier publish post.md --to devto
|
|
56
|
+
|
|
57
|
+
# Publish to multiple platforms at once
|
|
58
|
+
crier publish post.md --to devto --to bluesky --to mastodon
|
|
59
|
+
|
|
60
|
+
# List your articles
|
|
61
|
+
crier list devto
|
|
62
|
+
|
|
63
|
+
# Update an existing article
|
|
64
|
+
crier update devto 12345 --file updated-post.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Supported Platforms
|
|
68
|
+
|
|
69
|
+
| Platform | API Key Format | Notes |
|
|
70
|
+
|----------|---------------|-------|
|
|
71
|
+
| **dev.to** | `api_key` | Full article support |
|
|
72
|
+
| **Hashnode** | `token` or `token:publication_id` | Full article support |
|
|
73
|
+
| **Medium** | `integration_token` | Publish only (no edit/list) |
|
|
74
|
+
| **Ghost** | `https://site.com:key_id:key_secret` | Full article support |
|
|
75
|
+
| **WordPress** | `site.wordpress.com:token` or `https://site.com:user:app_pass` | Full article support |
|
|
76
|
+
| **Buttondown** | `api_key` | Newsletter publishing |
|
|
77
|
+
| **Bluesky** | `handle:app_password` | Short posts with link cards |
|
|
78
|
+
| **Mastodon** | `instance:access_token` | Toots with hashtags |
|
|
79
|
+
| **Threads** | `user_id:access_token` | Short posts (no edit support) |
|
|
80
|
+
| **Telegram** | `bot_token:chat_id` | Channel/group posts |
|
|
81
|
+
| **Discord** | `webhook_url` | Server announcements |
|
|
82
|
+
| **LinkedIn** | `access_token` | Requires API access |
|
|
83
|
+
| **Twitter/X** | `any` (copy-paste mode) | Generates tweet for manual posting |
|
|
84
|
+
|
|
85
|
+
### Platform Notes
|
|
86
|
+
|
|
87
|
+
**Blog Platforms** (dev.to, Hashnode, Medium, Ghost, WordPress):
|
|
88
|
+
- Full markdown article publishing
|
|
89
|
+
- Preserves front matter (title, description, tags, canonical_url)
|
|
90
|
+
- Best for long-form content
|
|
91
|
+
|
|
92
|
+
**Newsletter Platforms** (Buttondown):
|
|
93
|
+
- Publishes to email subscribers
|
|
94
|
+
- Full markdown support
|
|
95
|
+
- Great for content repurposing
|
|
96
|
+
|
|
97
|
+
**Social Platforms** (Bluesky, Mastodon, LinkedIn, Twitter, Threads):
|
|
98
|
+
- Creates short posts with link to canonical URL
|
|
99
|
+
- Uses title + description + hashtags from tags
|
|
100
|
+
- Best for announcing new content
|
|
101
|
+
|
|
102
|
+
**Announcement Channels** (Telegram, Discord):
|
|
103
|
+
- Posts to channels/servers
|
|
104
|
+
- Good for community announcements
|
|
105
|
+
- Discord uses webhook embeds
|
|
106
|
+
|
|
107
|
+
## Configuration
|
|
108
|
+
|
|
109
|
+
API keys can be set via:
|
|
110
|
+
|
|
111
|
+
1. **Config file** (`~/.config/crier/config.yaml`):
|
|
112
|
+
```yaml
|
|
113
|
+
platforms:
|
|
114
|
+
devto:
|
|
115
|
+
api_key: your_key_here
|
|
116
|
+
bluesky:
|
|
117
|
+
api_key: "handle.bsky.social:app-password"
|
|
118
|
+
mastodon:
|
|
119
|
+
api_key: "mastodon.social:access-token"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
2. **Environment variables**:
|
|
123
|
+
```bash
|
|
124
|
+
export CRIER_DEVTO_API_KEY=your_key_here
|
|
125
|
+
export CRIER_BLUESKY_API_KEY="handle.bsky.social:app-password"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Markdown Format
|
|
129
|
+
|
|
130
|
+
Crier reads standard markdown with YAML front matter:
|
|
131
|
+
|
|
132
|
+
```markdown
|
|
133
|
+
---
|
|
134
|
+
title: "My Amazing Post"
|
|
135
|
+
description: "A brief description"
|
|
136
|
+
tags: [python, programming]
|
|
137
|
+
canonical_url: https://myblog.com/my-post
|
|
138
|
+
published: true
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
Your content here...
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Commands
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
crier publish FILE [--to PLATFORM]... # Publish to platform(s)
|
|
148
|
+
crier update PLATFORM ID --file FILE # Update existing article
|
|
149
|
+
crier list PLATFORM # List your articles
|
|
150
|
+
crier config set KEY VALUE # Set configuration
|
|
151
|
+
crier config show # Show configuration
|
|
152
|
+
crier platforms # List available platforms
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Getting API Keys
|
|
156
|
+
|
|
157
|
+
### dev.to
|
|
158
|
+
1. Go to https://dev.to/settings/extensions
|
|
159
|
+
2. Generate API key
|
|
160
|
+
|
|
161
|
+
### Hashnode
|
|
162
|
+
1. Go to https://hashnode.com/settings/developer
|
|
163
|
+
2. Generate Personal Access Token
|
|
164
|
+
|
|
165
|
+
### Medium
|
|
166
|
+
1. Go to https://medium.com/me/settings/security
|
|
167
|
+
2. Generate Integration Token
|
|
168
|
+
|
|
169
|
+
### Bluesky
|
|
170
|
+
1. Go to Settings → App Passwords
|
|
171
|
+
2. Create an app password
|
|
172
|
+
3. Use format: `yourhandle.bsky.social:xxxx-xxxx-xxxx-xxxx`
|
|
173
|
+
|
|
174
|
+
### Mastodon
|
|
175
|
+
1. Go to Settings → Development → New Application
|
|
176
|
+
2. Create app with `write:statuses` scope
|
|
177
|
+
3. Use format: `instance.social:your-access-token`
|
|
178
|
+
|
|
179
|
+
### Twitter/X
|
|
180
|
+
Uses copy-paste mode - generates formatted tweet text for manual posting.
|
|
181
|
+
No API setup required. Just set any placeholder value:
|
|
182
|
+
```bash
|
|
183
|
+
crier config set twitter.api_key manual
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Ghost
|
|
187
|
+
1. Go to Settings → Integrations → Add custom integration
|
|
188
|
+
2. Copy the Admin API Key (format: `key_id:key_secret`)
|
|
189
|
+
3. Use format: `https://yourblog.com:key_id:key_secret`
|
|
190
|
+
|
|
191
|
+
### WordPress
|
|
192
|
+
**WordPress.com:**
|
|
193
|
+
1. Go to https://developer.wordpress.com/apps/
|
|
194
|
+
2. Create an app and get OAuth token
|
|
195
|
+
3. Use format: `yoursite.wordpress.com:access_token`
|
|
196
|
+
|
|
197
|
+
**Self-hosted WordPress:**
|
|
198
|
+
1. Go to Users → Profile → Application Passwords
|
|
199
|
+
2. Create a new application password
|
|
200
|
+
3. Use format: `https://yoursite.com:username:app_password`
|
|
201
|
+
|
|
202
|
+
### Buttondown
|
|
203
|
+
1. Go to https://buttondown.email/settings/programming
|
|
204
|
+
2. Copy your API key
|
|
205
|
+
3. Use format: `api_key`
|
|
206
|
+
|
|
207
|
+
### Threads
|
|
208
|
+
1. Create a Meta Developer account at https://developers.facebook.com/
|
|
209
|
+
2. Create an app with Threads API access
|
|
210
|
+
3. Get your user_id and access_token
|
|
211
|
+
4. Use format: `user_id:access_token`
|
|
212
|
+
|
|
213
|
+
### Telegram
|
|
214
|
+
1. Message @BotFather to create a bot and get the bot token
|
|
215
|
+
2. Add your bot as admin to your channel
|
|
216
|
+
3. Get your channel's chat_id (e.g., `@yourchannel` or numeric ID)
|
|
217
|
+
4. Use format: `bot_token:chat_id`
|
|
218
|
+
|
|
219
|
+
### Discord
|
|
220
|
+
1. Go to Server Settings → Integrations → Webhooks
|
|
221
|
+
2. Create a new webhook for your announcement channel
|
|
222
|
+
3. Copy the webhook URL
|
|
223
|
+
4. Use the full URL as the API key
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
crier-0.2.0/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Crier
|
|
2
|
+
|
|
3
|
+
Cross-post your content to dev.to, Ghost, WordPress, Hashnode, Medium, Bluesky, Mastodon, Threads, Telegram, Discord, and more.
|
|
4
|
+
|
|
5
|
+
Like a town crier announcing your content to the world.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install crier
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Configure your API keys
|
|
17
|
+
crier config set devto.api_key YOUR_API_KEY
|
|
18
|
+
crier config set bluesky.api_key "handle.bsky.social:app-password"
|
|
19
|
+
crier config set mastodon.api_key "mastodon.social:access-token"
|
|
20
|
+
|
|
21
|
+
# Publish a markdown file
|
|
22
|
+
crier publish post.md --to devto
|
|
23
|
+
|
|
24
|
+
# Publish to multiple platforms at once
|
|
25
|
+
crier publish post.md --to devto --to bluesky --to mastodon
|
|
26
|
+
|
|
27
|
+
# List your articles
|
|
28
|
+
crier list devto
|
|
29
|
+
|
|
30
|
+
# Update an existing article
|
|
31
|
+
crier update devto 12345 --file updated-post.md
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Supported Platforms
|
|
35
|
+
|
|
36
|
+
| Platform | API Key Format | Notes |
|
|
37
|
+
|----------|---------------|-------|
|
|
38
|
+
| **dev.to** | `api_key` | Full article support |
|
|
39
|
+
| **Hashnode** | `token` or `token:publication_id` | Full article support |
|
|
40
|
+
| **Medium** | `integration_token` | Publish only (no edit/list) |
|
|
41
|
+
| **Ghost** | `https://site.com:key_id:key_secret` | Full article support |
|
|
42
|
+
| **WordPress** | `site.wordpress.com:token` or `https://site.com:user:app_pass` | Full article support |
|
|
43
|
+
| **Buttondown** | `api_key` | Newsletter publishing |
|
|
44
|
+
| **Bluesky** | `handle:app_password` | Short posts with link cards |
|
|
45
|
+
| **Mastodon** | `instance:access_token` | Toots with hashtags |
|
|
46
|
+
| **Threads** | `user_id:access_token` | Short posts (no edit support) |
|
|
47
|
+
| **Telegram** | `bot_token:chat_id` | Channel/group posts |
|
|
48
|
+
| **Discord** | `webhook_url` | Server announcements |
|
|
49
|
+
| **LinkedIn** | `access_token` | Requires API access |
|
|
50
|
+
| **Twitter/X** | `any` (copy-paste mode) | Generates tweet for manual posting |
|
|
51
|
+
|
|
52
|
+
### Platform Notes
|
|
53
|
+
|
|
54
|
+
**Blog Platforms** (dev.to, Hashnode, Medium, Ghost, WordPress):
|
|
55
|
+
- Full markdown article publishing
|
|
56
|
+
- Preserves front matter (title, description, tags, canonical_url)
|
|
57
|
+
- Best for long-form content
|
|
58
|
+
|
|
59
|
+
**Newsletter Platforms** (Buttondown):
|
|
60
|
+
- Publishes to email subscribers
|
|
61
|
+
- Full markdown support
|
|
62
|
+
- Great for content repurposing
|
|
63
|
+
|
|
64
|
+
**Social Platforms** (Bluesky, Mastodon, LinkedIn, Twitter, Threads):
|
|
65
|
+
- Creates short posts with link to canonical URL
|
|
66
|
+
- Uses title + description + hashtags from tags
|
|
67
|
+
- Best for announcing new content
|
|
68
|
+
|
|
69
|
+
**Announcement Channels** (Telegram, Discord):
|
|
70
|
+
- Posts to channels/servers
|
|
71
|
+
- Good for community announcements
|
|
72
|
+
- Discord uses webhook embeds
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
API keys can be set via:
|
|
77
|
+
|
|
78
|
+
1. **Config file** (`~/.config/crier/config.yaml`):
|
|
79
|
+
```yaml
|
|
80
|
+
platforms:
|
|
81
|
+
devto:
|
|
82
|
+
api_key: your_key_here
|
|
83
|
+
bluesky:
|
|
84
|
+
api_key: "handle.bsky.social:app-password"
|
|
85
|
+
mastodon:
|
|
86
|
+
api_key: "mastodon.social:access-token"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
2. **Environment variables**:
|
|
90
|
+
```bash
|
|
91
|
+
export CRIER_DEVTO_API_KEY=your_key_here
|
|
92
|
+
export CRIER_BLUESKY_API_KEY="handle.bsky.social:app-password"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Markdown Format
|
|
96
|
+
|
|
97
|
+
Crier reads standard markdown with YAML front matter:
|
|
98
|
+
|
|
99
|
+
```markdown
|
|
100
|
+
---
|
|
101
|
+
title: "My Amazing Post"
|
|
102
|
+
description: "A brief description"
|
|
103
|
+
tags: [python, programming]
|
|
104
|
+
canonical_url: https://myblog.com/my-post
|
|
105
|
+
published: true
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
Your content here...
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Commands
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
crier publish FILE [--to PLATFORM]... # Publish to platform(s)
|
|
115
|
+
crier update PLATFORM ID --file FILE # Update existing article
|
|
116
|
+
crier list PLATFORM # List your articles
|
|
117
|
+
crier config set KEY VALUE # Set configuration
|
|
118
|
+
crier config show # Show configuration
|
|
119
|
+
crier platforms # List available platforms
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Getting API Keys
|
|
123
|
+
|
|
124
|
+
### dev.to
|
|
125
|
+
1. Go to https://dev.to/settings/extensions
|
|
126
|
+
2. Generate API key
|
|
127
|
+
|
|
128
|
+
### Hashnode
|
|
129
|
+
1. Go to https://hashnode.com/settings/developer
|
|
130
|
+
2. Generate Personal Access Token
|
|
131
|
+
|
|
132
|
+
### Medium
|
|
133
|
+
1. Go to https://medium.com/me/settings/security
|
|
134
|
+
2. Generate Integration Token
|
|
135
|
+
|
|
136
|
+
### Bluesky
|
|
137
|
+
1. Go to Settings → App Passwords
|
|
138
|
+
2. Create an app password
|
|
139
|
+
3. Use format: `yourhandle.bsky.social:xxxx-xxxx-xxxx-xxxx`
|
|
140
|
+
|
|
141
|
+
### Mastodon
|
|
142
|
+
1. Go to Settings → Development → New Application
|
|
143
|
+
2. Create app with `write:statuses` scope
|
|
144
|
+
3. Use format: `instance.social:your-access-token`
|
|
145
|
+
|
|
146
|
+
### Twitter/X
|
|
147
|
+
Uses copy-paste mode - generates formatted tweet text for manual posting.
|
|
148
|
+
No API setup required. Just set any placeholder value:
|
|
149
|
+
```bash
|
|
150
|
+
crier config set twitter.api_key manual
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Ghost
|
|
154
|
+
1. Go to Settings → Integrations → Add custom integration
|
|
155
|
+
2. Copy the Admin API Key (format: `key_id:key_secret`)
|
|
156
|
+
3. Use format: `https://yourblog.com:key_id:key_secret`
|
|
157
|
+
|
|
158
|
+
### WordPress
|
|
159
|
+
**WordPress.com:**
|
|
160
|
+
1. Go to https://developer.wordpress.com/apps/
|
|
161
|
+
2. Create an app and get OAuth token
|
|
162
|
+
3. Use format: `yoursite.wordpress.com:access_token`
|
|
163
|
+
|
|
164
|
+
**Self-hosted WordPress:**
|
|
165
|
+
1. Go to Users → Profile → Application Passwords
|
|
166
|
+
2. Create a new application password
|
|
167
|
+
3. Use format: `https://yoursite.com:username:app_password`
|
|
168
|
+
|
|
169
|
+
### Buttondown
|
|
170
|
+
1. Go to https://buttondown.email/settings/programming
|
|
171
|
+
2. Copy your API key
|
|
172
|
+
3. Use format: `api_key`
|
|
173
|
+
|
|
174
|
+
### Threads
|
|
175
|
+
1. Create a Meta Developer account at https://developers.facebook.com/
|
|
176
|
+
2. Create an app with Threads API access
|
|
177
|
+
3. Get your user_id and access_token
|
|
178
|
+
4. Use format: `user_id:access_token`
|
|
179
|
+
|
|
180
|
+
### Telegram
|
|
181
|
+
1. Message @BotFather to create a bot and get the bot token
|
|
182
|
+
2. Add your bot as admin to your channel
|
|
183
|
+
3. Get your channel's chat_id (e.g., `@yourchannel` or numeric ID)
|
|
184
|
+
4. Use format: `bot_token:chat_id`
|
|
185
|
+
|
|
186
|
+
### Discord
|
|
187
|
+
1. Go to Server Settings → Integrations → Webhooks
|
|
188
|
+
2. Create a new webhook for your announcement channel
|
|
189
|
+
3. Copy the webhook URL
|
|
190
|
+
4. Use the full URL as the API key
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
MIT
|