zapostit-api 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.
- zapostit_api-0.2.0/.github/workflows/publish.yml +37 -0
- zapostit_api-0.2.0/.gitignore +8 -0
- zapostit_api-0.2.0/LICENSE +21 -0
- zapostit_api-0.2.0/PKG-INFO +205 -0
- zapostit_api-0.2.0/README.md +187 -0
- zapostit_api-0.2.0/README.ru.md +187 -0
- zapostit_api-0.2.0/pyproject.toml +47 -0
- zapostit_api-0.2.0/src/zapostit/__init__.py +86 -0
- zapostit_api-0.2.0/src/zapostit/client.py +886 -0
- zapostit_api-0.2.0/src/zapostit/codec.py +295 -0
- zapostit_api-0.2.0/src/zapostit/entities.py +80 -0
- zapostit_api-0.2.0/src/zapostit/errors.py +51 -0
- zapostit_api-0.2.0/src/zapostit/homepage.py +174 -0
- zapostit_api-0.2.0/src/zapostit/mappers.py +323 -0
- zapostit_api-0.2.0/src/zapostit/media.py +216 -0
- zapostit_api-0.2.0/src/zapostit/models.py +322 -0
- zapostit_api-0.2.0/src/zapostit/py.typed +1 -0
- zapostit_api-0.2.0/src/zapostit/transport.py +574 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.13"
|
|
16
|
+
|
|
17
|
+
- run: python -m pip install --upgrade build
|
|
18
|
+
- run: python -m build
|
|
19
|
+
|
|
20
|
+
- uses: actions/upload-artifact@v4
|
|
21
|
+
with:
|
|
22
|
+
name: python-package-distributions
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
publish:
|
|
26
|
+
needs: build
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
environment: pypi
|
|
29
|
+
permissions:
|
|
30
|
+
id-token: write
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/download-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: python-package-distributions
|
|
35
|
+
path: dist/
|
|
36
|
+
|
|
37
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yaroslav
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: zapostit-api
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Typed Python client for zapostit.com
|
|
5
|
+
Project-URL: Repository, https://github.com/yar2slav/zapostit-api
|
|
6
|
+
Project-URL: Documentation, https://github.com/yar2slav/zapostit-api#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/yar2slav/zapostit-api/issues
|
|
8
|
+
Author: yaroslav
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Requires-Dist: httpx<1,>=0.27
|
|
13
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
16
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# zapostit-api
|
|
20
|
+
|
|
21
|
+
[русская версия](README.ru.md)
|
|
22
|
+
|
|
23
|
+
typed python client for zapostit.com with sync and async apis
|
|
24
|
+
|
|
25
|
+
it reads authors, posts, comments, replies, polls and media links. authenticated sessions can create comments, reply, toggle reactions and delete their own comments
|
|
26
|
+
|
|
27
|
+
## installation
|
|
28
|
+
|
|
29
|
+
python 3.11 or newer is required
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install "zapostit-api @ git+ssh://git@github.com/yar2slav/zapostit-api.git@v0.2.0"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
local editable install:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone git@github.com:yar2slav/zapostit-api.git
|
|
39
|
+
cd zapostit-api
|
|
40
|
+
pip install -e ".[dev]"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## basic usage
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from zapostit import Zapostit
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
with Zapostit() as api:
|
|
50
|
+
author = api.get_author("slivach")
|
|
51
|
+
print(author.name, api.get_post_count(author.id))
|
|
52
|
+
|
|
53
|
+
for post in api.iter_posts(author.slug, max_posts=20):
|
|
54
|
+
print(post.created_at, post.url)
|
|
55
|
+
print(post.text_with_links)
|
|
56
|
+
|
|
57
|
+
for media in post.media:
|
|
58
|
+
print(media.kind, media.url)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`post.text` contains the original text. `post.text_with_links` shows hidden hyperlink targets next to the linked text
|
|
62
|
+
|
|
63
|
+
## pages and search
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
page = api.get_posts_page("slivach", limit=10)
|
|
67
|
+
|
|
68
|
+
for post in page.items:
|
|
69
|
+
print(post.id)
|
|
70
|
+
|
|
71
|
+
next_page = api.get_posts_page(
|
|
72
|
+
"slivach",
|
|
73
|
+
cursor=page.next_cursor,
|
|
74
|
+
limit=10,
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`iter_posts()` handles cursors and duplicate ids automatically
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
for post in api.search_posts("pozdnyakov", "Черногория"):
|
|
82
|
+
print(post.url, post.text_with_links)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## comments
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
for comment in api.iter_comments(post_id=104459, sort="newest"):
|
|
89
|
+
print(comment.author.name, comment.text_with_links)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
comments can also be returned as a tree:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
threads = api.get_comment_threads(104459)
|
|
96
|
+
|
|
97
|
+
for thread in threads:
|
|
98
|
+
print(thread.comment.text)
|
|
99
|
+
for reply in thread.replies:
|
|
100
|
+
print(" ", reply.comment.text)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## media
|
|
104
|
+
|
|
105
|
+
the library returns public urls and metadata without downloading files
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
for media in post.media:
|
|
109
|
+
print(media.kind, media.url, media.thumbnail_url)
|
|
110
|
+
|
|
111
|
+
for variant in media.variants:
|
|
112
|
+
print(variant.type, variant.width, variant.height, variant.url)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
photos, albums, videos, voice messages, audio, documents and polls are supported
|
|
116
|
+
|
|
117
|
+
## polling
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
with Zapostit() as api:
|
|
121
|
+
for post in api.watch_posts("slivach", interval=30):
|
|
122
|
+
print("new post:", post.url)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
the first request creates a baseline. pass `emit_existing=True` to receive the current first page immediately
|
|
126
|
+
|
|
127
|
+
## authenticated actions
|
|
128
|
+
|
|
129
|
+
an existing session token can be passed through an environment variable:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
import os
|
|
133
|
+
|
|
134
|
+
from zapostit import Zapostit
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
with Zapostit(session_token=os.environ["ZAPOSTIT_SESSION_TOKEN"]) as api:
|
|
138
|
+
print(api.get_session().user.login)
|
|
139
|
+
|
|
140
|
+
comment = api.create_comment(104459, "hello")
|
|
141
|
+
reply = api.reply_to_comment(104459, comment.id, "reply")
|
|
142
|
+
|
|
143
|
+
api.toggle_reaction(104459, "post", emoji_id=6)
|
|
144
|
+
api.toggle_reaction(comment.id, "comment", emoji_id=0)
|
|
145
|
+
|
|
146
|
+
api.delete_comment(reply.id)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
mutation requests are sent once and are not retried automatically
|
|
150
|
+
|
|
151
|
+
## async usage
|
|
152
|
+
|
|
153
|
+
`AsyncZapostit` has the same method names. iterators become async iterators
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
import asyncio
|
|
157
|
+
|
|
158
|
+
from zapostit import AsyncZapostit
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
async def main() -> None:
|
|
162
|
+
async with AsyncZapostit() as api:
|
|
163
|
+
async for post in api.iter_posts("slivach", max_posts=20):
|
|
164
|
+
print(post.url)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
asyncio.run(main())
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## main methods
|
|
171
|
+
|
|
172
|
+
- `get_authors()`, `get_author()`, `get_post_count()`
|
|
173
|
+
- `get_posts_page()`, `iter_posts()`, `search_posts()`, `iter_all_posts()`
|
|
174
|
+
- `get_comments_page()`, `get_replies_page()`, `iter_comments()`
|
|
175
|
+
- `get_comment_threads()`, `get_poll_results()`
|
|
176
|
+
- `watch_posts()`
|
|
177
|
+
- `login()`, `get_session()`
|
|
178
|
+
- `create_comment()`, `reply_to_comment()`, `delete_comment()`
|
|
179
|
+
- `toggle_reaction()`
|
|
180
|
+
|
|
181
|
+
models are frozen pydantic models. use `model_dump()` or `model_dump_json()` for serialization. unknown upstream fields are kept in `raw`
|
|
182
|
+
|
|
183
|
+
## errors
|
|
184
|
+
|
|
185
|
+
all library errors inherit from `ZapostitError`
|
|
186
|
+
|
|
187
|
+
- `ApiError`
|
|
188
|
+
- `AuthenticationError`
|
|
189
|
+
- `RateLimitError`
|
|
190
|
+
- `DecodeError`
|
|
191
|
+
- `NotFoundError`
|
|
192
|
+
|
|
193
|
+
read requests use bounded retries for network errors, `429` and `5xx` responses
|
|
194
|
+
|
|
195
|
+
## development
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
ruff format --check src
|
|
199
|
+
ruff check src
|
|
200
|
+
mypy --strict src/zapostit
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## license
|
|
204
|
+
|
|
205
|
+
[mit](LICENSE). commercial use, modification, distribution, sublicensing and private use are allowed
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# zapostit-api
|
|
2
|
+
|
|
3
|
+
[русская версия](README.ru.md)
|
|
4
|
+
|
|
5
|
+
typed python client for zapostit.com with sync and async apis
|
|
6
|
+
|
|
7
|
+
it reads authors, posts, comments, replies, polls and media links. authenticated sessions can create comments, reply, toggle reactions and delete their own comments
|
|
8
|
+
|
|
9
|
+
## installation
|
|
10
|
+
|
|
11
|
+
python 3.11 or newer is required
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install "zapostit-api @ git+ssh://git@github.com/yar2slav/zapostit-api.git@v0.2.0"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
local editable install:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone git@github.com:yar2slav/zapostit-api.git
|
|
21
|
+
cd zapostit-api
|
|
22
|
+
pip install -e ".[dev]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## basic usage
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from zapostit import Zapostit
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
with Zapostit() as api:
|
|
32
|
+
author = api.get_author("slivach")
|
|
33
|
+
print(author.name, api.get_post_count(author.id))
|
|
34
|
+
|
|
35
|
+
for post in api.iter_posts(author.slug, max_posts=20):
|
|
36
|
+
print(post.created_at, post.url)
|
|
37
|
+
print(post.text_with_links)
|
|
38
|
+
|
|
39
|
+
for media in post.media:
|
|
40
|
+
print(media.kind, media.url)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`post.text` contains the original text. `post.text_with_links` shows hidden hyperlink targets next to the linked text
|
|
44
|
+
|
|
45
|
+
## pages and search
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
page = api.get_posts_page("slivach", limit=10)
|
|
49
|
+
|
|
50
|
+
for post in page.items:
|
|
51
|
+
print(post.id)
|
|
52
|
+
|
|
53
|
+
next_page = api.get_posts_page(
|
|
54
|
+
"slivach",
|
|
55
|
+
cursor=page.next_cursor,
|
|
56
|
+
limit=10,
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`iter_posts()` handles cursors and duplicate ids automatically
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
for post in api.search_posts("pozdnyakov", "Черногория"):
|
|
64
|
+
print(post.url, post.text_with_links)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## comments
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
for comment in api.iter_comments(post_id=104459, sort="newest"):
|
|
71
|
+
print(comment.author.name, comment.text_with_links)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
comments can also be returned as a tree:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
threads = api.get_comment_threads(104459)
|
|
78
|
+
|
|
79
|
+
for thread in threads:
|
|
80
|
+
print(thread.comment.text)
|
|
81
|
+
for reply in thread.replies:
|
|
82
|
+
print(" ", reply.comment.text)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## media
|
|
86
|
+
|
|
87
|
+
the library returns public urls and metadata without downloading files
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
for media in post.media:
|
|
91
|
+
print(media.kind, media.url, media.thumbnail_url)
|
|
92
|
+
|
|
93
|
+
for variant in media.variants:
|
|
94
|
+
print(variant.type, variant.width, variant.height, variant.url)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
photos, albums, videos, voice messages, audio, documents and polls are supported
|
|
98
|
+
|
|
99
|
+
## polling
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
with Zapostit() as api:
|
|
103
|
+
for post in api.watch_posts("slivach", interval=30):
|
|
104
|
+
print("new post:", post.url)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
the first request creates a baseline. pass `emit_existing=True` to receive the current first page immediately
|
|
108
|
+
|
|
109
|
+
## authenticated actions
|
|
110
|
+
|
|
111
|
+
an existing session token can be passed through an environment variable:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import os
|
|
115
|
+
|
|
116
|
+
from zapostit import Zapostit
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
with Zapostit(session_token=os.environ["ZAPOSTIT_SESSION_TOKEN"]) as api:
|
|
120
|
+
print(api.get_session().user.login)
|
|
121
|
+
|
|
122
|
+
comment = api.create_comment(104459, "hello")
|
|
123
|
+
reply = api.reply_to_comment(104459, comment.id, "reply")
|
|
124
|
+
|
|
125
|
+
api.toggle_reaction(104459, "post", emoji_id=6)
|
|
126
|
+
api.toggle_reaction(comment.id, "comment", emoji_id=0)
|
|
127
|
+
|
|
128
|
+
api.delete_comment(reply.id)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
mutation requests are sent once and are not retried automatically
|
|
132
|
+
|
|
133
|
+
## async usage
|
|
134
|
+
|
|
135
|
+
`AsyncZapostit` has the same method names. iterators become async iterators
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import asyncio
|
|
139
|
+
|
|
140
|
+
from zapostit import AsyncZapostit
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def main() -> None:
|
|
144
|
+
async with AsyncZapostit() as api:
|
|
145
|
+
async for post in api.iter_posts("slivach", max_posts=20):
|
|
146
|
+
print(post.url)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
asyncio.run(main())
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## main methods
|
|
153
|
+
|
|
154
|
+
- `get_authors()`, `get_author()`, `get_post_count()`
|
|
155
|
+
- `get_posts_page()`, `iter_posts()`, `search_posts()`, `iter_all_posts()`
|
|
156
|
+
- `get_comments_page()`, `get_replies_page()`, `iter_comments()`
|
|
157
|
+
- `get_comment_threads()`, `get_poll_results()`
|
|
158
|
+
- `watch_posts()`
|
|
159
|
+
- `login()`, `get_session()`
|
|
160
|
+
- `create_comment()`, `reply_to_comment()`, `delete_comment()`
|
|
161
|
+
- `toggle_reaction()`
|
|
162
|
+
|
|
163
|
+
models are frozen pydantic models. use `model_dump()` or `model_dump_json()` for serialization. unknown upstream fields are kept in `raw`
|
|
164
|
+
|
|
165
|
+
## errors
|
|
166
|
+
|
|
167
|
+
all library errors inherit from `ZapostitError`
|
|
168
|
+
|
|
169
|
+
- `ApiError`
|
|
170
|
+
- `AuthenticationError`
|
|
171
|
+
- `RateLimitError`
|
|
172
|
+
- `DecodeError`
|
|
173
|
+
- `NotFoundError`
|
|
174
|
+
|
|
175
|
+
read requests use bounded retries for network errors, `429` and `5xx` responses
|
|
176
|
+
|
|
177
|
+
## development
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
ruff format --check src
|
|
181
|
+
ruff check src
|
|
182
|
+
mypy --strict src/zapostit
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## license
|
|
186
|
+
|
|
187
|
+
[mit](LICENSE). commercial use, modification, distribution, sublicensing and private use are allowed
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# zapostit-api
|
|
2
|
+
|
|
3
|
+
[english version](README.md)
|
|
4
|
+
|
|
5
|
+
типизированный python-клиент для zapostit.com с синхронным и асинхронным api
|
|
6
|
+
|
|
7
|
+
умеет получать авторов, посты, комментарии, ответы, опросы и ссылки на медиа. после авторизации можно писать комментарии, отвечать, ставить реакции и удалять свои комментарии
|
|
8
|
+
|
|
9
|
+
## установка
|
|
10
|
+
|
|
11
|
+
нужен python 3.11 или новее
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install "zapostit-api @ git+ssh://git@github.com/yar2slav/zapostit-api.git@v0.2.0"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
локальная установка для разработки:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone git@github.com:yar2slav/zapostit-api.git
|
|
21
|
+
cd zapostit-api
|
|
22
|
+
pip install -e ".[dev]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## базовый пример
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from zapostit import Zapostit
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
with Zapostit() as api:
|
|
32
|
+
author = api.get_author("slivach")
|
|
33
|
+
print(author.name, api.get_post_count(author.id))
|
|
34
|
+
|
|
35
|
+
for post in api.iter_posts(author.slug, max_posts=20):
|
|
36
|
+
print(post.created_at, post.url)
|
|
37
|
+
print(post.text_with_links)
|
|
38
|
+
|
|
39
|
+
for media in post.media:
|
|
40
|
+
print(media.kind, media.url)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`post.text` содержит исходный текст. `post.text_with_links` показывает адреса скрытых гиперссылок рядом с текстом, на котором они стоят
|
|
44
|
+
|
|
45
|
+
## страницы и поиск
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
page = api.get_posts_page("slivach", limit=10)
|
|
49
|
+
|
|
50
|
+
for post in page.items:
|
|
51
|
+
print(post.id)
|
|
52
|
+
|
|
53
|
+
next_page = api.get_posts_page(
|
|
54
|
+
"slivach",
|
|
55
|
+
cursor=page.next_cursor,
|
|
56
|
+
limit=10,
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`iter_posts()` сам обрабатывает курсоры и убирает повторяющиеся id
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
for post in api.search_posts("pozdnyakov", "Черногория"):
|
|
64
|
+
print(post.url, post.text_with_links)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## комментарии
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
for comment in api.iter_comments(post_id=104459, sort="newest"):
|
|
71
|
+
print(comment.author.name, comment.text_with_links)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
комментарии можно получить готовым деревом:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
threads = api.get_comment_threads(104459)
|
|
78
|
+
|
|
79
|
+
for thread in threads:
|
|
80
|
+
print(thread.comment.text)
|
|
81
|
+
for reply in thread.replies:
|
|
82
|
+
print(" ", reply.comment.text)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## медиа
|
|
86
|
+
|
|
87
|
+
библиотека возвращает публичные ссылки и метаданные без скачивания файлов
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
for media in post.media:
|
|
91
|
+
print(media.kind, media.url, media.thumbnail_url)
|
|
92
|
+
|
|
93
|
+
for variant in media.variants:
|
|
94
|
+
print(variant.type, variant.width, variant.height, variant.url)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
поддерживаются фото, альбомы, видео, голосовые сообщения, аудио, документы и опросы
|
|
98
|
+
|
|
99
|
+
## поллинг
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
with Zapostit() as api:
|
|
103
|
+
for post in api.watch_posts("slivach", interval=30):
|
|
104
|
+
print("новый пост:", post.url)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
первый запрос создаёт исходную точку. `emit_existing=True` сразу вернёт текущую первую страницу
|
|
108
|
+
|
|
109
|
+
## действия после авторизации
|
|
110
|
+
|
|
111
|
+
готовый токен сессии можно передать через переменную окружения:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import os
|
|
115
|
+
|
|
116
|
+
from zapostit import Zapostit
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
with Zapostit(session_token=os.environ["ZAPOSTIT_SESSION_TOKEN"]) as api:
|
|
120
|
+
print(api.get_session().user.login)
|
|
121
|
+
|
|
122
|
+
comment = api.create_comment(104459, "hello")
|
|
123
|
+
reply = api.reply_to_comment(104459, comment.id, "reply")
|
|
124
|
+
|
|
125
|
+
api.toggle_reaction(104459, "post", emoji_id=6)
|
|
126
|
+
api.toggle_reaction(comment.id, "comment", emoji_id=0)
|
|
127
|
+
|
|
128
|
+
api.delete_comment(reply.id)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
запросы на изменение данных отправляются один раз и автоматически не повторяются
|
|
132
|
+
|
|
133
|
+
## асинхронное использование
|
|
134
|
+
|
|
135
|
+
`AsyncZapostit` использует те же названия методов. обычные итераторы становятся асинхронными
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import asyncio
|
|
139
|
+
|
|
140
|
+
from zapostit import AsyncZapostit
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def main() -> None:
|
|
144
|
+
async with AsyncZapostit() as api:
|
|
145
|
+
async for post in api.iter_posts("slivach", max_posts=20):
|
|
146
|
+
print(post.url)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
asyncio.run(main())
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## основные методы
|
|
153
|
+
|
|
154
|
+
- `get_authors()`, `get_author()`, `get_post_count()`
|
|
155
|
+
- `get_posts_page()`, `iter_posts()`, `search_posts()`, `iter_all_posts()`
|
|
156
|
+
- `get_comments_page()`, `get_replies_page()`, `iter_comments()`
|
|
157
|
+
- `get_comment_threads()`, `get_poll_results()`
|
|
158
|
+
- `watch_posts()`
|
|
159
|
+
- `login()`, `get_session()`
|
|
160
|
+
- `create_comment()`, `reply_to_comment()`, `delete_comment()`
|
|
161
|
+
- `toggle_reaction()`
|
|
162
|
+
|
|
163
|
+
модели сделаны на pydantic и не изменяются после создания. для сериализации используются `model_dump()` и `model_dump_json()`. неизвестные поля ответа сохраняются в `raw`
|
|
164
|
+
|
|
165
|
+
## ошибки
|
|
166
|
+
|
|
167
|
+
все ошибки библиотеки наследуются от `ZapostitError`
|
|
168
|
+
|
|
169
|
+
- `ApiError`
|
|
170
|
+
- `AuthenticationError`
|
|
171
|
+
- `RateLimitError`
|
|
172
|
+
- `DecodeError`
|
|
173
|
+
- `NotFoundError`
|
|
174
|
+
|
|
175
|
+
запросы на чтение ограниченно повторяются при сетевых ошибках, ответах `429` и `5xx`
|
|
176
|
+
|
|
177
|
+
## разработка
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
ruff format --check src
|
|
181
|
+
ruff check src
|
|
182
|
+
mypy --strict src/zapostit
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## лицензия
|
|
186
|
+
|
|
187
|
+
[mit](LICENSE). разрешены коммерческое использование, изменение, распространение, сублицензирование и приватное использование
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zapostit-api"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Typed Python client for zapostit.com"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "yaroslav" },
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"httpx>=0.27,<1",
|
|
17
|
+
"pydantic>=2.7,<3",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Repository = "https://github.com/yar2slav/zapostit-api"
|
|
22
|
+
Documentation = "https://github.com/yar2slav/zapostit-api#readme"
|
|
23
|
+
Issues = "https://github.com/yar2slav/zapostit-api/issues"
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
dev = [
|
|
27
|
+
"mypy>=1.11",
|
|
28
|
+
"ruff>=0.6",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[tool.hatch.build.targets.wheel]
|
|
32
|
+
packages = ["src/zapostit"]
|
|
33
|
+
|
|
34
|
+
[tool.ruff]
|
|
35
|
+
target-version = "py311"
|
|
36
|
+
line-length = 100
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint]
|
|
39
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
40
|
+
allowed-confusables = ["с", "о"]
|
|
41
|
+
|
|
42
|
+
[tool.mypy]
|
|
43
|
+
python_version = "3.11"
|
|
44
|
+
strict = true
|
|
45
|
+
plugins = ["pydantic.mypy"]
|
|
46
|
+
packages = ["zapostit"]
|
|
47
|
+
mypy_path = "src"
|