#!/usr/bin/env ruby # 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. # 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 'bundler/setup' 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} " 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))