fetch_bookmarks.rb
Example: sync your private bookmarks to a local JSON file. When run again, it will only fetch new ones since the last time and add them to the file.
rb
# Since bookmarks are private (currently stored on the AppView), this requires
# authentication. You will need a .yml config file with contents like this:
#
# id: your.handle
# pass: secretpass
require 'didkit'
require 'minisky'
require 'time'
require 'yaml'
$config_file = ARGV[0]
$bookmarks_file = ARGV[1]
if $config_file.nil? || $bookmarks_file.nil?
puts "Usage: #{$PROGRAM_NAME} <config.yml> <bookmarks.json>"
puts "Config.yml needs to include: { id: 'handle', pass: 'password' }"
exit 1
elsif !File.exist?(File.expand_path($config_file))
puts "Config file not found (#{$config_file})."
puts "Create a YAML file with { id: 'handle', pass: 'password' }"
exit 1
end
# this is a bit suboptimal, but currently you need to pass the PDS hostname to
# Minisky, even though it could look it up itself based on the handle in the config.
# this might be fixed in the future
id = YAML.load(File.read($config_file))['id']
pds = DID.resolve_handle(id).document.pds_host
# create a client instance using the auth config file
bsky = Minisky.new(pds, $config_file)
# print progress dots when loading multiple pages
bsky.default_progress = '.'
# load previously saved bookmarks; we will only fetch bookmarks newer than the
# last saved before
bookmarks = File.exist?($bookmarks_file) ? JSON.parse(File.read($bookmarks_file)) : []
latest_date = bookmarks[0] && bookmarks[0]['createdAt']
if !bookmarks.empty?
last_date_fmt = Time.parse(latest_date).getlocal
puts "Loaded #{bookmarks.length} existing bookmarks (last date: #{last_date_fmt})"
end
# fetch all bookmarks until the target timestamp
new_items = bsky.fetch_all('app.bsky.bookmark.getBookmarks',
{ limit: 100 },
field: 'bookmarks',
break_when: latest_date && proc { |x| x['createdAt'] <= latest_date }
)
# trim some data to save space
new_items.each do |b|
if b['item']['author']
b['item']['author'] = b['item']['author'].slice('did', 'handle')
end
end
bookmarks = new_items + bookmarks
puts
puts "Fetched #{new_items.length} new bookmarks (total = #{bookmarks.length})"
# save all new and old bookmarks back to the file
File.write($bookmarks_file, JSON.pretty_generate(bookmarks))