+21
LICENSE.txt
+21
LICENSE.txt
···
1
+
The zlib License
2
+
3
+
Copyright (c) 2024 Jakub Suder
4
+
5
+
This software is provided 'as-is', without any express or implied
6
+
warranty. In no event will the authors be held liable for any damages
7
+
arising from the use of this software.
8
+
9
+
Permission is granted to anyone to use this software for any purpose,
10
+
including commercial applications, and to alter it and redistribute it
11
+
freely, subject to the following restrictions:
12
+
13
+
1. The origin of this software must not be misrepresented; you must not
14
+
claim that you wrote the original software. If you use this software
15
+
in a product, an acknowledgment in the product documentation would be
16
+
appreciated but is not required.
17
+
18
+
2. Altered source versions must be plainly marked as such, and must not be
19
+
misrepresented as being the original software.
20
+
21
+
3. This notice may not be removed or altered from any source distribution.
+60
README.md
+60
README.md
···
1
+
# Userlist Sync
2
+
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
+
5
+
6
+
## How to use
7
+
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)).
52
+
53
+
54
+
## Credits
55
+
56
+
Copyright © 2024-25 Kuba Suder ([@mackuba.eu](https://bsky.app/profile/mackuba.eu)).
57
+
58
+
The code is available under the terms of the [zlib license](https://choosealicense.com/licenses/zlib/) (permissive, similar to MIT).
59
+
60
+
Bug reports and pull requests are welcome 😎
+16
dist/userlist_sync.service
+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
+7
-1
lib/sync.rb
+7
-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
···
30
31
cursor: @data['cursor']
31
32
})
32
33
34
+
@jetstream.check_heartbeat = true
35
+
@jetstream.heartbeat_timeout = 120
36
+
@jetstream.heartbeat_interval = 20
37
+
33
38
@jetstream.on_connecting { |u| log "Connecting to #{u}..." }
34
39
@jetstream.on_connect { log "Connected ✓" }
35
40
@jetstream.on_disconnect { log "Disconnected." }
···
52
57
53
58
def log(s)
54
59
puts "#{Time.now}: #{s}"
60
+
$stdout.flush
55
61
end
56
62
57
63