ssky 0.1.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.
- ssky-0.1.0/LICENSE +21 -0
- ssky-0.1.0/PKG-INFO +213 -0
- ssky-0.1.0/README.md +190 -0
- ssky-0.1.0/pyproject.toml +26 -0
- ssky-0.1.0/src/ssky/__init__.py +0 -0
- ssky-0.1.0/src/ssky/delete.py +25 -0
- ssky-0.1.0/src/ssky/follow.py +20 -0
- ssky-0.1.0/src/ssky/get.py +54 -0
- ssky-0.1.0/src/ssky/login.py +18 -0
- ssky-0.1.0/src/ssky/main.py +127 -0
- ssky-0.1.0/src/ssky/post.py +302 -0
- ssky-0.1.0/src/ssky/post_data_list.py +144 -0
- ssky-0.1.0/src/ssky/profile.py +20 -0
- ssky-0.1.0/src/ssky/profile_list.py +124 -0
- ssky-0.1.0/src/ssky/repost.py +32 -0
- ssky-0.1.0/src/ssky/search.py +53 -0
- ssky-0.1.0/src/ssky/ssky_session.py +112 -0
- ssky-0.1.0/src/ssky/unfollow.py +28 -0
- ssky-0.1.0/src/ssky/unrepost.py +41 -0
- ssky-0.1.0/src/ssky/user.py +27 -0
- ssky-0.1.0/src/ssky/util.py +20 -0
ssky-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 simpleskyclient
|
|
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.
|
ssky-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ssky
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Simple bluesky client
|
|
5
|
+
Home-page: https://github.com/simpleskyclient/ssky
|
|
6
|
+
License: LICENSE
|
|
7
|
+
Keywords: bluesky,client
|
|
8
|
+
Author: SimpleSkyClient Project
|
|
9
|
+
Author-email: simpleskypclient@gmail.com
|
|
10
|
+
Requires-Python: >=3.12,<3.14
|
|
11
|
+
Classifier: License :: Other/Proprietary License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: atproto (>=0.0.55,<0.0.56)
|
|
16
|
+
Requires-Dist: beautifulsoup4 (>=4.12.3,<5.0.0)
|
|
17
|
+
Requires-Dist: pytest (>=8.3.4,<9.0.0)
|
|
18
|
+
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
19
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
20
|
+
Project-URL: Repository, https://github.com/simpleskyclient/ssky
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# ssky - Simple Bluesky client
|
|
24
|
+
|
|
25
|
+
## Introduction
|
|
26
|
+
|
|
27
|
+
Ssky is a simple Bluesky client, providing some specific features.
|
|
28
|
+
|
|
29
|
+
* Simple but Linux shell friendly user interface
|
|
30
|
+
* You can give `URI` or `URI::CID` to retrieve (get), quote, reply-to, repost/unrepost and delete a unique post
|
|
31
|
+
* You can give `DID` or `handle` to retrieve timeline/posts/profile, follow/unfollow a unique user
|
|
32
|
+
* You can get simply 'URI:CID' for posts and 'DID' for users when you retrieve (get) them, so you can use them for Linux pipeline or command substitution
|
|
33
|
+
* Various output options:
|
|
34
|
+
* Only unique identifier such as `URI::CID` or `DID`, for Linux pipeline or command substitution ([See Samples](#samples) )
|
|
35
|
+
* Line oriented output with identifier and human friendly text, for listing many records
|
|
36
|
+
* Multiline output with full texts of some attributes, for reading details
|
|
37
|
+
* JSON output, for preserving record structure derived from atproto library
|
|
38
|
+
* Some subcommands such as `get` and `search` allow to output to files per records
|
|
39
|
+
|
|
40
|
+
### Requirements
|
|
41
|
+
|
|
42
|
+
* Python 3.12 or later
|
|
43
|
+
|
|
44
|
+
### Install from github repository
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install git+https://github.com/simpleskyclient/ssky.git
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
Ssky's behavior is specified by subcommand and options like `ssky subcommand [options]`.
|
|
53
|
+
|
|
54
|
+
### Common options and names
|
|
55
|
+
|
|
56
|
+
* Common option -D, --delimiter: Delimiter string in output
|
|
57
|
+
* Common option -I, --id: Identifier only such as `URI::CID` or `DID`, depending on context
|
|
58
|
+
* Common option -T, --text: Text only such as main text in post or description in user profile
|
|
59
|
+
* Common option -L, --long: Long output
|
|
60
|
+
* Common option -J, --json: JSON output
|
|
61
|
+
* Common option -N NUM, --limit NUM: MAX result counts
|
|
62
|
+
* Common option -O DIR, --output DIR: Output to files in the specified directory
|
|
63
|
+
* Common name "myself": replace with login user DID or handle automatically
|
|
64
|
+
|
|
65
|
+
### Login bluesky
|
|
66
|
+
|
|
67
|
+
First or all, you must log in the Bluesky.
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
ssky login handle password
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
*Handle* and *password* are formatted like `xxxx.bsky.social` and `xxxx-xxxxx-xxxx-xxxx`, respectively.
|
|
74
|
+
|
|
75
|
+
Once you have logged in, ssky remembers the login session in local environment (`~/.ssky`).
|
|
76
|
+
However, you must log in again when ssky reports session timeout error like "400 Token has been revoked".
|
|
77
|
+
|
|
78
|
+
You can also set Bluesky handle and password in environment variable `SSKY_USER`, separated by ':' like `handle:password`.
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
export SSKY_USER=user.bsky.social:xxxx-xxxxx-xxxx-xxxx
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The environment variable overrides command line arguments, so you will login by the user alpha in the following example.
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
SSKY_USER=alpha:password1 ssky login bravo password2
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Get posts
|
|
91
|
+
|
|
92
|
+
Get subcommand retrieves your timeline, another author's feed by handle or `DID`, and a post by `URI` or `URI::CID`.
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
ssky get # Get your timeline
|
|
96
|
+
ssky get handle # Get other author's feed by handle, such as user.bsky.social
|
|
97
|
+
ssky get did:... # Get other author's feed by DID
|
|
98
|
+
ssky get at://... # Get a post specified by URI
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Get profile
|
|
102
|
+
|
|
103
|
+
Profile subcommand retrieves the user profile from handle or display name.
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
ssky profile user.bsky.social
|
|
107
|
+
ssky profile 'Display Name'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Post
|
|
111
|
+
|
|
112
|
+
Post subcommand sends a post. You can give the message by command line argument or the standard input. Tags, link cards, mentions, quotations, reply-to and attached images are available.
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
ssky post Hello # Post from command line text
|
|
116
|
+
echo Hello | ssky post # Post from /dev/stdin
|
|
117
|
+
ssky post 'Hello, #bluesky @atproto.com https://bsky.app/' # Post with tags, mentions, and embed link card
|
|
118
|
+
ssky post 'Hello, bluesky!' --image dir1/hello1.png --image dir2/hello2.png # Post with images
|
|
119
|
+
ssky post 'Hello, bluesky!' --quote at://... # Quote the post
|
|
120
|
+
ssky post 'Hello, bluesky!' --reply-to at://... # Reply to the post
|
|
121
|
+
|
|
122
|
+
ssky post Hello --dry # Dry run
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Search posts
|
|
126
|
+
|
|
127
|
+
Search subcommand searches posts.
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
ssky search foo # Search posts including 'foo'
|
|
131
|
+
ssky search foo --author handle # Search posts including 'foo' by the specified author
|
|
132
|
+
ssky search foo --since 20240101 --until 20241231 # Search posts including 'foo' in the specified period
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Delete post
|
|
136
|
+
|
|
137
|
+
Delete subcommand deletes a post.
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
ssky delete at://... # Delete the post
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Repost to post
|
|
144
|
+
|
|
145
|
+
Repost subcommand reposts the post.
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
ssky repost at://... # Repost the post
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Unrepost to post
|
|
152
|
+
|
|
153
|
+
Repost subcommand deletes the repost to a post.
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
ssky unrepost at://... # Delete your repost to the specified post
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Search users
|
|
160
|
+
|
|
161
|
+
User subcommand searches users.
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
ssky user foo # Search users including 'foo' in handle name and description
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Follow user
|
|
168
|
+
|
|
169
|
+
Follow subcommand follows a user.
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
ssky follow handle # Follow the user
|
|
173
|
+
ssky follow did:.. # Follow the user
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Unfollow user
|
|
177
|
+
|
|
178
|
+
Unfollow subcommand deletes the follow to the user.
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
ssky unfollow handle # Unfollow the user
|
|
182
|
+
ssky unfollow did:.. # Unfollow the user
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Samples
|
|
186
|
+
|
|
187
|
+
### Search keyword 'bluesky' in your posts
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
ssky search bluesky --author myself
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Save your last post in the directory './log'
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
ssky post 'My very important posted message'
|
|
197
|
+
ssky get myself --limit 1 --text --output ./log
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Reply to the last post by myself
|
|
201
|
+
|
|
202
|
+
```sh
|
|
203
|
+
ssky post 'Reply!' --reply-to $(ssky get myself --limit 1 --id)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
[MIT License](LICENSE)
|
|
209
|
+
|
|
210
|
+
## Author
|
|
211
|
+
|
|
212
|
+
[SimpleSkyClient Project](https://github.com/simpleskyclient)
|
|
213
|
+
|
ssky-0.1.0/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# ssky - Simple Bluesky client
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Ssky is a simple Bluesky client, providing some specific features.
|
|
6
|
+
|
|
7
|
+
* Simple but Linux shell friendly user interface
|
|
8
|
+
* You can give `URI` or `URI::CID` to retrieve (get), quote, reply-to, repost/unrepost and delete a unique post
|
|
9
|
+
* You can give `DID` or `handle` to retrieve timeline/posts/profile, follow/unfollow a unique user
|
|
10
|
+
* You can get simply 'URI:CID' for posts and 'DID' for users when you retrieve (get) them, so you can use them for Linux pipeline or command substitution
|
|
11
|
+
* Various output options:
|
|
12
|
+
* Only unique identifier such as `URI::CID` or `DID`, for Linux pipeline or command substitution ([See Samples](#samples) )
|
|
13
|
+
* Line oriented output with identifier and human friendly text, for listing many records
|
|
14
|
+
* Multiline output with full texts of some attributes, for reading details
|
|
15
|
+
* JSON output, for preserving record structure derived from atproto library
|
|
16
|
+
* Some subcommands such as `get` and `search` allow to output to files per records
|
|
17
|
+
|
|
18
|
+
### Requirements
|
|
19
|
+
|
|
20
|
+
* Python 3.12 or later
|
|
21
|
+
|
|
22
|
+
### Install from github repository
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install git+https://github.com/simpleskyclient/ssky.git
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Ssky's behavior is specified by subcommand and options like `ssky subcommand [options]`.
|
|
31
|
+
|
|
32
|
+
### Common options and names
|
|
33
|
+
|
|
34
|
+
* Common option -D, --delimiter: Delimiter string in output
|
|
35
|
+
* Common option -I, --id: Identifier only such as `URI::CID` or `DID`, depending on context
|
|
36
|
+
* Common option -T, --text: Text only such as main text in post or description in user profile
|
|
37
|
+
* Common option -L, --long: Long output
|
|
38
|
+
* Common option -J, --json: JSON output
|
|
39
|
+
* Common option -N NUM, --limit NUM: MAX result counts
|
|
40
|
+
* Common option -O DIR, --output DIR: Output to files in the specified directory
|
|
41
|
+
* Common name "myself": replace with login user DID or handle automatically
|
|
42
|
+
|
|
43
|
+
### Login bluesky
|
|
44
|
+
|
|
45
|
+
First or all, you must log in the Bluesky.
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
ssky login handle password
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
*Handle* and *password* are formatted like `xxxx.bsky.social` and `xxxx-xxxxx-xxxx-xxxx`, respectively.
|
|
52
|
+
|
|
53
|
+
Once you have logged in, ssky remembers the login session in local environment (`~/.ssky`).
|
|
54
|
+
However, you must log in again when ssky reports session timeout error like "400 Token has been revoked".
|
|
55
|
+
|
|
56
|
+
You can also set Bluesky handle and password in environment variable `SSKY_USER`, separated by ':' like `handle:password`.
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
export SSKY_USER=user.bsky.social:xxxx-xxxxx-xxxx-xxxx
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The environment variable overrides command line arguments, so you will login by the user alpha in the following example.
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
SSKY_USER=alpha:password1 ssky login bravo password2
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Get posts
|
|
69
|
+
|
|
70
|
+
Get subcommand retrieves your timeline, another author's feed by handle or `DID`, and a post by `URI` or `URI::CID`.
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
ssky get # Get your timeline
|
|
74
|
+
ssky get handle # Get other author's feed by handle, such as user.bsky.social
|
|
75
|
+
ssky get did:... # Get other author's feed by DID
|
|
76
|
+
ssky get at://... # Get a post specified by URI
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Get profile
|
|
80
|
+
|
|
81
|
+
Profile subcommand retrieves the user profile from handle or display name.
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
ssky profile user.bsky.social
|
|
85
|
+
ssky profile 'Display Name'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Post
|
|
89
|
+
|
|
90
|
+
Post subcommand sends a post. You can give the message by command line argument or the standard input. Tags, link cards, mentions, quotations, reply-to and attached images are available.
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
ssky post Hello # Post from command line text
|
|
94
|
+
echo Hello | ssky post # Post from /dev/stdin
|
|
95
|
+
ssky post 'Hello, #bluesky @atproto.com https://bsky.app/' # Post with tags, mentions, and embed link card
|
|
96
|
+
ssky post 'Hello, bluesky!' --image dir1/hello1.png --image dir2/hello2.png # Post with images
|
|
97
|
+
ssky post 'Hello, bluesky!' --quote at://... # Quote the post
|
|
98
|
+
ssky post 'Hello, bluesky!' --reply-to at://... # Reply to the post
|
|
99
|
+
|
|
100
|
+
ssky post Hello --dry # Dry run
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Search posts
|
|
104
|
+
|
|
105
|
+
Search subcommand searches posts.
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
ssky search foo # Search posts including 'foo'
|
|
109
|
+
ssky search foo --author handle # Search posts including 'foo' by the specified author
|
|
110
|
+
ssky search foo --since 20240101 --until 20241231 # Search posts including 'foo' in the specified period
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Delete post
|
|
114
|
+
|
|
115
|
+
Delete subcommand deletes a post.
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
ssky delete at://... # Delete the post
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Repost to post
|
|
122
|
+
|
|
123
|
+
Repost subcommand reposts the post.
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
ssky repost at://... # Repost the post
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Unrepost to post
|
|
130
|
+
|
|
131
|
+
Repost subcommand deletes the repost to a post.
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
ssky unrepost at://... # Delete your repost to the specified post
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Search users
|
|
138
|
+
|
|
139
|
+
User subcommand searches users.
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
ssky user foo # Search users including 'foo' in handle name and description
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Follow user
|
|
146
|
+
|
|
147
|
+
Follow subcommand follows a user.
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
ssky follow handle # Follow the user
|
|
151
|
+
ssky follow did:.. # Follow the user
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Unfollow user
|
|
155
|
+
|
|
156
|
+
Unfollow subcommand deletes the follow to the user.
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
ssky unfollow handle # Unfollow the user
|
|
160
|
+
ssky unfollow did:.. # Unfollow the user
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Samples
|
|
164
|
+
|
|
165
|
+
### Search keyword 'bluesky' in your posts
|
|
166
|
+
|
|
167
|
+
```sh
|
|
168
|
+
ssky search bluesky --author myself
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Save your last post in the directory './log'
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
ssky post 'My very important posted message'
|
|
175
|
+
ssky get myself --limit 1 --text --output ./log
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Reply to the last post by myself
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
ssky post 'Reply!' --reply-to $(ssky get myself --limit 1 --id)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
[MIT License](LICENSE)
|
|
187
|
+
|
|
188
|
+
## Author
|
|
189
|
+
|
|
190
|
+
[SimpleSkyClient Project](https://github.com/simpleskyclient)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "ssky"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Simple bluesky client"
|
|
5
|
+
authors = ["SimpleSkyClient Project <simpleskypclient@gmail.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = "LICENSE"
|
|
8
|
+
homepage = "https://github.com/simpleskyclient/ssky"
|
|
9
|
+
repository = "https://github.com/simpleskyclient/ssky"
|
|
10
|
+
keywords = ["bluesky", "client"]
|
|
11
|
+
packages = [{include = "ssky", from = "src"}]
|
|
12
|
+
|
|
13
|
+
[tool.poetry.dependencies]
|
|
14
|
+
python = ">=3.12,<3.14"
|
|
15
|
+
beautifulsoup4 = "^4.12.3"
|
|
16
|
+
python-dotenv = "^1.0.1"
|
|
17
|
+
requests = "^2.32.3"
|
|
18
|
+
atproto = "^0.0.55"
|
|
19
|
+
pytest = "^8.3.4"
|
|
20
|
+
|
|
21
|
+
[tool.poetry.scripts]
|
|
22
|
+
ssky = "ssky.main:main"
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["poetry-core"]
|
|
26
|
+
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import atproto_client
|
|
3
|
+
from ssky.ssky_session import ssky_client
|
|
4
|
+
from ssky.util import disjoin_uri_cid, is_joined_uri_cid
|
|
5
|
+
|
|
6
|
+
def delete(post, **kwargs) -> str:
|
|
7
|
+
if is_joined_uri_cid(post):
|
|
8
|
+
uri, _ = disjoin_uri_cid(post)
|
|
9
|
+
else:
|
|
10
|
+
uri = post
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
status = ssky_client().delete_post(uri)
|
|
14
|
+
if status is False:
|
|
15
|
+
print('Failed to delete', file=sys.stderr)
|
|
16
|
+
return None
|
|
17
|
+
return uri
|
|
18
|
+
except atproto_client.exceptions.AtProtocolError as e:
|
|
19
|
+
if 'response' in dir(e) and e.response is not None:
|
|
20
|
+
print(f'{e.response.status_code} {e.response.content.message}', file=sys.stderr)
|
|
21
|
+
elif str(e) is not None and len(str(e)) > 0:
|
|
22
|
+
print(f'{str(e)}', file=sys.stderr)
|
|
23
|
+
else:
|
|
24
|
+
print(f'{e.__class__.__name__}', file=sys.stderr)
|
|
25
|
+
return None
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import atproto_client
|
|
3
|
+
from ssky.profile_list import ProfileList
|
|
4
|
+
from ssky.ssky_session import expand_actor, ssky_client
|
|
5
|
+
|
|
6
|
+
def follow(name, **kwargs) -> str:
|
|
7
|
+
try:
|
|
8
|
+
client = ssky_client()
|
|
9
|
+
actor = expand_actor(name)
|
|
10
|
+
profile = client.get_profile(actor)
|
|
11
|
+
client.follow(profile.did)
|
|
12
|
+
return ProfileList().append(profile.did)
|
|
13
|
+
except atproto_client.exceptions.AtProtocolError as e:
|
|
14
|
+
if 'response' in dir(e) and e.response is not None:
|
|
15
|
+
print(f'{e.response.status_code} {e.response.content.message}', file=sys.stderr)
|
|
16
|
+
elif str(e) is not None and len(str(e)) > 0:
|
|
17
|
+
print(f'{str(e)}', file=sys.stderr)
|
|
18
|
+
else:
|
|
19
|
+
print(f'{e.__class__.__name__}', file=sys.stderr)
|
|
20
|
+
return None
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import atproto_client
|
|
3
|
+
from ssky.ssky_session import expand_actor, ssky_client
|
|
4
|
+
from ssky.post_data_list import PostDataList
|
|
5
|
+
from ssky.util import disjoin_uri_cid, is_joined_uri_cid
|
|
6
|
+
|
|
7
|
+
def get_posts(client, uri, cid) -> None:
|
|
8
|
+
res = client.get_posts([uri])
|
|
9
|
+
post_data_list = PostDataList()
|
|
10
|
+
for post in res.posts:
|
|
11
|
+
if post.uri == uri and (cid is None or post.cid == cid):
|
|
12
|
+
post_data_list.append(post)
|
|
13
|
+
return post_data_list
|
|
14
|
+
|
|
15
|
+
def get_author_feed(client, user, limit=100) -> None:
|
|
16
|
+
res = client.get_author_feed(user, limit=limit)
|
|
17
|
+
post_data_list = PostDataList()
|
|
18
|
+
for feed_post in res.feed:
|
|
19
|
+
post_data_list.append(feed_post.post)
|
|
20
|
+
return post_data_list
|
|
21
|
+
|
|
22
|
+
def get_timeline(client, limit=100) -> None:
|
|
23
|
+
res = client.get_timeline(limit=limit)
|
|
24
|
+
post_data_list = PostDataList()
|
|
25
|
+
for feed_post in res.feed:
|
|
26
|
+
post_data_list.append(feed_post.post)
|
|
27
|
+
return post_data_list
|
|
28
|
+
|
|
29
|
+
def get(target=None, limit=100, **kwargs) -> PostDataList:
|
|
30
|
+
try:
|
|
31
|
+
client = ssky_client()
|
|
32
|
+
if target is None:
|
|
33
|
+
post_data_list = get_timeline(client, limit=limit)
|
|
34
|
+
elif target.startswith('at://'):
|
|
35
|
+
if is_joined_uri_cid(target):
|
|
36
|
+
uri, cid = disjoin_uri_cid(target)
|
|
37
|
+
else:
|
|
38
|
+
uri = target
|
|
39
|
+
cid = None
|
|
40
|
+
post_data_list = get_posts(client, uri, cid)
|
|
41
|
+
elif target.startswith('did:'):
|
|
42
|
+
post_data_list = get_author_feed(client, target, limit=limit)
|
|
43
|
+
else:
|
|
44
|
+
actor = expand_actor(target)
|
|
45
|
+
post_data_list = get_author_feed(client, actor, limit=limit)
|
|
46
|
+
return post_data_list
|
|
47
|
+
except atproto_client.exceptions.AtProtocolError as e:
|
|
48
|
+
if 'response' in dir(e) and e.response is not None:
|
|
49
|
+
print(f'{e.response.status_code} {e.response.content.message}', file=sys.stderr)
|
|
50
|
+
elif str(e) is not None and len(str(e)) > 0:
|
|
51
|
+
print(f'{str(e)}', file=sys.stderr)
|
|
52
|
+
else:
|
|
53
|
+
print(f'{e.__class__.__name__}', file=sys.stderr)
|
|
54
|
+
return None
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import atproto_client
|
|
3
|
+
from ssky.profile_list import ProfileList
|
|
4
|
+
from ssky.ssky_session import SskySession
|
|
5
|
+
|
|
6
|
+
def login(handle=None, password=None, **kwargs) -> list:
|
|
7
|
+
try:
|
|
8
|
+
session = SskySession(handle=handle, password=password)
|
|
9
|
+
session.persist()
|
|
10
|
+
return ProfileList().append(session.profile().did)
|
|
11
|
+
except atproto_client.exceptions.AtProtocolError as e:
|
|
12
|
+
if 'response' in dir(e) and e.response is not None:
|
|
13
|
+
print(f'{e.response.status_code} {e.response.content.message}', file=sys.stderr)
|
|
14
|
+
elif str(e) is not None and len(str(e)) > 0:
|
|
15
|
+
print(f'{str(e)}', file=sys.stderr)
|
|
16
|
+
else:
|
|
17
|
+
print(f'{e.__class__.__name__}', file=sys.stderr)
|
|
18
|
+
return None
|