python-substack 0.1.27__tar.gz → 0.3.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.
- python_substack-0.3.0/PKG-INFO +284 -0
- python_substack-0.3.0/README.md +247 -0
- {python_substack-0.1.27 → python_substack-0.3.0}/pyproject.toml +5 -3
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/__init__.py +4 -2
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/api.py +0 -1
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/post.py +33 -36
- python_substack-0.1.27/PKG-INFO +0 -479
- python_substack-0.1.27/README.md +0 -443
- {python_substack-0.1.27 → python_substack-0.3.0}/LICENSE +0 -0
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/cli.py +0 -0
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/exceptions.py +0 -0
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/mdrender.py +0 -0
- {python_substack-0.1.27 → python_substack-0.3.0}/substack/nodes.py +0 -0
- {python_substack-0.1.27 → python_substack-0.3.0}/substack_mcp/mcp_server.py +0 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-substack
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Write and safely manage Substack drafts from Markdown with Python, CLI, and MCP.
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: substack,substack-api,cli,newsletter,publishing,automation,mcp
|
|
8
|
+
Author: Paolo Mazza
|
|
9
|
+
Author-email: mazzapaolo2019@gmail.com
|
|
10
|
+
Requires-Python: >=3.10,<4.0
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Communications :: Email
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Provides-Extra: mcp
|
|
24
|
+
Requires-Dist: PyYAML (>=6.0,<7.0)
|
|
25
|
+
Requires-Dist: fastmcp (>=3.1.1,<4.0.0) ; extra == "mcp"
|
|
26
|
+
Requires-Dist: markdown-it-py (>=3.0,<4.0)
|
|
27
|
+
Requires-Dist: mdit-py-plugins (>=0.5,<0.7)
|
|
28
|
+
Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
|
|
29
|
+
Requires-Dist: requests (>=2.32.0,<3.0.0)
|
|
30
|
+
Project-URL: Changelog, https://github.com/ma2za/python-substack/blob/main/CHANGELOG.md
|
|
31
|
+
Project-URL: Documentation, https://ma2za.github.io/python-substack/
|
|
32
|
+
Project-URL: Homepage, https://github.com/ma2za/python-substack
|
|
33
|
+
Project-URL: Issues, https://github.com/ma2za/python-substack/issues
|
|
34
|
+
Project-URL: Repository, https://github.com/ma2za/python-substack
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# Python Substack
|
|
38
|
+
|
|
39
|
+
Write Substack posts in Markdown and safely create, inspect, schedule, and
|
|
40
|
+
publish them through Python, a command-line interface, or MCP.
|
|
41
|
+
|
|
42
|
+
[](https://pypi.org/project/python-substack/)
|
|
43
|
+
[](https://pypi.org/project/python-substack/)
|
|
44
|
+
[](https://github.com/ma2za/python-substack/actions/workflows/ci.yml)
|
|
45
|
+
[](https://github.com/ma2za/python-substack/actions/workflows/ci_publish.yml)
|
|
46
|
+
[](LICENSE)
|
|
47
|
+
[](https://pepy.tech/project/python-substack)
|
|
48
|
+
|
|
49
|
+
[Documentation](https://ma2za.github.io/python-substack/) ·
|
|
50
|
+
[Getting started](https://ma2za.github.io/python-substack/getting-started.html) ·
|
|
51
|
+
[PyPI](https://pypi.org/project/python-substack/)
|
|
52
|
+
|
|
53
|
+
> [!IMPORTANT]
|
|
54
|
+
> Creating and publishing are separate operations. `substack drafts create`
|
|
55
|
+
> always creates an unpublished draft. It never schedules, sends, publishes,
|
|
56
|
+
> or deletes content.
|
|
57
|
+
|
|
58
|
+
## From Markdown to a Substack draft
|
|
59
|
+
|
|
60
|
+
Install the package:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install python-substack
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Check the selected account and publication:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
substack status
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Create a safe unpublished draft, then publish only when it is ready:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
substack drafts create post.md
|
|
76
|
+
substack drafts publish 12345 --no-send
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Publishing and deletion require confirmation. Noninteractive and JSON
|
|
80
|
+
workflows must pass `--yes` explicitly.
|
|
81
|
+
|
|
82
|
+
Markdown source:
|
|
83
|
+
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
Substack result:
|
|
87
|
+
|
|
88
|
+

|
|
89
|
+
|
|
90
|
+
## What it supports
|
|
91
|
+
|
|
92
|
+
- Create rich Substack drafts from Markdown.
|
|
93
|
+
- Upload local images referenced by Markdown.
|
|
94
|
+
- Set audience, comment permissions, SEO metadata, slug, sections, and tags.
|
|
95
|
+
- List and inspect publications and drafts.
|
|
96
|
+
- Schedule, unschedule, publish, and delete drafts with explicit safeguards.
|
|
97
|
+
- Use stable JSON envelopes in scripts and automation.
|
|
98
|
+
- Authenticate with browser cookies or email and password.
|
|
99
|
+
- Use the same publishing workflow from Python or an optional MCP server.
|
|
100
|
+
|
|
101
|
+
## Setup
|
|
102
|
+
|
|
103
|
+
Copy `.env.example` to `.env` and configure one authentication method:
|
|
104
|
+
|
|
105
|
+
```env
|
|
106
|
+
EMAIL=
|
|
107
|
+
PASSWORD=
|
|
108
|
+
PUBLICATION_URL=
|
|
109
|
+
COOKIES_PATH=
|
|
110
|
+
COOKIES_STRING=
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Cookie authentication is usually more reliable when Substack requires captcha
|
|
114
|
+
or magic-link sign-in. See
|
|
115
|
+
[Authentication](docs/authentication.md) for cookie export instructions and
|
|
116
|
+
account-selection details.
|
|
117
|
+
|
|
118
|
+
Verify the installation without authenticating:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
substack --version
|
|
122
|
+
substack --help
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## CLI
|
|
126
|
+
|
|
127
|
+
Create a draft with metadata:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
substack --json drafts create post.md \
|
|
131
|
+
--title "My Post" \
|
|
132
|
+
--subtitle "Optional subtitle" \
|
|
133
|
+
--tag python \
|
|
134
|
+
--tag substack \
|
|
135
|
+
--slug my-post \
|
|
136
|
+
--search-engine-title "SEO title" \
|
|
137
|
+
--search-engine-description "SEO description"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Inspect publications and drafts:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
substack publications list
|
|
144
|
+
substack drafts list --limit 10
|
|
145
|
+
substack drafts get 12345
|
|
146
|
+
substack --publication-url https://example.substack.com drafts list
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Manage scheduling:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
substack drafts schedule 12345 --at 2026-08-01T09:00:00+03:00
|
|
153
|
+
substack drafts unschedule 12345
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Publish or delete intentionally:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
substack drafts publish 12345 --no-send
|
|
160
|
+
substack drafts delete 12345 --yes
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Global options such as `--json`, `--cookies`, and `--publication-url` must
|
|
164
|
+
appear before the command:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
substack --json drafts list
|
|
168
|
+
substack --cookies cookies.json --json status
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The original standalone commands remain supported. See
|
|
172
|
+
[Legacy CLI commands](docs/legacy-cli.md).
|
|
173
|
+
|
|
174
|
+
## Python
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
import os
|
|
178
|
+
|
|
179
|
+
from dotenv import load_dotenv
|
|
180
|
+
from substack import Api
|
|
181
|
+
|
|
182
|
+
load_dotenv()
|
|
183
|
+
|
|
184
|
+
api = Api(
|
|
185
|
+
email=os.getenv("EMAIL"),
|
|
186
|
+
password=os.getenv("PASSWORD"),
|
|
187
|
+
publication_url=os.getenv("PUBLICATION_URL"),
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
result = api.create_draft_from_markdown(
|
|
191
|
+
title="Shipping with Python",
|
|
192
|
+
subtitle="A short note from a script",
|
|
193
|
+
markdown="""
|
|
194
|
+
# Hello
|
|
195
|
+
|
|
196
|
+
This draft was created from **Markdown**.
|
|
197
|
+
|
|
198
|
+

|
|
199
|
+
""",
|
|
200
|
+
tags=["python", "automation"],
|
|
201
|
+
slug="shipping-with-python",
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
print(result["draft"]["id"])
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`create_draft_from_markdown` creates a draft by default. It publishes only when
|
|
208
|
+
`publish=True` is passed.
|
|
209
|
+
|
|
210
|
+
For direct ProseMirror node construction, see the
|
|
211
|
+
[low-level Python API](docs/low-level-api.md). YAML workflows are documented in
|
|
212
|
+
[YAML drafts](docs/yaml.md).
|
|
213
|
+
|
|
214
|
+
## Markdown
|
|
215
|
+
|
|
216
|
+
Supported Markdown includes headings, paragraphs, bold, italic, inline code,
|
|
217
|
+
strikethrough, superscript, subscript, links, images, linked images, image
|
|
218
|
+
captions, code blocks, blockquotes, ordered and unordered lists, horizontal
|
|
219
|
+
rules, footnotes, LaTeX math, pull quotes, and callouts.
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from substack.post import Post
|
|
223
|
+
|
|
224
|
+
post = Post("Title", "Subtitle", user_id=1)
|
|
225
|
+
post.from_markdown(
|
|
226
|
+
"""
|
|
227
|
+
# Heading
|
|
228
|
+
|
|
229
|
+
Paragraph with **bold**, *italic*, `code`, and [links](https://example.com).
|
|
230
|
+
"""
|
|
231
|
+
)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Pass `api=` to upload local images while rendering:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
post.from_markdown(markdown_content, api=api)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
See the complete [Markdown reference](docs/markdown.md).
|
|
241
|
+
|
|
242
|
+
## MCP
|
|
243
|
+
|
|
244
|
+
Install and run the optional MCP server:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
pip install "python-substack[mcp]"
|
|
248
|
+
substack-mcp
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The MCP tools use the same environment variables and SDK behavior as the CLI.
|
|
252
|
+
See [MCP server](docs/mcp.md) for the tool list and safety notes.
|
|
253
|
+
|
|
254
|
+
## Project documentation
|
|
255
|
+
|
|
256
|
+
- [Documentation site](https://ma2za.github.io/python-substack/)
|
|
257
|
+
- [Installation and first draft](docs/getting-started.md)
|
|
258
|
+
- [Unified CLI](docs/cli.md)
|
|
259
|
+
- [Python SDK](docs/python-sdk.md)
|
|
260
|
+
- [Authentication](docs/authentication.md)
|
|
261
|
+
- [Markdown reference](docs/markdown.md)
|
|
262
|
+
- [Legacy CLI commands](docs/legacy-cli.md)
|
|
263
|
+
- [Low-level Python API](docs/low-level-api.md)
|
|
264
|
+
- [YAML drafts](docs/yaml.md)
|
|
265
|
+
- [MCP server](docs/mcp.md)
|
|
266
|
+
- [Safety and publishing behavior](docs/safety.md)
|
|
267
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
268
|
+
- [Compatibility policy](docs/compatibility.md)
|
|
269
|
+
- [Contributing](CONTRIBUTING.md)
|
|
270
|
+
- [Security policy](SECURITY.md)
|
|
271
|
+
- [Changelog](CHANGELOG.md)
|
|
272
|
+
|
|
273
|
+
## Compatibility
|
|
274
|
+
|
|
275
|
+
The project preserves existing Python APIs, console commands, CLI behavior,
|
|
276
|
+
environment variables, JSON keys, and MCP tool signatures through the 1.x
|
|
277
|
+
series. Additive capabilities may be introduced. See the
|
|
278
|
+
[compatibility policy](docs/compatibility.md).
|
|
279
|
+
|
|
280
|
+
## Disclaimer
|
|
281
|
+
|
|
282
|
+
This project is not affiliated with Substack. It uses undocumented Substack
|
|
283
|
+
interfaces that may change without notice.
|
|
284
|
+
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Python Substack
|
|
2
|
+
|
|
3
|
+
Write Substack posts in Markdown and safely create, inspect, schedule, and
|
|
4
|
+
publish them through Python, a command-line interface, or MCP.
|
|
5
|
+
|
|
6
|
+
[](https://pypi.org/project/python-substack/)
|
|
7
|
+
[](https://pypi.org/project/python-substack/)
|
|
8
|
+
[](https://github.com/ma2za/python-substack/actions/workflows/ci.yml)
|
|
9
|
+
[](https://github.com/ma2za/python-substack/actions/workflows/ci_publish.yml)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://pepy.tech/project/python-substack)
|
|
12
|
+
|
|
13
|
+
[Documentation](https://ma2za.github.io/python-substack/) ·
|
|
14
|
+
[Getting started](https://ma2za.github.io/python-substack/getting-started.html) ·
|
|
15
|
+
[PyPI](https://pypi.org/project/python-substack/)
|
|
16
|
+
|
|
17
|
+
> [!IMPORTANT]
|
|
18
|
+
> Creating and publishing are separate operations. `substack drafts create`
|
|
19
|
+
> always creates an unpublished draft. It never schedules, sends, publishes,
|
|
20
|
+
> or deletes content.
|
|
21
|
+
|
|
22
|
+
## From Markdown to a Substack draft
|
|
23
|
+
|
|
24
|
+
Install the package:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install python-substack
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Check the selected account and publication:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
substack status
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Create a safe unpublished draft, then publish only when it is ready:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
substack drafts create post.md
|
|
40
|
+
substack drafts publish 12345 --no-send
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Publishing and deletion require confirmation. Noninteractive and JSON
|
|
44
|
+
workflows must pass `--yes` explicitly.
|
|
45
|
+
|
|
46
|
+
Markdown source:
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
Substack result:
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
## What it supports
|
|
55
|
+
|
|
56
|
+
- Create rich Substack drafts from Markdown.
|
|
57
|
+
- Upload local images referenced by Markdown.
|
|
58
|
+
- Set audience, comment permissions, SEO metadata, slug, sections, and tags.
|
|
59
|
+
- List and inspect publications and drafts.
|
|
60
|
+
- Schedule, unschedule, publish, and delete drafts with explicit safeguards.
|
|
61
|
+
- Use stable JSON envelopes in scripts and automation.
|
|
62
|
+
- Authenticate with browser cookies or email and password.
|
|
63
|
+
- Use the same publishing workflow from Python or an optional MCP server.
|
|
64
|
+
|
|
65
|
+
## Setup
|
|
66
|
+
|
|
67
|
+
Copy `.env.example` to `.env` and configure one authentication method:
|
|
68
|
+
|
|
69
|
+
```env
|
|
70
|
+
EMAIL=
|
|
71
|
+
PASSWORD=
|
|
72
|
+
PUBLICATION_URL=
|
|
73
|
+
COOKIES_PATH=
|
|
74
|
+
COOKIES_STRING=
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Cookie authentication is usually more reliable when Substack requires captcha
|
|
78
|
+
or magic-link sign-in. See
|
|
79
|
+
[Authentication](docs/authentication.md) for cookie export instructions and
|
|
80
|
+
account-selection details.
|
|
81
|
+
|
|
82
|
+
Verify the installation without authenticating:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
substack --version
|
|
86
|
+
substack --help
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## CLI
|
|
90
|
+
|
|
91
|
+
Create a draft with metadata:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
substack --json drafts create post.md \
|
|
95
|
+
--title "My Post" \
|
|
96
|
+
--subtitle "Optional subtitle" \
|
|
97
|
+
--tag python \
|
|
98
|
+
--tag substack \
|
|
99
|
+
--slug my-post \
|
|
100
|
+
--search-engine-title "SEO title" \
|
|
101
|
+
--search-engine-description "SEO description"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Inspect publications and drafts:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
substack publications list
|
|
108
|
+
substack drafts list --limit 10
|
|
109
|
+
substack drafts get 12345
|
|
110
|
+
substack --publication-url https://example.substack.com drafts list
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Manage scheduling:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
substack drafts schedule 12345 --at 2026-08-01T09:00:00+03:00
|
|
117
|
+
substack drafts unschedule 12345
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Publish or delete intentionally:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
substack drafts publish 12345 --no-send
|
|
124
|
+
substack drafts delete 12345 --yes
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Global options such as `--json`, `--cookies`, and `--publication-url` must
|
|
128
|
+
appear before the command:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
substack --json drafts list
|
|
132
|
+
substack --cookies cookies.json --json status
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The original standalone commands remain supported. See
|
|
136
|
+
[Legacy CLI commands](docs/legacy-cli.md).
|
|
137
|
+
|
|
138
|
+
## Python
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
import os
|
|
142
|
+
|
|
143
|
+
from dotenv import load_dotenv
|
|
144
|
+
from substack import Api
|
|
145
|
+
|
|
146
|
+
load_dotenv()
|
|
147
|
+
|
|
148
|
+
api = Api(
|
|
149
|
+
email=os.getenv("EMAIL"),
|
|
150
|
+
password=os.getenv("PASSWORD"),
|
|
151
|
+
publication_url=os.getenv("PUBLICATION_URL"),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
result = api.create_draft_from_markdown(
|
|
155
|
+
title="Shipping with Python",
|
|
156
|
+
subtitle="A short note from a script",
|
|
157
|
+
markdown="""
|
|
158
|
+
# Hello
|
|
159
|
+
|
|
160
|
+
This draft was created from **Markdown**.
|
|
161
|
+
|
|
162
|
+

|
|
163
|
+
""",
|
|
164
|
+
tags=["python", "automation"],
|
|
165
|
+
slug="shipping-with-python",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
print(result["draft"]["id"])
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`create_draft_from_markdown` creates a draft by default. It publishes only when
|
|
172
|
+
`publish=True` is passed.
|
|
173
|
+
|
|
174
|
+
For direct ProseMirror node construction, see the
|
|
175
|
+
[low-level Python API](docs/low-level-api.md). YAML workflows are documented in
|
|
176
|
+
[YAML drafts](docs/yaml.md).
|
|
177
|
+
|
|
178
|
+
## Markdown
|
|
179
|
+
|
|
180
|
+
Supported Markdown includes headings, paragraphs, bold, italic, inline code,
|
|
181
|
+
strikethrough, superscript, subscript, links, images, linked images, image
|
|
182
|
+
captions, code blocks, blockquotes, ordered and unordered lists, horizontal
|
|
183
|
+
rules, footnotes, LaTeX math, pull quotes, and callouts.
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from substack.post import Post
|
|
187
|
+
|
|
188
|
+
post = Post("Title", "Subtitle", user_id=1)
|
|
189
|
+
post.from_markdown(
|
|
190
|
+
"""
|
|
191
|
+
# Heading
|
|
192
|
+
|
|
193
|
+
Paragraph with **bold**, *italic*, `code`, and [links](https://example.com).
|
|
194
|
+
"""
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Pass `api=` to upload local images while rendering:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
post.from_markdown(markdown_content, api=api)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
See the complete [Markdown reference](docs/markdown.md).
|
|
205
|
+
|
|
206
|
+
## MCP
|
|
207
|
+
|
|
208
|
+
Install and run the optional MCP server:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pip install "python-substack[mcp]"
|
|
212
|
+
substack-mcp
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The MCP tools use the same environment variables and SDK behavior as the CLI.
|
|
216
|
+
See [MCP server](docs/mcp.md) for the tool list and safety notes.
|
|
217
|
+
|
|
218
|
+
## Project documentation
|
|
219
|
+
|
|
220
|
+
- [Documentation site](https://ma2za.github.io/python-substack/)
|
|
221
|
+
- [Installation and first draft](docs/getting-started.md)
|
|
222
|
+
- [Unified CLI](docs/cli.md)
|
|
223
|
+
- [Python SDK](docs/python-sdk.md)
|
|
224
|
+
- [Authentication](docs/authentication.md)
|
|
225
|
+
- [Markdown reference](docs/markdown.md)
|
|
226
|
+
- [Legacy CLI commands](docs/legacy-cli.md)
|
|
227
|
+
- [Low-level Python API](docs/low-level-api.md)
|
|
228
|
+
- [YAML drafts](docs/yaml.md)
|
|
229
|
+
- [MCP server](docs/mcp.md)
|
|
230
|
+
- [Safety and publishing behavior](docs/safety.md)
|
|
231
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
232
|
+
- [Compatibility policy](docs/compatibility.md)
|
|
233
|
+
- [Contributing](CONTRIBUTING.md)
|
|
234
|
+
- [Security policy](SECURITY.md)
|
|
235
|
+
- [Changelog](CHANGELOG.md)
|
|
236
|
+
|
|
237
|
+
## Compatibility
|
|
238
|
+
|
|
239
|
+
The project preserves existing Python APIs, console commands, CLI behavior,
|
|
240
|
+
environment variables, JSON keys, and MCP tool signatures through the 1.x
|
|
241
|
+
series. Additive capabilities may be introduced. See the
|
|
242
|
+
[compatibility policy](docs/compatibility.md).
|
|
243
|
+
|
|
244
|
+
## Disclaimer
|
|
245
|
+
|
|
246
|
+
This project is not affiliated with Substack. It uses undocumented Substack
|
|
247
|
+
interfaces that may change without notice.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-substack"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "Write and safely manage Substack drafts from Markdown with Python, CLI, and MCP."
|
|
5
5
|
authors = ["Paolo Mazza <mazzapaolo2019@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
7
7
|
packages = [
|
|
@@ -16,7 +16,7 @@ homepage = "https://github.com/ma2za/python-substack"
|
|
|
16
16
|
|
|
17
17
|
keywords = ["substack", "substack-api", "cli", "newsletter", "publishing", "automation", "mcp"]
|
|
18
18
|
classifiers = [
|
|
19
|
-
"Development Status ::
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
20
|
"Intended Audience :: Developers",
|
|
21
21
|
"Programming Language :: Python :: 3",
|
|
22
22
|
"Programming Language :: Python :: 3.10",
|
|
@@ -29,6 +29,7 @@ classifiers = [
|
|
|
29
29
|
]
|
|
30
30
|
|
|
31
31
|
[tool.poetry.urls]
|
|
32
|
+
"Documentation" = "https://ma2za.github.io/python-substack/"
|
|
32
33
|
"Changelog" = "https://github.com/ma2za/python-substack/blob/main/CHANGELOG.md"
|
|
33
34
|
"Issues" = "https://github.com/ma2za/python-substack/issues"
|
|
34
35
|
|
|
@@ -47,6 +48,7 @@ mcp = ["fastmcp"]
|
|
|
47
48
|
|
|
48
49
|
[tool.poetry.group.dev.dependencies]
|
|
49
50
|
pytest = "^9.1.1"
|
|
51
|
+
pre-commit = "^4.6.1"
|
|
50
52
|
|
|
51
53
|
[tool.pytest.ini_options]
|
|
52
54
|
markers = [
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
__author__ = "Paolo Mazza"
|
|
4
4
|
__email__ = "mazzapaolo2019@gmail.com"
|
|
5
5
|
__license__ = "MIT License"
|
|
6
|
-
__version__ = "0.
|
|
6
|
+
__version__ = "0.3.0"
|
|
7
7
|
__url__ = "https://github.com/ma2za/python-substack"
|
|
8
8
|
__download_url__ = "https://pypi.python.org/pypi/python-substack"
|
|
9
|
-
__description__ =
|
|
9
|
+
__description__ = (
|
|
10
|
+
"Write and safely manage Substack drafts from Markdown with Python, CLI, and MCP."
|
|
11
|
+
)
|
|
10
12
|
|
|
11
13
|
from .api import Api
|