latest_leaflets.rb
Example: latest Leaflet articles from the people you follow.
Leaflet is a blogging platform based on the AT Protocol. This script downloads the list of accounts you follow on Bluesky, checks which of them have a Leaflet blog, and then looks up the most recent Leaflet post for each of those accounts.
rb
require 'didkit'
require 'minisky'
# TODO: currently only these "staging" relays support listReposByCollection
RELAY = 'relay1.us-west.bsky.network'
$handle = ARGV[0]
if $handle.nil?
puts "Usage: #{$PROGRAM_NAME} <handle | did>"
exit 1
end
$did = DID.resolve_handle($handle)
if $did.nil?
puts "Couldn't resolve handle: #{$handle}"
exit 1
end
pds_host = $did.document.pds_host
pds = Minisky.new(pds_host, nil, progress: '.')
print "Fetching all follows of #{$handle} from #{pds_host}: "
follows = pds.fetch_all('com.atproto.repo.listRecords',
{ repo: $did, collection: 'app.bsky.graph.follow', limit: 100 }, field: 'records')
puts
puts "Found #{follows.length} follows."
print "Fetching list of repos with Leaflet documents: "
# listReposByCollection returns a list of all DIDs on the whole network (known to
# the relay) which have at least one record of the given type
relay = Minisky.new(RELAY, nil, progress: '.')
leaflet_repos = relay.fetch_all('com.atproto.sync.listReposByCollection',
{ collection: 'pub.leaflet.document' }, field: 'repos')
# follows with Leaflets are the intersection of the two lists:
followed_dids = follows.map { |x| x['value']['subject'] }
leaflet_dids = leaflet_repos.map { |x| x['did'] }
leaflet_follows = followed_dids & leaflet_dids
puts
print "Found #{leaflet_repos.length} repos - "
puts "#{leaflet_follows.length} followed profiles have a Leaflet blog."
puts
puts '-' * 40
# For each user, load Bluesky profile info from the AppView (to get their name)
# and one Leaflet document record from their PDS. Records in listRecords are
# sorted by rkey (which is based on time), so the first one will be the newest.
appview = Minisky.new('api.bsky.app', nil)
leaflet_follows.each do |did|
begin
fpds = DID.new(did).document.pds_host
response = Minisky.new(fpds, nil).get_request('com.atproto.repo.listRecords', {
repo: did,
collection: 'pub.leaflet.document',
limit: 1
})
if record = response['records'][0]
profile = appview.get_request('app.bsky.actor.getProfile', { actor: did })
puts
puts "#{profile['displayName']} (@#{profile['handle']}):"
published_at = Time.parse(record['value']['publishedAt'])
puts "#{record['value']['title'].inspect} • #{published_at}"
if !record['value']['description'].to_s.empty?
puts
puts record['value']['description']
end
puts
puts '-' * 40
end
rescue StandardError => e
if fpds
puts "\n#{did}: error loading repo from #{fpds}"
else
puts "\n#{did}: error loading account info"
end
puts
puts '-' * 40
end
end