A tool for adding all Bluesky users with a matching handle to a user list

Compare changes

Choose any two refs to compare.

Changed files
+68 -4
dist
lib
+46 -3
README.md
··· 1 1 # Userlist Sync 2 2 3 - A small tool written in Ruby for adding all users with handles matching some kind of pattern (e.g. all *.gov) to a user list on Bluesky. 3 + A small tool written in Ruby for adding all users with handles matching some kind of pattern (e.g. all [*.gov](https://bsky.app/profile/did:plc:oio4hkxaop4ao4wz2pp3f4cr/lists/3lcq5ovmsjn2s)) to a user list on Bluesky. 4 4 5 5 6 6 ## How to use 7 7 8 - TODO 8 + 1) Deploy this repo to some kind of server using a method of your choice (manual `git clone`, Capistrano, etc.). 9 + 10 + 2) Make sure you have a reasonably new version of Ruby installed there. Any recent Linux distribution should have Ruby 3.0 or newer available as a package (as of January 2025, the latest version is 3.4.1, 3.1.x is in security maintenance mode, and 3.0.x is EOL); however, this code should work with 2.6 or 2.7 too, though that's not recommended. You can also install Ruby using tools such as [RVM](https://rvm.io), [asdf](https://asdf-vm.com), [ruby-install](https://github.com/postmodern/ruby-install) or [ruby-build](https://github.com/rbenv/ruby-build). 11 + 12 + 3) `cd` into the project directory and install gem dependencies using `bundle`. You might want to configure it to install the gems into the local directory instead of system-wide, e.g.: 13 + 14 + ``` 15 + bundle config --local bundle_path ./vendor 16 + bundle 17 + ``` 18 + 19 + 4) Create a `config/auth.yml` file with authentication info for the account that manages the lists. It should look like this (sorry, no OAuth yet): 20 + 21 + ``` 22 + id: your.handle 23 + pass: app-pass-word 24 + ``` 25 + 26 + This file will also be used to keep access tokens (try to delete the tokens from there if something goes wrong and the app can't authenticate). 27 + 28 + 5) Create a second config file `config/config.yml` with options for the list and handles: 29 + 30 + ``` 31 + jetstream_host: jetstream2.us-east.bsky.network 32 + handle_patterns: 33 + - "*.uk" 34 + list_key: 3lqwertyuiop 35 + ``` 36 + 37 + Fields in the config: 38 + 39 + - `jetstream_host` - Jetstream server hostname, see [here](https://github.com/bluesky-social/jetstream?tab=readme-ov-file#public-instances) 40 + - `handle_patterns` - list of one or more handle patterns to look for; the entries are currently not regexps, but just simple patterns with `*` matching one or more characters 41 + - `list_key` - the *rkey* of the list to which accounts should be added (the last part of the list URL) 42 + 43 + 6) Test if the app works by running: 44 + 45 + ``` 46 + ./run_sync.rb 47 + ``` 48 + 49 + The app will save some data like current cursor and list of known accounts to `data/data.json` (on first run, it will fetch the initial state of the list first). 50 + 51 + 7) Use something like `systemd` to launch the service automatically and keep it running (you can find a sample systemd service file in the [dist folder](https://github.com/mackuba/userlist_sync/blob/master/dist/userlist_sync.service)). 9 52 10 53 11 54 ## Credits 12 55 13 - Copyright © 2024 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/mackuba.eu)). 56 + Copyright © 2024-25 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/mackuba.eu)). 14 57 15 58 The code is available under the terms of the [zlib license](https://choosealicense.com/licenses/zlib/) (permissive, similar to MIT). 16 59
+16
dist/userlist_sync.service
··· 1 + [Unit] 2 + Description=Bluesky userlist sync 3 + After=network.target 4 + 5 + [Service] 6 + Type=simple 7 + User=alf 8 + WorkingDirectory=/var/www/userlist_sync 9 + ExecStart=/usr/bin/ruby ./run_sync.rb 10 + TimeoutSec=15 11 + Restart=on-failure 12 + RestartSec=1 13 + StandardOutput=append:/var/www/userlist_sync/sync.log 14 + 15 + [Install] 16 + WantedBy=multi-user.target
+6 -1
lib/sync.rb
··· 3 3 require 'json' 4 4 require 'minisky' 5 5 require 'set' 6 - require 'skyfall' 6 + require 'skyfall/jetstream' 7 + require 'skyfall/version' 7 8 require 'yaml' 8 9 9 10 class Sync ··· 29 30 wanted_collections: 'app.bsky.none', 30 31 cursor: @data['cursor'] 31 32 }) 33 + 34 + @jetstream.check_heartbeat = true 35 + @jetstream.heartbeat_timeout = 120 36 + @jetstream.heartbeat_interval = 20 32 37 33 38 @jetstream.on_connecting { |u| log "Connecting to #{u}..." } 34 39 @jetstream.on_connect { log "Connected ✓" }