+24
-43
app/importer.rb
+24
-43
app/importer.rb
···
6
6
require_relative 'models/user'
7
7
8
8
class Importer
9
+
attr_accessor :post_queue
10
+
9
11
def initialize(user_did)
10
12
@did = DID.new(user_did)
11
-
@did.get_document
12
-
13
13
@user = User.find_or_create_by!(did: user_did)
14
14
15
-
@pds_cache = { user_did => @did.document.pds_host }
16
15
@uid_cache = { user_did => @user.id }
17
16
end
18
17
···
41
40
42
41
def process_likes(likes)
43
42
likes.each do |record|
44
-
like_rkey = record['uri'].split('/').last
45
-
next if @user.likes.where(rkey: like_rkey).exists?
43
+
begin
44
+
like_rkey = record['uri'].split('/').last
45
+
next if @user.likes.where(rkey: like_rkey).exists?
46
46
47
-
like_time = Time.parse(record['value']['createdAt'])
47
+
like_time = Time.parse(record['value']['createdAt'])
48
48
49
-
post_uri = record['value']['subject']['uri']
50
-
parts = post_uri.split('/')
51
-
next if parts[3] != 'app.bsky.feed.post'
49
+
post_uri = record['value']['subject']['uri']
50
+
parts = post_uri.split('/')
51
+
next if parts[3] != 'app.bsky.feed.post'
52
52
53
-
post_did, _, post_rkey = parts[2..4]
53
+
post_did, _, post_rkey = parts[2..4]
54
54
55
-
if @uid_cache[post_did].nil?
56
-
post_author = User.find_or_create_by!(did: post_did)
57
-
@uid_cache[post_did] = post_author.id
58
-
end
55
+
if @uid_cache[post_did].nil?
56
+
post_author = User.find_or_create_by!(did: post_did)
57
+
@uid_cache[post_did] = post_author.id
58
+
end
59
59
60
-
author_id = @uid_cache[post_did]
61
-
post = Post.find_by(user_id: author_id, rkey: post_rkey)
60
+
post = Post.find_by(user_id: @uid_cache[post_did], rkey: post_rkey)
62
61
63
-
if post.nil?
64
-
begin
65
-
post_record = fetch_post_record(post_did, post_rkey)
66
-
json = post_record['value']
67
-
text = json.delete('text')
68
-
created = json.delete('createdAt')
62
+
if post
63
+
@user.likes.create!(rkey: like_rkey, time: like_time, post: post)
64
+
else
65
+
like_stub = @user.likes.create!(rkey: like_rkey, time: like_time, post_uri: post_uri)
69
66
70
-
post = Post.create!(
71
-
user_id: author_id,
72
-
rkey: post_rkey,
73
-
time: Time.parse(created),
74
-
text: text,
75
-
data: JSON.generate(json)
76
-
)
77
-
rescue StandardError => e
78
-
# skip
79
-
next
67
+
if @post_queue
68
+
@post_queue.push(like_stub)
69
+
end
80
70
end
71
+
rescue StandardError => e
72
+
puts "Error in Importer#process_likes: #{record['uri']}: #{e}"
81
73
end
82
-
83
-
@user.likes.create!(rkey: like_rkey, post: post, time: like_time)
84
74
end
85
-
end
86
-
87
-
def fetch_post_record(did, rkey)
88
-
@pds_cache[did] ||= DID.new(did).document.pds_host
89
-
90
-
pds = @pds_cache[did]
91
-
sky = Minisky.new(pds, nil)
92
-
93
-
sky.get_request('com.atproto.repo.getRecord', { repo: did, collection: 'app.bsky.feed.post', rkey: rkey })
94
75
end
95
76
end
+3
-1
app/models/like.rb
+3
-1
app/models/like.rb
+52
app/post_downloader.rb
+52
app/post_downloader.rb
···
1
+
require 'didkit'
2
+
require 'minisky'
3
+
4
+
require_relative 'models/post'
5
+
require_relative 'models/user'
6
+
7
+
class PostDownloader
8
+
def initialize
9
+
@pds_cache = {}
10
+
end
11
+
12
+
def import_from_queue(queue)
13
+
loop do
14
+
like = queue.pop
15
+
16
+
begin
17
+
post = import_post(like.post_uri)
18
+
like.update!(post: post, post_uri: nil)
19
+
rescue StandardError => e
20
+
puts "Error in PostDownloader: #{like.post_uri}: #{e}"
21
+
end
22
+
end
23
+
end
24
+
25
+
def import_post(post_uri)
26
+
did, _, rkey = post_uri.split('/')[2..4]
27
+
post_record = fetch_post_record(did, rkey)
28
+
29
+
json = post_record['value']
30
+
text = json.delete('text')
31
+
created = json.delete('createdAt')
32
+
33
+
author = User.find_or_create_by!(did: did)
34
+
35
+
Post.create!(
36
+
user: author,
37
+
rkey: rkey,
38
+
time: Time.parse(created),
39
+
text: text,
40
+
data: JSON.generate(json)
41
+
)
42
+
end
43
+
44
+
def fetch_post_record(did, rkey)
45
+
@pds_cache[did] ||= DID.new(did).document.pds_host
46
+
47
+
pds = @pds_cache[did]
48
+
sky = Minisky.new(pds, nil)
49
+
50
+
sky.get_request('com.atproto.repo.getRecord', { repo: did, collection: 'app.bsky.feed.post', rkey: rkey })
51
+
end
52
+
end
+6
db/migrate/20250830210139_add_uri_to_likes.rb
+6
db/migrate/20250830210139_add_uri_to_likes.rb
+3
-2
db/schema.rb
+3
-2
db/schema.rb
···
10
10
#
11
11
# It's strongly recommended that you check this file into your version control system.
12
12
13
-
ActiveRecord::Schema[7.2].define(version: 2025_08_29_000022) do
13
+
ActiveRecord::Schema[7.2].define(version: 2025_08_30_210139) do
14
14
# These are extensions that must be enabled in order to support this database
15
15
enable_extension "plpgsql"
16
16
···
18
18
t.integer "actor_id", null: false
19
19
t.string "rkey", limit: 13, null: false
20
20
t.datetime "time", null: false
21
-
t.bigint "post_id", null: false
21
+
t.bigint "post_id"
22
+
t.string "post_uri"
22
23
t.index ["actor_id", "rkey"], name: "index_likes_on_actor_id_and_rkey", unique: true
23
24
t.index ["actor_id", "time", "id"], name: "index_likes_on_actor_id_and_time_and_id", order: { time: :desc, id: :desc }
24
25
end