Last active
January 3, 2025 20:47
-
-
Save ianrenton/8f5c3d26e3ad3b3ab2746d53a3e6ea61 to your computer and use it in GitHub Desktop.
Scrape callsigns of ham radio folks from your fedi mutuals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Find callsigns of all the ham radio folks you are mutuals with on fedi (may only work with Mastodon) | |
# and produce a list so you can add them to HamAlert or something. | |
# Ian Renton, January 2025 | |
# Public Domain software | |
import re | |
import requests | |
USERNAME='ian' | |
INSTANCE='https://mastodon.radio' | |
CALLSIGN_REGEX=re.compile(r'[a-zA-Z0-9]{1,3}[0-9Ø][a-zA-Z0-9Ø]{0,3}[a-zA-Z]') | |
NEXT_LINK_REGEX=re.compile(r'<(.+?)>; rel="next"') | |
# Get user ID | |
acct_lookup_response = requests.get(INSTANCE + '/api/v1/accounts/lookup?acct=' + USERNAME) | |
my_id = acct_lookup_response.json()['id'] | |
# Get followers and following. There is a maximum limit per request so we need to go through | |
# pagination hassle. | |
followers = [] | |
page = 1 | |
next_followers_url = INSTANCE + '/api/v1/accounts/' + my_id + '/followers' | |
while True: | |
print("Getting followers page " + str(page) + "...") | |
followers_response = requests.get(next_followers_url) | |
followers.extend(followers_response.json()) | |
link_text = followers_response.headers['link'] | |
link_match = NEXT_LINK_REGEX.search(link_text) | |
if link_match: | |
next_followers_url = link_match.group(1) | |
page += 1 | |
else: | |
break | |
print("Found " + str(len(followers)) + " followers.") | |
following = [] | |
page = 1 | |
next_following_url = INSTANCE + '/api/v1/accounts/' + my_id + '/following' | |
while True: | |
print("Getting following page " + str(page) + "...") | |
following_response = requests.get(next_following_url) | |
following.extend(following_response.json()) | |
link_text = following_response.headers['link'] | |
link_match = NEXT_LINK_REGEX.search(link_text) | |
if link_match: | |
next_following_url = link_match.group(1) | |
page += 1 | |
else: | |
break | |
print("Found " + str(len(following)) + " following.") | |
# Find mutuals | |
following_accts = list(map(lambda a: a['acct'], following)) | |
mutuals = list(filter(lambda a: a['acct'] in following_accts, followers)) | |
print("Found " + str(len(mutuals)) + " mutuals.") | |
# Build a list of things that look like callsigns from your mutuals | |
callsigns = [] | |
for acct in mutuals: | |
print('Checking ' + acct['acct'] + '...') | |
# Check for callsigns in the account name itsef, the display name and any custom fields. | |
# For account name and custom field values we expect the whole thing to be a valid callsign; | |
# for display names we allow it to match anywhere. | |
account = acct['acct'] | |
display_name = acct['display_name'] | |
field_values = list(map(lambda f: f['value'], acct['fields'])) | |
if CALLSIGN_REGEX.fullmatch(account): | |
callsigns.append(account.upper().replace('Ø', '0')) | |
continue | |
cs_in_field = False | |
for v in field_values: | |
if CALLSIGN_REGEX.fullmatch(v): | |
callsigns.append(v.upper().replace('Ø', '0')) | |
cs_in_field = True | |
continue | |
if cs_in_field: | |
continue | |
cs_in_display_name = re.findall(CALLSIGN_REGEX, display_name) | |
if len(cs_in_display_name) > 0: | |
callsigns.append(cs_in_display_name[0].upper().replace('Ø', '0')) | |
# Print output | |
print("\nCallsigns found in your fedi mutuals:") | |
print(','.join(sorted(callsigns))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment