Don't forget to lycansubscribe

added reposts importer

Changed files
+90 -2
app
db
lib
tasks
+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
··· 5 5 class Import < ActiveRecord::Base 6 6 belongs_to :user 7 7 8 - validates_inclusion_of :collection, in: %w(likes) 8 + validates_inclusion_of :collection, in: %w(likes reposts) 9 9 validates_uniqueness_of :collection, scope: :user_id 10 10 end
+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
··· 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
··· 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
··· 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
··· 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