bskyrb 0.5 → 0.5.1
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.
- checksums.yaml +4 -4
- data/lib/bskyrb/codegen.rb +1 -0
- data/lib/bskyrb/error.rb +10 -0
- data/lib/bskyrb/firehose.rb +19 -21
- data/lib/bskyrb/generated_classes.rb +711 -4
- data/lib/bskyrb/records.rb +50 -91
- data/lib/bskyrb/session.rb +40 -30
- data/lib/bskyrb/version.rb +2 -1
- data/lib/bskyrb.rb +3 -0
- metadata +3 -16
data/lib/bskyrb/records.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
module Bskyrb
|
2
3
|
class RecordManager
|
3
4
|
include RequestUtils
|
@@ -9,6 +10,7 @@ module Bskyrb
|
|
9
10
|
|
10
11
|
def get_post_by_url(url, depth = 10)
|
11
12
|
# e.g. "https://staging.bsky.app/profile/naia.bsky.social/post/3jszsrnruws27"
|
13
|
+
# or "at://did:plc:scx5mrfxxrqlfzkjcpbt3xfr/app.bsky.feed.post/3jszsrnruws27"
|
12
14
|
# regex by chatgpt:
|
13
15
|
query = Bskyrb::AppBskyFeedGetpostthread::GetPostThread::Input.new.tap do |q|
|
14
16
|
q.uri = at_post_link(session.pds, url)
|
@@ -16,7 +18,7 @@ module Bskyrb
|
|
16
18
|
end
|
17
19
|
res = HTTParty.get(
|
18
20
|
get_post_thread_uri(session.pds, query),
|
19
|
-
headers: default_authenticated_headers(session)
|
21
|
+
headers: default_authenticated_headers(session),
|
20
22
|
)
|
21
23
|
Bskyrb::AppBskyFeedDefs::PostView.from_hash res["thread"]["post"]
|
22
24
|
end
|
@@ -27,7 +29,7 @@ module Bskyrb
|
|
27
29
|
HTTParty.post(
|
28
30
|
upload_blob_uri(session.pds),
|
29
31
|
body: image_bytes,
|
30
|
-
headers: default_authenticated_headers(session)
|
32
|
+
headers: default_authenticated_headers(session),
|
31
33
|
)
|
32
34
|
end
|
33
35
|
|
@@ -38,47 +40,17 @@ module Bskyrb
|
|
38
40
|
HTTParty.post(
|
39
41
|
create_record_uri(session.pds),
|
40
42
|
body: input.to_h.compact.to_json,
|
41
|
-
headers: default_authenticated_headers(session)
|
43
|
+
headers: default_authenticated_headers(session),
|
42
44
|
)
|
43
45
|
end
|
44
46
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# Loop through the matches and resolve the handles
|
54
|
-
matches.each do |match|
|
55
|
-
handle = match[0]
|
56
|
-
resolved_handle = resolve_handle(session.pds, handle)
|
57
|
-
byte_start = json_hash["record"]["text"].index("@" + handle)
|
58
|
-
byte_end = byte_start + handle.length
|
59
|
-
facet = {
|
60
|
-
"$type": "app.bsky.richtext.facet",
|
61
|
-
features: [
|
62
|
-
{
|
63
|
-
"$type": "app.bsky.richtext.facet#mention",
|
64
|
-
did: resolved_handle
|
65
|
-
}
|
66
|
-
],
|
67
|
-
index: {
|
68
|
-
byteStart: byte_start,
|
69
|
-
byteEnd: byte_end
|
70
|
-
}
|
71
|
-
}
|
72
|
-
facets.push(facet)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Append the facets to the JSON hash
|
76
|
-
json_hash["record"]["facets"] = facets
|
77
|
-
|
78
|
-
# Convert the JSON hash back to a string
|
79
|
-
JSON.generate(json_hash)
|
80
|
-
|
81
|
-
# "Doesn't work yet"
|
47
|
+
def delete_record(collection, rkey)
|
48
|
+
data = { collection: collection, repo: session.did, rkey: rkey }
|
49
|
+
HTTParty.post(
|
50
|
+
delete_record_uri(session),
|
51
|
+
body: data.to_json,
|
52
|
+
headers: default_authenticated_headers(session),
|
53
|
+
)
|
82
54
|
end
|
83
55
|
|
84
56
|
def create_post(text)
|
@@ -89,34 +61,36 @@ module Bskyrb
|
|
89
61
|
"record" => {
|
90
62
|
"$type" => "app.bsky.feed.post",
|
91
63
|
"createdAt" => DateTime.now.iso8601(3),
|
92
|
-
"text" => text
|
93
|
-
}
|
64
|
+
"text" => text,
|
65
|
+
},
|
94
66
|
})
|
95
67
|
create_record(input)
|
96
68
|
end
|
97
69
|
|
98
70
|
def create_reply(replylink, text)
|
99
71
|
reply_to = get_post_by_url(replylink)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
72
|
+
input = Bskyrb::ComAtprotoRepoCreaterecord::CreateRecord::Input.from_hash({
|
73
|
+
"collection" => "app.bsky.feed.post",
|
74
|
+
"$type" => "app.bsky.feed.post",
|
75
|
+
"repo" => session.did,
|
76
|
+
|
77
|
+
"record" => {
|
78
|
+
"reply" => {
|
79
|
+
"parent" => {
|
80
|
+
"uri" => reply_to.uri,
|
81
|
+
"cid" => reply_to.cid,
|
82
|
+
},
|
83
|
+
"root" => {
|
84
|
+
"uri" => reply_to.uri,
|
85
|
+
"cid" => reply_to.cid,
|
86
|
+
},
|
87
|
+
},
|
88
|
+
"$type" => "app.bsky.feed.post",
|
89
|
+
"createdAt" => DateTime.now.iso8601(3),
|
90
|
+
"text" => text,
|
108
91
|
},
|
109
|
-
|
110
|
-
|
111
|
-
record: {
|
112
|
-
"$type": "app.bsky.feed.post",
|
113
|
-
createdAt: DateTime.now.iso8601(3),
|
114
|
-
text: text
|
115
|
-
}
|
116
|
-
},
|
117
|
-
reply_hash = JSON.parse(reply_json.to_json)
|
118
|
-
reply = Bskyrb::ComAtprotoRepoCreaterecord::CreateRecord::Input.from_hash(reply_hash)
|
119
|
-
create_record(reply)
|
92
|
+
})
|
93
|
+
create_record(input)
|
120
94
|
end
|
121
95
|
|
122
96
|
def profile_action(username, type)
|
@@ -126,27 +100,26 @@ module Bskyrb
|
|
126
100
|
"record" => {
|
127
101
|
"subject" => resolve_handle(session.pds, username)["did"],
|
128
102
|
"createdAt" => DateTime.now.iso8601(3),
|
129
|
-
"$type" => type
|
130
|
-
}
|
103
|
+
"$type" => type,
|
104
|
+
},
|
131
105
|
})
|
132
106
|
create_record(input)
|
133
107
|
end
|
134
108
|
|
135
|
-
|
136
109
|
def post_action(post, action_type)
|
137
110
|
data = {
|
138
111
|
collection: action_type,
|
139
112
|
repo: session.did,
|
140
113
|
record: {
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
}
|
148
|
-
|
149
|
-
|
114
|
+
subject: {
|
115
|
+
uri: post.uri,
|
116
|
+
cid: post.cid,
|
117
|
+
},
|
118
|
+
createdAt: DateTime.now.iso8601(3),
|
119
|
+
"$type": action_type,
|
120
|
+
},
|
121
|
+
}
|
122
|
+
create_record(data)
|
150
123
|
end
|
151
124
|
|
152
125
|
def like(post_url)
|
@@ -158,29 +131,15 @@ module Bskyrb
|
|
158
131
|
post = get_post_by_url(post_url)
|
159
132
|
post_action(post, "app.bsky.feed.repost")
|
160
133
|
end
|
161
|
-
|
134
|
+
|
162
135
|
def follow(username)
|
163
136
|
profile_action(username, "app.bsky.graph.follow")
|
164
137
|
end
|
165
138
|
|
166
|
-
# def unfollow(username)
|
167
|
-
# profile_action(username, "app.bsky.graph.unfollow(?)")
|
168
|
-
# end
|
169
|
-
#NONE OF THESE WORK
|
170
|
-
# def mute(username)
|
171
|
-
# profile_action(username, "app.bsky.graph.mute")
|
172
|
-
# end
|
173
|
-
|
174
|
-
# def unmute(username)
|
175
|
-
# profile_action(username, "app.bsky.graph.unmute")
|
176
|
-
# end
|
177
|
-
|
178
|
-
|
179
139
|
def block(username)
|
180
140
|
profile_action(username, "app.bsky.graph.block")
|
181
141
|
end
|
182
142
|
|
183
|
-
|
184
143
|
def get_latest_post(username)
|
185
144
|
feed = get_latest_n_posts(username, 1)
|
186
145
|
feed.feed.first
|
@@ -193,7 +152,7 @@ module Bskyrb
|
|
193
152
|
end
|
194
153
|
hydrate_feed HTTParty.get(
|
195
154
|
get_author_feed_uri(session.pds, query),
|
196
|
-
headers: default_authenticated_headers(session)
|
155
|
+
headers: default_authenticated_headers(session),
|
197
156
|
), Bskyrb::AppBskyFeedGetauthorfeed::GetAuthorFeed::Output
|
198
157
|
end
|
199
158
|
|
@@ -203,7 +162,7 @@ module Bskyrb
|
|
203
162
|
end
|
204
163
|
hydrate_feed HTTParty.get(
|
205
164
|
get_timeline_uri(session.pds, query),
|
206
|
-
headers: default_authenticated_headers(session)
|
165
|
+
headers: default_authenticated_headers(session),
|
207
166
|
), Bskyrb::AppBskyFeedGettimeline::GetTimeline::Output
|
208
167
|
end
|
209
168
|
|
@@ -213,7 +172,7 @@ module Bskyrb
|
|
213
172
|
end
|
214
173
|
hydrate_feed HTTParty.get(
|
215
174
|
get_popular_uri(session.pds, query),
|
216
|
-
headers: default_authenticated_headers(session)
|
175
|
+
headers: default_authenticated_headers(session),
|
217
176
|
), Bskyrb::AppBskyUnspeccedGetpopular::GetPopular::Output
|
218
177
|
end
|
219
178
|
|
data/lib/bskyrb/session.rb
CHANGED
@@ -1,28 +1,12 @@
|
|
1
|
+
# typed: false
|
1
2
|
require "uri"
|
2
3
|
require "httparty"
|
3
4
|
|
4
|
-
|
5
|
-
# # doesn't go within session class because it wouldn't work unless you already have an account
|
6
|
-
# data = {
|
7
|
-
# "email": email,
|
8
|
-
# "handle": user + ".bsky.social", # defaulting to bsky.social handles because you can't add dns records for a DID that doesn't exist yet
|
9
|
-
# "inviteCode": invcode,
|
10
|
-
# "password": password,
|
11
|
-
# }
|
12
|
-
# resp = HTTParty.post(
|
13
|
-
# "#{pds}/xrpc/com.atproto.server.createAccount",
|
14
|
-
# body: data.to_json,
|
15
|
-
# headers: {'Content-Type' => 'application/json'}
|
16
|
-
# )
|
17
|
-
# resp
|
18
|
-
# end
|
19
|
-
|
20
|
-
module Bskyrb
|
5
|
+
module Bskyrb
|
21
6
|
module RequestUtils
|
22
7
|
def resolve_handle(pds, username)
|
23
|
-
|
24
|
-
|
25
|
-
)
|
8
|
+
resolveHandle = XRPC::Endpoint.new(pds, "com.atproto.identity.resolveHandle", :handle)
|
9
|
+
resolveHandle.get(handle: username)
|
26
10
|
end
|
27
11
|
|
28
12
|
def query_obj_to_query_params(q)
|
@@ -34,13 +18,17 @@ module Bskyrb
|
|
34
18
|
end
|
35
19
|
|
36
20
|
def default_headers
|
37
|
-
{"Content-Type" => "application/json"}
|
21
|
+
{ "Content-Type" => "application/json" }
|
38
22
|
end
|
39
23
|
|
40
24
|
def create_record_uri(pds)
|
41
25
|
"#{pds}/xrpc/com.atproto.repo.createRecord"
|
42
26
|
end
|
43
27
|
|
28
|
+
def delete_record_uri(pds)
|
29
|
+
"#{pds}/xrpc/com.atproto.repo.deleteRecord"
|
30
|
+
end
|
31
|
+
|
44
32
|
def upload_blob_uri(pds)
|
45
33
|
"#{pds}/xrpc/com.atproto.repo.uploadBlob"
|
46
34
|
end
|
@@ -63,18 +51,39 @@ module Bskyrb
|
|
63
51
|
|
64
52
|
def default_authenticated_headers(session)
|
65
53
|
default_headers.merge({
|
66
|
-
Authorization: "Bearer #{session.access_token}"
|
54
|
+
Authorization: "Bearer #{session.access_token}",
|
67
55
|
})
|
68
56
|
end
|
69
57
|
|
70
58
|
def at_post_link(pds, url)
|
71
|
-
# e.g. "https://staging.bsky.app/profile/naia.bsky.social/post/3jszsrnruws27"
|
72
59
|
url = url.to_s
|
73
|
-
|
74
|
-
|
60
|
+
|
61
|
+
# Check if the URL is already in AT format
|
62
|
+
if url.start_with?("at://")
|
63
|
+
# Validate the username and post ID in the URL
|
64
|
+
parts = url.split("/")
|
65
|
+
if parts.length == 5 && parts[3] == "app.bsky.feed.post"
|
66
|
+
username = parts[2]
|
67
|
+
post_id = parts[4]
|
68
|
+
if post_id
|
69
|
+
return url
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# If the URL is not valid, raise an error
|
74
|
+
raise "The provided URL #{url} is not a valid AT URL"
|
75
|
+
end
|
76
|
+
|
77
|
+
# Validate the format of the regular URL and extract the username and post ID
|
78
|
+
regex = /https:\/\/[a-zA-Z0-9.-]+\/profile\/[a-zA-Z0-9.-]+\/post\/[a-zA-Z0-9.-]+/
|
79
|
+
raise "The provided URL #{url} does not match the expected schema" unless regex.match?(url)
|
75
80
|
username = url.split("/")[-3]
|
76
|
-
did = resolve_handle(pds, username)["did"]
|
77
81
|
post_id = url.split("/")[-1]
|
82
|
+
|
83
|
+
# Validate the username and post ID in the AT URL
|
84
|
+
did = resolve_handle(pds, username)["did"]
|
85
|
+
|
86
|
+
# Construct the AT URL
|
78
87
|
"at://#{did}/app.bsky.feed.post/#{post_id}"
|
79
88
|
end
|
80
89
|
end
|
@@ -103,14 +112,15 @@ module Bskyrb
|
|
103
112
|
uri = URI("#{pds}/xrpc/com.atproto.server.createSession")
|
104
113
|
response = HTTParty.post(
|
105
114
|
uri,
|
106
|
-
body: {identifier: credentials.username, password: credentials.pw}.to_json,
|
107
|
-
headers: default_headers
|
115
|
+
body: { identifier: credentials.username, password: credentials.pw }.to_json,
|
116
|
+
headers: default_headers,
|
108
117
|
)
|
118
|
+
|
119
|
+
raise UnauthorizedError if response.code == 401
|
120
|
+
|
109
121
|
@access_token = response["accessJwt"]
|
110
122
|
@refresh_token = response["refreshJwt"]
|
111
123
|
@did = response["did"]
|
112
124
|
end
|
113
125
|
end
|
114
|
-
|
115
|
-
|
116
126
|
end
|
data/lib/bskyrb/version.rb
CHANGED
data/lib/bskyrb.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bskyrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shreyan Jain
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-05-
|
12
|
+
date: 2023-05-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -25,20 +25,6 @@ dependencies:
|
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '2.0'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: net-http
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - ">="
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '0'
|
35
|
-
type: :runtime
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '0'
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: date
|
44
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -76,6 +62,7 @@ extra_rdoc_files: []
|
|
76
62
|
files:
|
77
63
|
- "./lib/bskyrb.rb"
|
78
64
|
- "./lib/bskyrb/codegen.rb"
|
65
|
+
- "./lib/bskyrb/error.rb"
|
79
66
|
- "./lib/bskyrb/firehose.rb"
|
80
67
|
- "./lib/bskyrb/generated_classes.rb"
|
81
68
|
- "./lib/bskyrb/records.rb"
|