|
1 | 1 | # Python Substack |
2 | 2 |
|
3 | | -Unofficial Python tools for publishing to [Substack](https://substack.com/). |
| 3 | +An unofficial Python SDK and CLI for managing [Substack](https://substack.com/) publications and drafts. |
4 | 4 |
|
| 5 | +[](https://pypi.org/project/python-substack/) |
| 6 | +[](https://pypi.org/project/python-substack/) |
| 7 | +[](https://github.com/ma2za/python-substack/actions/workflows/ci.yml) |
| 8 | +[](https://github.com/ma2za/python-substack/actions/workflows/ci_publish.yml) |
| 9 | +[](LICENSE) |
5 | 10 | [](https://pepy.tech/project/python-substack) |
6 | | - |
7 | 11 |
|
8 | 12 | ## Features |
9 | 13 |
|
| 14 | +- Inspect authentication and publication status from the terminal. |
| 15 | +- List publications and inspect, schedule, publish, or delete drafts. |
| 16 | +- Use stable JSON output in scripts and automation. |
10 | 17 | - Create drafts and publish posts from Python. |
11 | 18 | - Convert Markdown into Substack's editor document format. |
12 | 19 | - Upload local images while rendering Markdown. |
@@ -43,6 +50,49 @@ Use either `EMAIL` and `PASSWORD`, or cookie-based authentication with `COOKIES_ |
43 | 50 |
|
44 | 51 | Newer Substack accounts may only have magic-link sign-in enabled. To set a password, sign out of Substack, choose "Sign in with password", then choose "Set a new password". |
45 | 52 |
|
| 53 | +## CLI Operations |
| 54 | + |
| 55 | +Check authentication, the selected publication, and subscriber count: |
| 56 | + |
| 57 | +```bash |
| 58 | +substack status |
| 59 | +``` |
| 60 | + |
| 61 | +List available publications or target one without changing `.env`: |
| 62 | + |
| 63 | +```bash |
| 64 | +substack publications list |
| 65 | +substack --publication-url https://example.substack.com drafts list |
| 66 | +``` |
| 67 | + |
| 68 | +List and inspect drafts: |
| 69 | + |
| 70 | +```bash |
| 71 | +substack drafts list --limit 10 |
| 72 | +substack drafts get 12345 |
| 73 | +``` |
| 74 | + |
| 75 | +Schedule with a timezone-aware ISO 8601 timestamp, or remove a schedule: |
| 76 | + |
| 77 | +```bash |
| 78 | +substack drafts schedule 12345 --at 2026-08-01T09:00:00+03:00 |
| 79 | +substack drafts unschedule 12345 |
| 80 | +``` |
| 81 | + |
| 82 | +Publishing and deletion prompt for confirmation. Use `--yes` for intentional non-interactive execution: |
| 83 | + |
| 84 | +```bash |
| 85 | +substack drafts publish 12345 --no-send |
| 86 | +substack drafts delete 12345 --yes |
| 87 | +``` |
| 88 | + |
| 89 | +Global options must appear before the command. `--json` returns stable envelopes containing the raw Substack responses: |
| 90 | + |
| 91 | +```bash |
| 92 | +substack --json drafts list |
| 93 | +substack --cookies cookies.json --json status |
| 94 | +``` |
| 95 | + |
46 | 96 | ## Quickstart |
47 | 97 |
|
48 | 98 | ```python |
@@ -78,7 +128,7 @@ print(result["draft"]["id"]) |
78 | 128 |
|
79 | 129 | `create_draft_from_markdown` creates a draft by default. It only publishes when `publish=True` is passed. |
80 | 130 |
|
81 | | -## CLI |
| 131 | +## Content Publishing CLI |
82 | 132 |
|
83 | 133 | Check authentication without creating a draft: |
84 | 134 |
|
@@ -338,6 +388,8 @@ pytest |
338 | 388 |
|
339 | 389 | Live Substack tests are opt-in. Set `RUN_SUBSTACK_E2E=1` and configure credentials before running them. |
340 | 390 |
|
| 391 | +The CLI operations smoke test is separately opt-in. Set `RUN_SUBSTACK_CLI_E2E=1` to create, schedule, unschedule, inspect, and delete a disposable draft. It never publishes the draft. |
| 392 | + |
341 | 393 | Release changes are tracked in [CHANGELOG.md](CHANGELOG.md). |
342 | 394 |
|
343 | 395 | ## Disclaimer |
|
0 commit comments