Einleitung
Natürlich hat das Mastodon UI schon eine recht gute Verwaltung, der Followers und Following, aber es wird spannend sein, wenn man die Informationen auch mal lokal hat. Man hat da mehr Möglichkeiten, was die Verfolgung von Veränderungen betrifft, man kann man die Interessengebiete der eigenen Bubble anschauen oder schlicht ein regelmäßiges Backup machen.
Es gab im OpenSearch Blog bereits zwei vorbereitende Artikel, die man sich definitiv anschauen muss.
Mit den Index-Templates haben wir eine Vorlage angelegt, die für alle neue Indexe verwendet werden. Im zweiten Artikel greifen wir auf das Template zurück und legen zwei Indexe an: followers
und following
.
Dazu gibt es noch diese beiden Grundlagen-Artikel:
In dem Einführungs-Artikel wird unsere App (also unsere Sammlung an Python Scripten) registriert. Diese Registrierungsdaten benötigen wir, da wir nicht mehr auf die Public API zugreifen.
Im zweiten Artikel wird zwar beschrieben, wie man einen Toot absendet, aber auch wie man sich mit einem User-Account anmeldet. Das ist für unser kommendes Beispiel wichtig, weil wir von unserem Account die Vernetzung der Accounts lesen wollen.
Jepp, ganz schön viele Bausteine, die man vorab braucht, aber ihr folgt hier einem großen Plan ;-) - alle Artikel haben ihren Sinn und werden Stück für Stück zusammengefügt.
User-Account Anmeldung
Das Script-Präfix beginnt diesmal damit auch anders:
import json
from mastodon import Mastodon
from opensearchpy import OpenSearch
def login_os(host, port):
# Client zu dem Dev Cluster (ohne SSL, ohne Anmeldung)
return OpenSearch(
hosts=[{'host': host, 'port': port}],
http_compress=True, # enables gzip compression for request bodies
use_ssl=False
)
def login_mastodon(url, user, password):
mastodon = Mastodon(
client_id='ep********************************************Xo', # Use your registred ID
client_secret='AY******************************************0s', # Use your registred secret
api_base_url=url
)
mastodon.access_token = mastodon.log_in(
username=user,
password=password,
scopes=['read', 'write']
)
return mastodon
Wichtig ist, dass die Registrierungsdaten eurer App da oben eingetragen werden.
Um zu schauen, ob das alles klappt, mal diese Scriptzeilen anfügen:
client = login_os('localhost', 9200)
mastodon = login_mastodon('https://social.tchncs.de', '<your email-address>', '<your secret password>')
# It's me:
me = mastodon.me()
print (f"Me: {me['id']} = {me['username']}")
Und wieder der Hinweis: Da oben die Mailadresse und Kennwort des persönlichen Accounts.
Zusammen ausgeführt, wird eine ID und ein Benutzername ausgegeben - oder es hagelt Fehlermeldungen. Vertippt? App wirklich registriert? Bitte das erst korrigieren, dann geht es hier weiter:
Followers laden und speichern
Im letzten Blog-Artikel haben wir zwei Indexe angelegt: followers und following. Die wollen wir nun mit unseren geliebten Mutuals füllen - und zwar allen.
Bei den Toots hatten wir immer eine Begrenzung der Ladevorgänge der Seiten, das machen wir nicht. Wir haben eine Endlosschleife. Mein erster Versuch sah so aus (und funktioniert auch):
page = None
while True:
page = mastodon.account_followers(id=me['id'], limit=80) if page is None else mastodon.fetch_next(page)
if page:
for account in page:
client.index('followers', id=account['id'], body=account)
else:
break
Bestimmt hat jemand eine bessere Idee für einen Schleife oder Iterator, aber das ist erstmal eingängig.
Allerdings müssten wir das zweimal programmieren (für followers und following), weil die Mastodon API, zwei verschiedene Methoden zum Laden nutzt.
Softwareentwickler sind aber von Haus aus wirklich faul und nichts ist schlimmer als redundanter Code, wo nur eine Zeile unterschiedlich ist. Die Lösung sind Callback-Funktionen. Auch Python beherrscht das und wir basteln uns mal eine Funktion:
Accounts laden und speichern
def load_to_index(client, index_name, initial_load, next_load):
page = None
while True:
page = initial_load(id=me['id'], limit=80) if page is None else next_load(page)
if page:
for account in page:
client.index(index_name, id=account['id'], body=account)
else:
break
client
ist unser OpenSearch Objekt, index_name
unser Index. Dann kommen die Callback-Parameter: initial_load
und next_load
.
Das wird auch sehr einfach aufgerufen:
load_to_index(client, 'followers', mastodon.account_followers, mastodon.fetch_next)
load_to_index(client, 'following', mastodon.account_following, mastodon.fetch_next)
Das ist schon ziemlich cool.
Beim Import möchte ich aber sehen, was passiert. Also kommt etwas geschwätzige Statistik hinzu. Die nächste Variante:
def load_to_index(client, index_name, initial_load, next_load):
print(f'Import {index_name}')
page = None
created = 0
updated = 0
while True:
page = initial_load(id=me['id'], limit=80) if page is None else next_load(page)
if page:
for account in page:
response = client.index(index_name, id=account['id'], body=account)
if response['result'] == "created":
print(f" New in {index_name}: {account['acct']}")
created += 1
elif response['result'] == "updated":
updated += 1
else:
break
client.indices.refresh(index=index_name)
print(f'Finished "{index_name}". Created {created} accounts and updated {updated}')
Ja, das Refresh dürfen wir nicht vergessen und abschließend eine Ausgabe, was passiert ist.
Ok, bekommt ihr das selber zusammengesetzt?
Als Ergebnis sollte man das sehen:
Import followers
Finished "followers". Created 197 accounts and updated 0
Import following
Finished "following". Created 139 accounts and updated 0
Ruft man das Script erneut auf:
Import followers
Finished "followers". Created 0 accounts and updated 197
Import following
Finished "following". Created 0 accounts and updated 139
Wenn man das alle paar Tage mal macht und das Glück hat mehr Follower zu bekommen, erhöht sich die Zahl kontinuierlich.
Allerdings haben wir auch ein Problem mit dieser simplen Art, von Mastodon die Accounts zu synchronisieren. Welches? Das kommt im nächsten Artikel. Ja ja, der Cliffhanger - da ist er wieder.
Comments
No comments yet. Be the first to react!