# Mastodon, Teil 1: Toots abrufen

Quelle: https://dev.inf.zone/exercises/11/mastodon/

## Aufgabe

**Auf einen Blick**

- **Was:** Ein Python-Programm, das über die Programmierschnittstelle (API) von [Mastodon](https://mastodon.social/) Beiträge zu einem Hashtag lädt und nach Kriterien filtert. Die Beiträge heißen bei Mastodon **Toots**.
- **Datei:** `mastodon_oop.py` im Ordner `mastodon_oop` (Codegerüst). Beide Teile der Aufgabe schreiben Sie in diese Datei.
- **Teil 1 (diese Seite):** Zugriffstoken anlegen, dann die Klasse `Toot` und die Funktionen `get_text_content` und `load` schreiben.
- **[Teil 2](https://dev.inf.zone/exercises/11/mastodon-2/):** Trigger-Klassen, die prüfen, ob ein Toot ein Kriterium erfüllt (Medien, Wörter im Text, Veröffentlichungszeit, verknüpft mit Not, And, Or), und die Funktion `filter_toots`.
- **Am Ende:** `python mastodon_oop.py` lädt bis zu 10 Toots zu einem Hashtag und gibt die aus, auf die Ihre Trigger zutreffen.

**Wozu das Ganze?**

Mit dieser Aufgabe üben Sie zum einen die objektorientierten Konzepte von Python. Zum anderen lernen Sie, sich im Ökosystem von Python zurechtzufinden und mit einer kleinen Auswahl der verfügbaren Werkzeuge zu arbeiten. Die Aufgabe ist eine gute Übung, geht in Umfang und Ausführlichkeit aber über das hinaus, was in der Prüfung verlangt wird. Die meisten Schritte sind kleinteilig erläutert; an einigen Stellen sind die Hinweise bewusst weniger genau, damit Sie die Lösung selbst erkunden können. Wir erwarten nicht, dass Sie die Aufgabe ohne Hilfe lösen: Helfen Sie sich gegenseitig, nutzen Sie das Forum und die Tutorien.

![Screenshot von Mastodon](https://dev.inf.zone/exercises/11/mastodon/mastodon-v4.3.1-screenshot.jpg)

Diese Aufgabe wurde an der FAU Erlangen-Nürnberg entwickelt ([Institute of Information Systems](https://www.is.rw.fau.de/), Prof. Dr. Martin Matzner) und wird gemäß Creative-Commons-Lizenz CC BY-NC-SA 4.0 bereitgestellt. Es handelt sich um eine angepasste Version der Aufgabe [Mastodon OOP](https://introcs.is.rw.fau.de/landing_page/pset7_mastodon/).

### So kommen die Toots ins Programm

1. **API:** Ihr Programm ruft keine Webseite ab, sondern fragt Mastodon über eine API: eine Schnittstelle, die auf festgelegte Anfragen Daten statt fertiger Seiten liefert.
2. **Zugriffstoken:** Mit einem Zugriffstoken weist sich Ihr Programm bei Mastodon aus und handelt in Ihrem Namen. Das Token ist geheim wie ein Passwort.
3. **Mastodon.py:** Die Python-Bibliothek [Mastodon.py](https://mastodonpy.readthedocs.io/en/stable/index.html) übernimmt die Kommunikation mit der API. Mit `mastodon.timeline_hashtag("python", limit=10)` erhalten Sie eine Liste der höchstens 10 neuesten Toots mit dem Hashtag `#python`.
4. **Status-dict:** Jeder Toot in dieser Liste ist ein Dictionary ([Status-dict](https://mastodonpy.readthedocs.io/en/stable/02_return_values.html#mastodon.return_types.Status)) mit vielen Schlüsseln. Für die Klasse `Toot` brauchen Sie fünf davon:

| Parameter von `Toot` | Schlüssel im Status-dict | Inhalt |
| -------------------- | ------------------------ | ------ |
| `content`  | `content`           | der Text des Toots – im Status-dict als HTML, im `Toot` als reiner Text |
| `account`  | `account`           | das Konto, das den Toot veröffentlicht hat |
| `hashtags` | `tags`              | die Hashtags des Toots |
| `pubdate`  | `created_at`        | die Veröffentlichungszeit, ein `datetime` mit Zeitzone |
| `media`    | `media_attachments` | Liste der Medienanhänge (Bilder, Videos, …); jeder Anhang ist ein Dictionary, unter anderem mit `type` und `url` |

**Beispiel** – ein Status-dict, stark gekürzt:

```python
{
    "content": '<p>Heute lerne ich <a class="mention hashtag">#<span>Python</span></a>!</p>',
    "account": {"acct": "alice", ...},
    "tags": [{"name": "python", ...}],
    "created_at": datetime(2026, 1, 10, 12, 0, tzinfo=tzutc()),
    "media_attachments": [],
    ...
}
```

Daraus wird ein `Toot` mit `content` = `"Heute lerne ich #Python!"`, `account` = `"alice"`, `hashtags` = `["python"]`, `pubdate` = die Zeit aus `created_at` und `media` = `[]`.

Mehr zu Mastodon und zu APIs steht am Ende der Seite unter „Zum Weiterlesen“.

## Vorbereitung

### Aufgabenmaterial

**Aufgabenmaterial herunterladen**

Öffnen Sie VS Code entsprechend Ihrem [Setup](https://dev.inf.zone/extras/setup/), klicken Sie auf Ihr Terminalfenster und führen Sie `cd` aus. Die Eingabeaufforderung Ihres Terminalfensters sollte ungefähr wie folgt aussehen:

```bash
$
```

Laden Sie das Aufgabenmaterial herunter, entpacken Sie es, löschen Sie die ZIP-Datei und wechseln Sie in den neuen Ordner:

```bash
wget https://dev.inf.zone/download/exercises/11/mastodon_oop.zip
unzip mastodon_oop.zip
rm mastodon_oop.zip
cd mastodon_oop
```

Wenn Sie jetzt `ls` ausführen, sollten Sie die Datei `mastodon_oop.py` sehen. Falls nicht, wiederholen Sie die Schritte und prüfen Sie, wo ein Fehler aufgetreten sein könnte.

Installieren Sie dann mit pip, dem Paketmanager von Python, die drei Bibliotheken, die `mastodon_oop.py` importiert – Mastodon.py, Beautiful Soup und pytz:

```bash
pip install Mastodon.py beautifulsoup4 pytz
```

Sehen Sie sich `mastodon_oop.py` an, bevor Sie loslegen: Das Gerüst enthält alle Klassen und Funktionen beider Teile samt `TODO`-Kommentaren. Fertig ist nur die Klasse `Trigger`; alles andere enthält vorerst nur `pass` (siehe [The pass statement](https://docs.python.org/3/reference/simple_stmts.html#the-pass-statement)). Die Parameterlisten im Gerüst sind leer – ergänzen Sie die Parameter, wenn Sie eine Funktion oder Methode schreiben.

### Zugriffstoken anlegen

1. Erstellen Sie ein Konto auf [mastodon.social](https://mastodon.social/) und melden Sie sich an.
2. Klicken Sie auf die drei Punkte rechts neben Ihrem Benutzernamen, dann auf `Preferences`, dann links in der Navigationsleiste auf `Development`.
3. Wählen Sie oben rechts `New application`. Geben Sie unter `Application name` einen passenden Namen ein, wählen Sie unter `Scopes` nur `read` und lassen Sie den Rest unverändert. Klicken Sie ganz unten auf `Submit`.
4. In der Liste, die nun erscheint, klicken Sie auf den Namen Ihrer Anwendung (erste Spalte). Dort stehen `Client key`, `Client secret` und `Access token`.
5. Tragen Sie die drei Werte oben in `mastodon_oop.py` bei `client_id`, `client_secret` und `access_token` ein. `api_base_url` bleibt unverändert. Geben Sie die Datei mit Ihren Werten nicht weiter.

## Spezifikation

### Schritt 1: Die Klasse `Toot`

- `__init__` nimmt die fünf Parameter `content`, `account`, `hashtags`, `pubdate` und `media` entgegen (Bedeutung siehe Tabelle oben) und speichert sie in Instanzvariablen mit Unterstrich (etwa `self._content`).
- Machen Sie jede der fünf mit dem Dekorator `@property` lesbar. Andere Klassen – etwa die Trigger in Teil 2 – greifen dann mit `toot.content`, `toot.account` usw. darauf zu.
- `__str__` gibt einen lesbaren String mit den wichtigsten Attributen des Toots zurück, damit Sie Toots mit `print` ausgeben können (Beispiel unter „Testen“).

### Schritt 2: Text aus HTML isolieren

Schreiben Sie eine Funktion `get_text_content(toot)`. Sie bekommt ein Status-dict und gibt den Text aus dessen `content` ohne HTML-Tags als String zurück. Verwenden Sie dafür die Bibliothek [Beautiful Soup](https://beautiful-soup-4.readthedocs.io/en/latest/#quick-start).

Aus dem `content` des Beispiels oben wird so `Heute lerne ich #Python!`.

### Schritt 3: Toots laden

Schreiben Sie eine Funktion `load(hashtag)`, die Toots mit dem Hashtag `hashtag` von Mastodon lädt:

1. Legen Sie eine leere Liste für die Toots an.
2. Rufen Sie [`timeline_hashtag`](https://mastodonpy.readthedocs.io/en/stable/07_timelines.html#mastodon.Mastodon.timeline_hashtag) auf und begrenzen Sie die Antwort mit `limit=10` auf höchstens 10 Toots.
3. Erzeugen Sie aus jedem Status-dict ein `Toot`-Objekt (Zuordnung der Schlüssel siehe Tabelle oben) und fügen Sie es der Liste hinzu. Den Inhalt speichern Sie als reinen Text, also mit `get_text_content`, nicht als HTML.
4. Geben Sie die Liste zurück.

## Hilfestellung

Klicken Sie auf die folgenden Tipps, um einige Ratschläge zu erhalten. Versuchen Sie aber zunächst, selbst so weit wie möglich zu kommen.

**Text mit Beautiful Soup isolieren**

- Erzeugen Sie zuerst ein Beautiful-Soup-Objekt aus dem HTML-Inhalt und dem Parser `"html.parser"`; wie das geht, zeigt der [Quick Start](https://beautiful-soup-4.readthedocs.io/en/latest/#quick-start) der Dokumentation.
- Die Methode `get_text` dieses Objekts gibt den Textinhalt des HTML-Baums zurück.

**Die Daten von Mastodon verarbeiten**

`toot_data = mastodon.timeline_hashtag(hashtag, limit=10)` gibt eine Liste von Status-dicts zurück. Über diese Liste können Sie mit einer `for`-Schleife iterieren:

```python
for data in toot_data:
    # TODO: create toot-objects from data
```

- Lassen Sie sich `data` einmal mit `print` ausgeben, um die Struktur zu sehen.
- Übergeben Sie den Hashtag ohne `#`, also `"python"` statt `"#python"`; sonst meldet Mastodon.py einen Fehler.
- `data["account"]` und die Einträge in `data["tags"]` sind selbst Dictionaries. Für `account` genügt der Kontoname unter `"acct"`, für `hashtags` eine Liste der Namen unter `"name"`.

## Testen

Rufen Sie im Abschnitt `if __name__ == '__main__':` die Funktion `load` mit einem Hashtag Ihrer Wahl auf und geben Sie die geladenen Toots mit `print` aus. Führen Sie das Programm aus:

```bash
python mastodon_oop.py
```

Jeder Toot sollte ohne HTML-Tags erscheinen, etwa so (das genaue Format bestimmt Ihre `__str__`-Methode):

```
Toot von @bob
Veröffentlicht am: 2026-01-10 14:00:00+00:00
Inhalt: Mein Python-Setup, siehe Foto.
Hashtags: python
Medien: https://example.org/foto.jpg
```

Dann geht es weiter mit [Teil 2: Toots filtern](https://dev.inf.zone/exercises/11/mastodon-2/).

### Korrektheit

Führen Sie in Ihrem Terminal den folgenden Befehl aus, um die Korrektheit Ihrer Arbeit zu überprüfen:

```bash
check50 -l inf-zone/exercises/2026/mastodon/load
```

## Abgeben

Geben Sie im Ordner `mastodon_oop` ab:

```bash
inf upload mastodon/load
```

Danach sehen Sie, welche Tests Ihr Programm besteht und ob die Übung für die Bonuspunkte zählt. Wie Sie `inf` installieren und sich anmelden, steht unter [Abgeben mit `inf`](https://dev.inf.zone/faq/uebung-solutions/#inf-installieren).

## Zum Weiterlesen: Mastodon und APIs

Für die Lösung der Aufgabe nicht nötig.

Eine API (Application Programming Interface) legt fest, wie Programme miteinander kommunizieren: welche Anfragen es gibt und in welchem Format die Daten zurückkommen. Die Anfragen gehen an Endpunkte, also festgelegte URLs, die jeweils für eine Aktion stehen, etwa „die neuesten Toots zu einem Hashtag“. Ein Schlüssel oder Token weist aus, wer anfragt und was er darf. Soziale Netzwerke wie Mastodon bieten solche APIs an, damit Programme Beiträge abrufen oder veröffentlichen können. Mastodon.py ist ein sogenannter Wrapper: eine Bibliothek, die die Anfragen an die API in gewöhnliche Python-Funktionen verpackt.

[Mastodon](https://mastodon.social/) ist eine Social-Media-Plattform, die [Eugen Rochko](https://de.wikipedia.org/wiki/Eugen_Rochko) 2016 als Alternative zu zentralisierten Netzwerken gestartet hat. Die Software ist Open Source: Der Quellcode ist frei verfügbar und darf genutzt, verändert und weitergegeben werden. Statt eines zentralen Servers gibt es viele unabhängig betriebene Server, sogenannte Instanzen, die zusammen ein Netzwerk bilden (föderiertes Modell). Jede Instanz hat eigene Regeln und Moderation; man wählt eine nach Interessen oder Vorlieben und kann trotzdem Konten auf anderen Instanzen folgen.
