Skip to content

Commit 52944dd

Browse files
committed
🪿 upkeep
1 parent 0196604 commit 52944dd

7 files changed

Lines changed: 162 additions & 99 deletions

File tree

‎.github/workflows/ci_publish.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Upload Python Package
1+
name: Publish
22
on:
33
push:
44
branches:

‎LICENSE‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2022 hogier
3+
Copyright (c) 2022 ma2za
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

‎README.md‎

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
# Python Substack
22

3-
# Introduction
4-
53
This is an unofficial library providing a Python interface for [Substack](https://substack.com/).
6-
I am in no way affiliated with Substack. It works with
7-
Python versions from 3.7+.
4+
I am in no way affiliated with Substack.
5+
6+
[![Python](https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058)](https://www.python.org/downloads/)
7+
[![Downloads](https://static.pepy.tech/badge/python-substack/month)](https://pepy.tech/project/python-substack)
8+
![Release Build](https://github.com/ma2za/python-substack/actions/workflows/ci_publish.yml/badge.svg)
9+
---
810

911
# Installation
1012

1113
You can install python-substack using:
1214

1315
$ pip install python-substack
1416

15-
# Usage
17+
---
18+
19+
# Setup
1620

1721
Set the following environment variables by creating a **.env** file:
1822

@@ -22,9 +26,40 @@ Set the following environment variables by creating a **.env** file:
2226
USER_ID=
2327

2428
To discover the USER_ID go to your public profile page,
25-
in the URL bar of the browser you find the substack address
29+
in the URL bar of the browser you find the substack address
2630
followed by your USER_ID and your username:
2731
https://substack.com/profile/[USER_ID]-[username]
2832

29-
3033
The .env file will be ignored by git but always be careful.
34+
35+
---
36+
37+
# Usage
38+
39+
```python
40+
import os
41+
42+
from substack import Api
43+
from substack.post import Post
44+
45+
api = Api(
46+
email=os.getenv("EMAIL"),
47+
password=os.getenv("PASSWORD"),
48+
publication_url=os.getenv("PUBLICATION_URL"),
49+
)
50+
51+
post = Post(
52+
title="How to publish a Substack post using the Python API",
53+
subtitle="This post was published using the Python API",
54+
user_id=os.getenv("USER_ID")
55+
)
56+
57+
post.add({'type': 'paragraph', 'content': 'This is how you add a new paragraph to your post!'})
58+
59+
draft = api.post_draft(post.get_draft())
60+
61+
api.prepublish_draft(draft.get("id"))
62+
63+
api.publish_draft(draft.get("id"))
64+
```
65+

‎examples/publish_post.py‎

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,18 @@
1010
load_dotenv()
1111

1212
if __name__ == "__main__":
13-
1413
parser = argparse.ArgumentParser()
15-
parser.add_argument("-p", "--post", default="draft.yaml", required=False,
16-
help="YAML file containing the post to publish.", type=str)
17-
parser.add_argument("--publish", help="Publish the draft.", action="store_true", default=False)
14+
parser.add_argument(
15+
"-p",
16+
"--post",
17+
default="draft.yaml",
18+
required=False,
19+
help="YAML file containing the post to publish.",
20+
type=str,
21+
)
22+
parser.add_argument(
23+
"--publish", help="Publish the draft.", action="store_true", default=False
24+
)
1825
args = parser.parse_args()
1926

2027
with open(args.post, "r") as fp:
@@ -26,11 +33,15 @@
2633
publication_url=os.getenv("PUBLICATION_URL"),
2734
)
2835

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"))
36+
post = Post(
37+
post_data.get("title"),
38+
post_data.get("subtitle", ""),
39+
os.getenv("USER_ID"),
40+
audience=post_data.get("audience", "everyone"),
41+
write_comment_permissions=post_data.get(
42+
"write_comment_permissions", "everyone"
43+
),
44+
)
3445

3546
body = post_data.get("body", {})
3647

‎substack/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
__email__ = "mazzapaolo2019@gmail.com"
55
__license__ = "MIT License"
66
__version__ = "1.0"
7-
__url__ = "https://github.com/hogier/python-substack"
7+
__url__ = "https://github.com/ma2za/python-substack"
88
__download_url__ = "https://pypi.python.org/pypi/python-substack"
99
__description__ = "A Python wrapper around the Substack API"
1010

‎substack/api.py‎

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
logger = logging.getLogger(__name__)
1212

13+
__all__ = ["Api"]
14+
1315

1416
class Api:
1517
"""
@@ -19,12 +21,12 @@ class Api:
1921
"""
2022

2123
def __init__(
22-
self,
23-
email=None,
24-
password=None,
25-
base_url=None,
26-
publication_url=None,
27-
debug=False,
24+
self,
25+
email=None,
26+
password=None,
27+
base_url=None,
28+
publication_url=None,
29+
debug=False,
2830
):
2931
"""
3032
@@ -116,9 +118,7 @@ def get_drafts(self, filter=None, offset=None, limit=None):
116118
return Api._handle_response(response=response)
117119

118120
def delete_draft(self, draft_id):
119-
response = self._session.delete(
120-
f"{self.publication_url}/drafts/{draft_id}"
121-
)
121+
response = self._session.delete(f"{self.publication_url}/drafts/{draft_id}")
122122
return Api._handle_response(response=response)
123123

124124
def post_draft(self, body) -> dict:
@@ -134,12 +134,12 @@ def post_draft(self, body) -> dict:
134134
return Api._handle_response(response=response)
135135

136136
def put_draft(
137-
self,
138-
draft,
139-
title=None,
140-
subtitle=None,
141-
body=None,
142-
cover_image=None,
137+
self,
138+
draft,
139+
title=None,
140+
subtitle=None,
141+
body=None,
142+
cover_image=None,
143143
) -> dict:
144144
"""
145145
@@ -181,7 +181,7 @@ def prepublish_draft(self, draft) -> dict:
181181
return Api._handle_response(response=response)
182182

183183
def publish_draft(
184-
self, draft, send: bool = True, share_automatically: bool = False
184+
self, draft, send: bool = True, share_automatically: bool = False
185185
) -> dict:
186186
"""
187187
@@ -211,7 +211,7 @@ def schedule_draft(self, draft, draft_datetime: datetime) -> dict:
211211
"""
212212
response = self._session.post(
213213
f"{self.publication_url}/drafts/{draft}/schedule",
214-
json={"post_date": draft_datetime.isoformat()}
214+
json={"post_date": draft_datetime.isoformat()},
215215
)
216216
return Api._handle_response(response=response)
217217

@@ -225,8 +225,7 @@ def unschedule_draft(self, draft) -> dict:
225225
226226
"""
227227
response = self._session.post(
228-
f"{self.publication_url}/drafts/{draft}/schedule",
229-
json={"post_date": None}
228+
f"{self.publication_url}/drafts/{draft}/schedule", json={"post_date": None}
230229
)
231230
return Api._handle_response(response=response)
232231

@@ -247,9 +246,7 @@ def get_image(self, image: str):
247246

248247
response = self._session.post(
249248
f"{self.publication_url}/image",
250-
data={
251-
"image": image
252-
},
249+
data={"image": image},
253250
)
254251
return Api._handle_response(response=response)
255252

@@ -265,12 +262,13 @@ def get_categories(self):
265262
return Api._handle_response(response=response)
266263

267264
def get_category(self, category_id, category_type, page):
268-
response = self._session.get(f"{self.base_url}/category/public/{category_id}/{category_type}",
269-
params={"page": page})
265+
response = self._session.get(
266+
f"{self.base_url}/category/public/{category_id}/{category_type}",
267+
params={"page": page},
268+
)
270269
return Api._handle_response(response=response)
271270

272-
def get_single_category(self, category_id, category_type, page=None,
273-
limit=None):
271+
def get_single_category(self, category_id, category_type, page=None, limit=None):
274272
"""
275273
276274
Args:
@@ -290,13 +288,15 @@ def get_single_category(self, category_id, category_type, page=None,
290288
while True:
291289
page_output = self.get_category(category_id, category_type, page)
292290
publications.extend(page_output.get("publications", []))
293-
if (limit is not None and limit <= len(publications)) or not page_output.get("more", False):
291+
if (
292+
limit is not None and limit <= len(publications)
293+
) or not page_output.get("more", False):
294294
publications = publications[:limit]
295295
break
296296
page += 1
297297
output = {
298298
"publications": publications,
299-
"more": page_output.get("more", False)
299+
"more": page_output.get("more", False),
300300
}
301301
return output
302302

0 commit comments

Comments
 (0)