+44
app/importers/reposts_importer.rb
+44
app/importers/reposts_importer.rb
···
1
+
require 'time'
2
+
3
+
require_relative '../at_uri'
4
+
require_relative 'base_importer'
5
+
6
+
class RepostsImporter < BaseImporter
7
+
def import_items
8
+
params = { repo: @did, collection: 'app.bsky.feed.repost', limit: 100 }
9
+
params[:cursor] = @import.cursor if @import.cursor
10
+
11
+
loop do
12
+
response = @minisky.get_request('com.atproto.repo.listRecords', params)
13
+
14
+
records = response['records']
15
+
cursor = response['cursor']
16
+
17
+
@imported_count += records.length
18
+
@report&.update(importers: { importer_name => { :imported_items => @imported_count }})
19
+
@report&.update(importers: { importer_name => { :oldest_date => Time.parse(records.last['value']['createdAt']) }}) unless records.empty?
20
+
21
+
records.each do |record|
22
+
begin
23
+
repost_rkey = AT_URI(record['uri']).rkey
24
+
next if @user.reposts.where(rkey: repost_rkey).exists?
25
+
26
+
repost_time = Time.parse(record['value']['createdAt'])
27
+
post_uri = record['value']['subject']['uri']
28
+
29
+
create_item_for_post(post_uri) do |args|
30
+
@user.reposts.create!(args.merge(rkey: repost_rkey, time: repost_time))
31
+
end
32
+
rescue StandardError => e
33
+
puts "Error in RepostsImporter: #{record['uri']}: #{e}"
34
+
end
35
+
end
36
+
37
+
params[:cursor] = cursor
38
+
@import.update!(cursor: cursor)
39
+
40
+
break if !cursor
41
+
break if @time_limit && records.any? { |x| Time.parse(x['value']['createdAt']) < @time_limit }
42
+
end
43
+
end
44
+
end
+1
-1
app/models/import.rb
+1
-1
app/models/import.rb
+14
app/models/repost.rb
+14
app/models/repost.rb
···
1
+
require 'active_record'
2
+
3
+
require_relative 'post'
4
+
require_relative 'user'
5
+
6
+
class Repost < ActiveRecord::Base
7
+
validates_presence_of :time, :rkey
8
+
validates_length_of :rkey, maximum: 13
9
+
10
+
validates_presence_of :post_uri, if: -> { post_id.nil? }
11
+
12
+
belongs_to :user, foreign_key: 'actor_id'
13
+
belongs_to :post, optional: true
14
+
end
+2
app/models/user.rb
+2
app/models/user.rb
···
3
3
require_relative 'import'
4
4
require_relative 'like'
5
5
require_relative 'post'
6
+
require_relative 'repost'
6
7
7
8
class User < ActiveRecord::Base
8
9
validates_presence_of :did
···
10
11
11
12
has_many :posts
12
13
has_many :likes, foreign_key: 'actor_id'
14
+
has_many :reposts, foreign_key: 'actor_id'
13
15
has_many :imports
14
16
end
+14
db/migrate/20250906005748_add_reposts.rb
+14
db/migrate/20250906005748_add_reposts.rb
···
1
+
class AddReposts < ActiveRecord::Migration[7.2]
2
+
def change
3
+
create_table :reposts do |t|
4
+
t.integer "actor_id", null: false
5
+
t.string "rkey", limit: 13, null: false
6
+
t.datetime "time", null: false
7
+
t.bigint "post_id"
8
+
t.string "post_uri"
9
+
end
10
+
11
+
add_index :reposts, [:actor_id, :time, :id], order: { time: :desc, id: :desc }
12
+
add_index :reposts, [:actor_id, :rkey], unique: true
13
+
end
14
+
end
+11
-1
db/schema.rb
+11
-1
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_09_03_215014) do
13
+
ActiveRecord::Schema[7.2].define(version: 2025_09_06_005748) do
14
14
# These are extensions that must be enabled in order to support this database
15
15
enable_extension "plpgsql"
16
16
···
41
41
t.text "data", null: false
42
42
t.index ["user_id", "rkey"], name: "index_posts_on_user_id_and_rkey", unique: true
43
43
t.index ["user_id", "time", "id"], name: "index_posts_on_user_id_and_time_and_id", order: { time: :desc, id: :desc }
44
+
end
45
+
46
+
create_table "reposts", force: :cascade do |t|
47
+
t.integer "actor_id", null: false
48
+
t.string "rkey", limit: 13, null: false
49
+
t.datetime "time", null: false
50
+
t.bigint "post_id"
51
+
t.string "post_uri"
52
+
t.index ["actor_id", "rkey"], name: "index_reposts_on_actor_id_and_rkey", unique: true
53
+
t.index ["actor_id", "time", "id"], name: "index_reposts_on_actor_id_and_time_and_id", order: { time: :desc, id: :desc }
44
54
end
45
55
46
56
create_table "users", id: :serial, force: :cascade do |t|
+4
lib/tasks/import.rake
+4
lib/tasks/import.rake
···
1
1
require_relative '../../app/importers/likes_importer'
2
+
require_relative '../../app/importers/reposts_importer'
2
3
require_relative '../../app/import_report'
3
4
require_relative '../../app/item_queue'
4
5
require_relative '../../app/post_downloader'
···
12
13
when 'likes'
13
14
queue = ItemQueue.new(Like.where(post: nil).to_a)
14
15
importer = LikesImporter.new(ENV['USER'])
16
+
when 'reposts'
17
+
queue = ItemQueue.new(Repost.where(post: nil).to_a)
18
+
importer = RepostsImporter.new(ENV['USER'])
15
19
when nil
16
20
raise "Required COLLECTION parameter missing"
17
21
else