Skip to content

Commit 0196604

Browse files
committed
🐉 audience and write_comment_permissions support
1 parent 235c35f commit 0196604

4 files changed

Lines changed: 107 additions & 12 deletions

File tree

examples/draft.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ title:
22
"How to publish a Substack post using the Python API"
33
subtitle:
44
"This post was published using the Python API"
5+
audience:
6+
"everyone" # everyone, only_paid, founding, only_free
7+
write_comment_permissions:
8+
"none" # none, only_paid, everyone
59
body:
610
0:
711
type: "heading"
@@ -12,7 +16,7 @@ body:
1216
content: "1)"
1317
2:
1418
type: "paragraph"
15-
content: "Discover your USER ID by inspecting the request body of any publish request."
19+
content: "discover the USER_ID in the url of the public profile page"
1620
3:
1721
type: "horizontal_rule"
1822
4:

examples/publish_post.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,20 @@
2020
with open(args.post, "r") as fp:
2121
post_data = yaml.safe_load(fp)
2222

23-
title = post_data.get("title", "")
24-
subtitle = post_data.get("subtitle", "")
25-
body = post_data.get("body", {})
26-
2723
api = Api(
2824
email=os.getenv("EMAIL"),
2925
password=os.getenv("PASSWORD"),
3026
publication_url=os.getenv("PUBLICATION_URL"),
3127
)
3228

33-
post = Post(title, subtitle, os.getenv("USER_ID"))
29+
post = Post(post_data.get("title"),
30+
post_data.get("subtitle", ""),
31+
os.getenv("USER_ID"),
32+
audience=post_data.get("audience", "everyone"),
33+
write_comment_permissions=post_data.get("write_comment_permissions", "everyone"))
34+
35+
body = post_data.get("body", {})
36+
3437
for _, item in body.items():
3538
if item.get("type") == "captionedImage":
3639
image = api.get_image(item.get("src"))

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "python-substack"
3-
version = "0.1.7"
3+
version = "0.1.8"
44
description = "A Python wrapper around the Substack API."
55
authors = ["Paolo Mazza <mazzapaolo2019@gmail.com>"]
66
license = "MIT"

substack/post.py

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,35 @@
44

55
class Post:
66

7-
def __init__(self, title, subtitle, user_id):
7+
def __init__(self, title: str, subtitle: str, user_id,
8+
audience: str = None,
9+
write_comment_permissions: str = None):
10+
"""
11+
12+
Args:
13+
title:
14+
subtitle:
15+
user_id:
16+
audience: possible values: everyone, only_paid, founding, only_free
17+
write_comment_permissions: none, only_paid, everyone (this field is a mess)
18+
"""
819
self.draft_title = title
920
self.draft_subtitle = subtitle
1021
self.draft_body = {"type": "doc", "content": []}
1122
self.draft_bylines = [{"id": int(user_id), "is_guest": False}]
23+
self.audience = audience if audience is not None else "everyone"
24+
25+
# TODO better understand the possible values and combinations with audience
26+
if write_comment_permissions is not None:
27+
self.write_comment_permissions = write_comment_permissions
28+
else:
29+
self.write_comment_permissions = self.audience
1230

1331
def add(self, item: Dict):
1432
"""
1533
34+
Add item to draft body.
35+
1636
Args:
1737
item:
1838
@@ -40,22 +60,53 @@ def add(self, item: Dict):
4060
return self
4161

4262
def paragraph(self, content=None):
63+
"""
64+
65+
Args:
66+
content:
67+
68+
Returns:
69+
70+
"""
4371
item = {"type": "paragraph"}
4472
if content is not None:
4573
item["content"] = content
4674
return self.add(item)
4775

48-
def heading(self, content=None, level=1):
76+
def heading(self, content=None, level: int = 1):
77+
"""
78+
79+
Args:
80+
content:
81+
level:
82+
83+
Returns:
84+
85+
"""
86+
4987
item = {"type": "heading"}
5088
if content is not None:
5189
item["content"] = content
5290
item["level"] = level
5391
return self.add(item)
5492

5593
def horizontal_rule(self):
94+
"""
95+
96+
Returns:
97+
98+
"""
5699
return self.add({"type": "horizontal_rule"})
57100

58101
def attrs(self, level):
102+
"""
103+
104+
Args:
105+
level:
106+
107+
Returns:
108+
109+
"""
59110
content_attrs = self.draft_body["content"][-1].get("attrs", {})
60111
content_attrs.update({"level": level})
61112
self.draft_body["content"][-1]["attrs"] = content_attrs
@@ -116,7 +167,7 @@ def captioned_image(self,
116167
self.draft_body["content"][-1]["content"] = content
117168
return self
118169

119-
def text(self, value):
170+
def text(self, value: str):
120171
"""
121172
122173
Add text to the last paragraph.
@@ -133,6 +184,11 @@ def text(self, value):
133184
return self
134185

135186
def add_complex_text(self, text):
187+
"""
188+
189+
Args:
190+
text:
191+
"""
136192
if isinstance(text, str):
137193
self.text(text)
138194
else:
@@ -141,6 +197,14 @@ def add_complex_text(self, text):
141197
self.text(chunk.get("content")).marks(chunk.get("marks"))
142198

143199
def marks(self, marks):
200+
"""
201+
202+
Args:
203+
marks:
204+
205+
Returns:
206+
207+
"""
144208
content = self.draft_body["content"][-1].get("content", [])[-1]
145209
content_marks = content.get("marks", [])
146210
for mark in marks:
@@ -155,14 +219,30 @@ def marks(self, marks):
155219
return self
156220

157221
def remove_last_paragraph(self):
222+
"""
223+
224+
"""
158225
del self.draft_body.get("content")[-1]
159226

160227
def get_draft(self):
228+
"""
229+
230+
Returns:
231+
232+
"""
161233
out = vars(self)
162234
out["draft_body"] = json.dumps(out["draft_body"])
163235
return out
164236

165-
def subscribe_with_caption(self, value):
237+
def subscribe_with_caption(self, value: str):
238+
"""
239+
240+
Args:
241+
value:
242+
243+
Returns:
244+
245+
"""
166246
content = self.draft_body["content"][-1].get("content", [])
167247
content += [{"type": "subscribeWidget",
168248
"attrs": {"url": "%%checkout_url%%", "text": "Subscribe"},
@@ -177,7 +257,15 @@ def subscribe_with_caption(self, value):
177257
self.draft_body["content"][-1]["content"] = content
178258
return self
179259

180-
def youtube(self, value):
260+
def youtube(self, value: str):
261+
"""
262+
263+
Args:
264+
value:
265+
266+
Returns:
267+
268+
"""
181269
content_attrs = self.draft_body["content"][-1].get("attrs", {})
182270
content_attrs.update({"videoId": value})
183271
self.draft_body["content"][-1]["attrs"] = content_attrs

0 commit comments

Comments
 (0)