Plugin Events
Plugins reagieren auf Ereignisse, die in Owncast stattfinden, indem sie einen Handler für jedes Ereignis definieren, das sie interessiert. Definieren Sie nur die Handler, die Sie möchten: Ein fehlender Handler bedeutet keine Anmeldung, und das SDK leitet die Abonnentenliste des Manifests davon ab, welche Handler vorhanden sind, sodass es nichts anderes gibt, was synchronisiert werden muss.
Der untenstehende Code wird für beide SDKs angezeigt. Wählen Sie Ihre Sprache mit den Tabs, und Ihre Auswahl bleibt über die Dokumentation hinweg bestehen. Neu dabei? Sehen Sie sich zuerst die JavaScript oder Python Einrichtungseiten an.
- JavaScript
- Python
const { definePlugin, owncast, filter } = require('@owncast/plugin-sdk');
module.exports = definePlugin({
onChatMessage(msg) {
/* react to a chat message */
},
onStreamStarted(info) {
/* react to the stream going live */
},
});
Handler sind Methoden des Objekts, das Sie an definePlugin übergeben, benannt in camelCase (onChatMessage, onStreamStarted, …). Payload-Felder sind ebenfalls camelCase (msg.user.displayName, msg.clientId).
from owncast_plugin import plugin, owncast, filter
@plugin.on_chat_message
def handle_chat(msg):
# react to a chat message
...
@plugin.on_stream_started
def handle_live(info):
# react to the stream going live
...
Handler sind dekorierte Funktionen (@plugin.on_chat_message, @plugin.on_stream_started, …). Payload-Felder sind snake_case (msg.user.display_name, msg.client_id). Verwenden Sie msg.raw für das zugrunde liegende Dict.
Payloads werden in ihrer Drahtform angezeigt. Jedes SDK exponiert die Felder idiomatisch: das JavaScript SDK wie es ist, das Python SDK als snake_case Attribute über dasselbe JSON (mit dem rohen Dict ebenfalls verfügbar).
Chat-Ereignisse
Ein Chat-fokussiertes Plugin erstellen? Chat-Plugins sind ein freundlicherer Ausgangspunkt.
Chatnachricht: chat.message.received
Feuert einmal pro Chatnachricht, nachdem die Filter ausgeführt wurden und die Nachricht an die Zuschauer gesendet wird.
interface ChatMessage {
id: string;
user?: User; // full sender identity (see User below); absent for the rare message with no account
clientId?: number; // originating connection; pass to the chat send-to / reply-to APIs for private replies
body: string; // raw text, not HTML-rendered markup
timestamp: string; // RFC3339Nano / ISO-8601, e.g. "2026-05-28T14:00:00.123456789Z"
}
- JavaScript
- Python
module.exports = definePlugin({
onChatMessage(msg) {
if (msg.user?.scopes?.includes('MODERATOR')) {
owncast.chat.send(`hi mod ${msg.user.displayName}`);
}
},
});
@plugin.on_chat_message
def greet_mods(msg):
if msg.user and "MODERATOR" in (msg.user.scopes or []):
owncast.chat.send(f"hi mod {msg.user.display_name}")
user enthält die vollständige Senderidentität, also speichert den benutzerspezifischen Zustand auf der stabilen user.id und steuert moderatorenexklusive Verhaltensweisen auf user.scopes (z.B. "MODERATOR") anstatt mit dem Anzeigenamen abzugleichen. Um privat auf den Sender zu antworten, verwenden Sie die Chat-Antwort-API (siehe Owncast APIs).
timestamp ist die Wanduhrzeit des Hosts für die Nachricht. Die Sandbox-Uhr funktioniert, aber timestamp ist deterministisch und die richtige Wahl, um die verstrichene Zeit über Ereignisse hinweg zu vergleichen oder in Tests zu bestätigen.
Es sind keine Berechtigungen erforderlich, um zu abonnieren.
Ältere Hosts lieferten
userals einfachen Anzeigenamen-String anstelle des Identitätsobjekts. Wenn Sie Hosts unterstützen, die vor der Identitäts-Payload existierten, lesen Sie sie defensiv. Sehen Sie auf Ihrer SDK-Seite nach dem Idiom.
Chatbenutzer beigetreten / getrennt: chat.user.joined, chat.user.parted
Feuert, wenn sich ein Chatbenutzer verbindet oder trennt.
interface User {
id: string;
displayName: string;
displayColor: number; // index into the instance's user-color palette, not a literal color
previousNames?: string[];
createdAt?: string; // ISO-8601
disabledAt?: string; // ISO-8601 if banned, omitted otherwise
isBot?: boolean;
isAuthenticated?: boolean;
scopes?: string[];
}
- JavaScript
- Python
module.exports = definePlugin({
onChatUserJoined(user) {
owncast.chat.send(`welcome ${user.displayName}`);
},
onChatUserParted(user) {
/* … */
},
});
@plugin.on_chat_user_joined
def welcome(user):
owncast.chat.send(f"welcome {user.display_name}")
@plugin.on_chat_user_parted
def farewell(user):
...
Es sind keine Berechtigungen erforderlich.
Chatbenutzer umbenannt: chat.user.renamed
Feuert, wenn ein Chatbenutzer seinen Anzeigenamen ändert.
interface { user: User; previousName: string }
Es sind keine Berechtigungen erforderlich.
Nachricht moderiert: chat.message.moderated
Feuert, wenn ein Moderator eine Chatnachricht verbirgt oder wieder sichtbar macht.
interface { messageId: string; visible: boolean; moderator?: User }
Es sind keine Berechtigungen erforderlich.
Stream-Lebenszyklus
Stream gestartet: stream.started
Feuert, wenn eine Übertragung beginnt.
interface { startedAt?: string; title?: string; summary?: string }
- JavaScript
- Python
module.exports = definePlugin({
onStreamStarted(info) {
owncast.chat.send(`live now: ${info.title}`);
},
onStreamStopped(info) {
/* … */
},
onStreamTitleChanged(change) {
/* change.to */
},
});
@plugin.on_stream_started
def announce(info):
owncast.chat.send(f"live now: {info.title}")
@plugin.on_stream_stopped
def wrap_up(info):
...
@plugin.on_stream_title_changed
def retitle(change):
... # change.to
Es sind keine Berechtigungen erforderlich.
Stream gestoppt: stream.stopped
Feuert, wenn eine Übertragung endet.
interface { stoppedAt?: string }
Es sind keine Berechtigungen erforderlich.
Streamtitel geändert: stream.title.changed
Feuert, wenn der Streamer den Titel während des Streams aktualisiert.
interface { from: string; to: string }
from ist derzeit immer leer: Das Ereignis Titel geändert von Owncast enthält nur den neuen Titel.
Es sind keine Berechtigungen erforderlich.
Fediverse-Ereignisse
Owncast exposes internal plugin event subscriptions for inbound Fediverse activity. Dies sind Plugin-Ereignisse, keine externen HTTP-Webhooks. Jedes Abonnement in diesem Abschnitt erfordert die Berechtigung fediverse.inbound.
| Ereignis | JavaScript-Handler | Python-Handler | Payload |
|---|---|---|---|
fediverse.follow | onFediverseFollow | @plugin.on_fediverse_follow | { actor } |
fediverse.like | onFediverseLike | @plugin.on_fediverse_like | { actor, target } |
fediverse.repost | onFediverseRepost | @plugin.on_fediverse_repost | { actor, target } |
fediverse.quote | onFediverseQuote | @plugin.on_fediverse_quote | FediverseQuote |
fediverse.mention | onFediverseMention | @plugin.on_fediverse_mention | FediverseInboundPost |
fediverse.reply | onFediverseReply | @plugin.on_fediverse_reply | FediverseInboundPost |
fediverse.activity | onFediverse | @plugin.on_fediverse | Rohe ActivityPub JSON-Objekt |
Folgen, liken, reposten und zitieren
interface FediverseActor {
name: string;
handle: string;
url?: string;
image?: string;
}
interface FediverseEngagement {
actor: FediverseActor;
target?: { url: string };
}
interface FediverseQuote extends FediverseEngagement {
target: { url: string }; // locally authored post being quoted
content?: string; // rendered HTML from the source instance
contentText?: string; // plain-text version
url: string; // remote quote post permalink
postedAt?: string; // ISO-8601
inReplyTo?: string;
attachments?: { url: string; mediaType: string; alt?: string }[];
language?: string;
}
Ein Follow enthält nur actor. Likes and reposts also contain target.
A quote contains target for the locally authored post and url for the remote quote post. Content metadata is included when the requesting server embeds its quote Note in the QuoteRequest. Some servers send only the quote post IRI, so content, contentText, postedAt, inReplyTo, attachments, and language are optional.
- JavaScript
- Python
module.exports = definePlugin({
onFediverseFollow(event) {
owncast.chat.send(`new follower: ${event.actor.handle}`);
},
onFediverseQuote(event) {
console.log(`${event.actor.handle}: ${event.contentText ?? 'quoted your post'}`);
console.log(`quote: ${event.url}`);
},
});
@plugin.on_fediverse_follow
def thank(event):
owncast.chat.send(f"new follower: {event.actor.handle}")
@plugin.on_fediverse_quote
def record_quote(event):
print(f"{event.actor.handle}: {event.content_text or 'quoted your post'}")
print(f"quote: {event.url}")
actor.handle ist die vollständig qualifizierte Adresse, wie @alice@fediverse.example. Die Follow-Beispiele rufen ebenfalls owncast.chat.send auf, das separat chat.send erfordert:
{ "permissions": ["fediverse.inbound", "chat.send"] }
Erwähnen und Antworten
Beide erhalten ein FediverseInboundPost:
interface FediverseInboundPost {
actor: FediverseActor;
content: string; // rendered HTML from the source instance
contentText: string; // plain-text version, usually what you want
url: string; // permalink on the source instance
postedAt: string; // ISO-8601
inReplyTo?: string; // parent post URL, set when this is a reply
attachments?: { url: string; mediaType: string; alt?: string }[];
language?: string;
}
Diese spezialisierten Hooks akzeptieren eine verifizierte Create-Aktivität, die genau einen Note enthält. Die Notiz muss dem Aktivitätsakteur zugeordnet sein. Eine Erwähnung muss sich auf den lokalen Owncast-Akteur beziehen. Eine Antwort muss auf einen Beitrag verweisen, der von der lokalen Owncast-Instanz gespeichert ist.
Verwenden Sie contentText für Analysen oder um in den Chat zurückzugeben. Verwenden Sie content nur, wenn Sie das ursprüngliche Format benötigen, und reinigen Sie es vor der Darstellung.
Rohe eingehende Aktivität
fediverse.activity erhält die verifizierte eingehende ActivityPub-Aktivität als ihr rohes JSON-Objekt. Owncast sendet es, nachdem die HTTP-Signatur die Überprüfung bestanden hat und der Ursprungsort des Aktivitätsakteurs mit dem Ursprungsort des unterzeichnenden Schlüssels übereinstimmt.
Der Catch-All wird zusätzlich zu einem spezialisierten Handler ausgeführt. Zum Beispiel kann ein akzeptiertes Zitat sowohl onFediverseQuote als auch onFediverse aufrufen.
- JavaScript
- Python
module.exports = definePlugin({
onFediverse(activity) {
if (typeof activity.type === 'string') {
console.log(`inbound activity: ${activity.type}`);
}
},
});
@plugin.on_fediverse
def record_activity(activity):
if isinstance(activity.type, str):
print(f"inbound activity: {activity.type}")
Die Überprüfung der Signatur und des Ursprungs des Akteurs legt fest, wo die Aktivität herkam. Sie machen jedoch nicht die Felder sicher. Behandeln Sie das rohe Objekt als nicht vertrauenswürdige Plugin-Eingabe. Überprüfen Sie die Feldtypen und erforderlichen Werte, bereinigen Sie den Inhalt vor der Darstellung und validieren Sie URLs, bevor Sie diese abrufen.
Filterkette
Filter sehen Chatnachrichten, bevor sie gesendet werden, mit der Möglichkeit, diese zu ändern oder zu verwerfen. Sie werden sequenziell in der Prioritätsreihenfolge (niedrigste zuerst ausgeführt), und jeder Filter kann die Kette unterbrechen: Ein drop beendet sie, während eine modify die neue Nutzlast an den nächsten Filter übergibt.
Chatnachrichtenfilter: chat.message.received (Filter)
Ein Filter-Handler erhält die gleiche ChatMessage-Form wie das Chatnachrichtenevent und gibt eines von drei Ergebnissen zurück:
- passieren: die Nachricht unverändert durchlassen.
- modifizieren: die Nachricht durch eine neue Nutzlast ersetzen, die an den nächsten Filter weitergeleitet wird.
- verwerfen: die Nachricht mit einem Grund blockieren. Die Kette endet hier.
- JavaScript
- Python
module.exports = definePlugin({
filterChatMessage(msg) {
if (msg.body.includes('spam')) return filter.drop('spam');
if (msg.body.includes('damn'))
return filter.modify({ ...msg, body: msg.body.replace('damn', '****') });
return filter.pass();
},
});
@plugin.filter_chat_message
def clean(msg):
if "spam" in msg.body:
return filter.drop("spam")
if "damn" in msg.body:
return filter.modify({**msg.raw, "body": msg.body.replace("damn", "****")})
return filter.pass_()
Benötigt die chat.filter-Berechtigung. Das Lesen oder Umschreiben jeder Chatnachricht hat eine bedeutende Nebenwirkung, daher muss der Admin die Berechtigung sehen, um sie zu erteilen. Der Host lehnt das Laden ab, wenn ein Plugin den Filter-Handler definiert, ohne die Berechtigung zu deklarieren.
Filterpriorität (optional)
Jeder Filter kann eine Priorität deklarieren. Niedrigere Zahlen werden früher ausgeführt (Standard 100). Verwenden Sie dies, wenn das Verhalten Ihres Plugins davon abhängt, ob andere Filter bereits ausgeführt wurden (zum Beispiel sollte ein Schimpfworte-Filter normalerweise vor einem Übersetzer ausgeführt werden). Siehe Ihre SDK-Seite, wo Sie es festlegen können.
Filter-Sicherheit
- Fehler werden als passieren behandelt. Ein werfender Filter blockiert niemals den Chat. Die Kette wird mit der ursprünglichen Nachricht fortgesetzt.
- Filter sind zeitlich auf 50 ms begrenzt. Ein langsamer Filter wird abgebrochen und als passieren behandelt.
- Nach 5 aufeinanderfolgenden Fehlern (Fehler oder Zeitüberschreitungen) wird das Plugin für den Rest der Sitzung automatisch deaktiviert, mit einer einmaligen Protokollzeile. Ein erfolgreicher Filteraufruf setzt den Zähler zurück, sodass vorübergehende Unzuverlässigkeiten nicht akkumuliert werden. Starten Sie den Host neu, um ihn wieder zu aktivieren.
Befehltabellen
Deklarieren Sie eine Befehltabelle für Aliase, Abkühlzeiten, Moderatorenbeschränkungen, geparste Argumente und automatische !help-Listen. Die Beschränkung nutzt die Identität des Absenders (user.scopes, user.id), nicht einen Namenraten-Vorhersage.
- JavaScript
- Python
module.exports = definePlugin({
commands: {
uptime: { description: "How long we've been live", run: ctx => ctx.reply('a while!') },
},
});
plugin.commands({
"uptime": {"description": "How long we've been live",
"run": lambda ctx: ctx.reply("a while!")},
})
Siehe Chatbefehle für die vollständige Referenz zur Befehltabelle (Aliases, Abkühlzeiten, Mod-only Gate, !help).
HTTP-Handler
HTTP-Anforderung
Wird für jede Anfrage an /plugins/\<your-slug>/* ausgelöst, die nicht mit einer statischen Datei in public/ übereinstimmt. Gibt ein Antwortobjekt zurück.
interface IncomingHttpRequest {
method: string;
path: string; // relative to /plugins/<your-slug>/
query: Record<string, string>;
headers: Record<string, string>;
body: string;
remoteAddr: string;
authenticated: boolean; // came from any authenticated Owncast session, admin or viewer
user?: { id: string; displayName: string; scopes: string[] }; // user-token requests only
}
interface OutgoingHttpResponse {
status?: number; // default 200
headers?: Record<string, string>;
body?: string;
}
- JavaScript
- Python
module.exports = definePlugin({
onHttpRequest(req) {
if (req.path === '/status') return { status: 200, body: '{"ok":true}' };
return { status: 404 };
},
});
@plugin.get("/status")
def status(req):
return {"status": 200, "body": '{"ok":true}'}
Endpunkte sind standardmäßig öffentlich. Administrationsfunktionen an req.authenticated beschränken. Paths matching a key in admin.pages are auth-gated by the host before your handler runs, so for those routes you don't need to check.
Benötigt die http.serve-Berechtigung. Das JavaScript-SDK bietet einen einzelnen onHttpRequest-Catch-All. Das Python-SDK fügt deklarative pro-Pfad/pro-Methode-Routen hinzu (@plugin.get, @plugin.route, …). Siehe HTTP-Dienste für das vollständige Anforderungsmodell.
Authentifizierung
Auth check hook
Wird nur für das aktivierte auth.gate Plugin ausgelöst und nur beim Laden der /-Seite eines Zuschauers, niemals auf dem heißen Pfad (Video-Segmente, die API, Chat). Zu diesem Zeitpunkt hat der Host bereits das Sitzungscookie des Zuschauers überprüft und ihre Identität ermittelt. Ihr Handler entscheidet, ob diese Sitzung fortgesetzt werden sollte. Es ist optional: Lassen Sie es weg, und ein gültiges Cookie reicht aus, bis es abläuft.
Geben Sie eines von drei Urteilen über den authCheck-Helper zurück:
- ok: die Sitzung unverändert behalten.
- aktualisieren: behalten und das Cookie neu ausstellen, optional mit einem neuen
ttlin Sekunden (gleitende Ablaufzeit). - verweigern: die Sitzung beenden und den Zuschauer zurück zum Anmeldebildschirm leiten. So widerrufen Sie den Zugriff (ein Benutzer wurde gelöscht oder gesperrt).
interface AuthCheckRequest {
user: {
id: string;
displayName: string;
scopes?: string[];
isAuthenticated?: boolean;
};
}
type AuthCheckResult =
{ action: 'ok' } | { action: 'refresh'; ttl?: number } | { action: 'deny'; reason?: string };
- JavaScript
- Python
const { definePlugin, owncast, authCheck } = require('@owncast/plugin-sdk');
module.exports = definePlugin({
onAuthCheck(req) {
if (owncast.kv.get(`banned:${req.user.id}`)) {
return authCheck.deny('access revoked');
}
return authCheck.ok();
},
});
from owncast_plugin import plugin, owncast, auth_check
@plugin.on_auth_check
def check(req):
if owncast.kv.get(f"banned:{req.user.id}"):
return auth_check.deny("access revoked")
return auth_check.ok()
Benötigt auth.gate, und es schlägt geschlossen fehl: Wenn der Handler einen Fehler verursacht oder nicht antwortet, behandelt der Host diesen Seitenaufruf als Verweigerung. Da die Prüfung nur auf / ausgeführt wird, behält ein Zuschauer, dessen Zugriff Sie widerrufen, alle offenen Registerkarten bis sie neu laden oder das Cookie abläuft. Die Sitzung ttl ist die harte Grenze.
Inhalts-Handler
These two handlers let a plugin generate tab or extra-page HTML at request time. Use them when content should be personalised per viewer or depend on live stream data. They're the dynamic counterpart to shipping a static HTML file via a tab value's content member or manifest.extraPageContent.content.
Beide Handler erhalten eine ContentRequest:
interface ContentRequest {
slug: string; // manifest.tabs object key or manifest.extraPageContent.slug
user?: User; // viewer's chat identity: present when authenticated, absent for anonymous viewers
}
Geben Sie den kompletten HTML-String für den Inhaltsblock zurück. Wenn Sie den Slug nicht erkennen, geben Sie eine leere Zeichenfolge zurück.
- JavaScript
- Python
module.exports = definePlugin({
onTabContent(ctx) {
if (ctx.slug === 'stats') {
return `<h1>Live stats for ${ctx.user?.displayName ?? 'viewer'}</h1>`;
}
return '';
},
onPageContent(ctx) {
return ctx.slug === 'banner' ? '<p>Welcome!</p>' : '';
},
});
@plugin.on_tab_content("stats")
def stats(ctx):
name = ctx.user.display_name if ctx.user else "viewer"
return f"<h1>Live stats for {name}</h1>"
@plugin.on_page_content("banner")
def banner(ctx):
return "<p>Welcome!</p>"
Tab-Inhalt
Called when a value in the manifest.tabs object has no static content file. The host passes that value's object key as slug, so a single plugin can serve multiple tabs. Es sind keine Berechtigungen erforderlich, um sich anzumelden. Welche Owncast-APIs Sie innerhalb des Handlers aufrufen, benötigen ihre üblichen Berechtigungen.
Seiteninhalt
Wird aufgerufen, wenn manifest.extraPageContent keine statische content-Datei hat. Der Host übergibt den Slug aus dem Manifest, sodass der Handler weiß, welcher Inhaltsplatz angefordert wird. Die gleichen Berechtigungsregeln wie für den Tab-Inhalt.
Siehe UI beizutragen für die Manifest-Seite.
SSE-Verbindungsereignisse
Wenn ein Browser einen Ihrer Plugin-/plugins/<name>/_sse/<channel>-Streams öffnet oder schließt, löst Owncast sse.connect und sse.disconnect aus. Verwenden Sie sie, um nachzuverfolgen, wer verbunden ist, um beispielsweise eine Live-Zählung für ein Overlay aufrechtzuerhalten. Siehe Echtzeitaktualisierungen für die Push-Seite, die Daten an diese Browser sendet.
Verbinden/Trennen: sse.connect, sse.disconnect
interface SSEConnectionEvent {
channel: string; // which _sse/<channel> stream the browser opened
connectionId: number; // unique per connection for the life of the host process
user?: User; // present only when the connection carried a chat identity
}
- JavaScript
- Python
module.exports = definePlugin({
onSseConnect(e) {
/* e.connectionId, e.channel */
},
onSseDisconnect(e) {
/* same connectionId as the matching connect */
},
});
@plugin.on_sse_connect
def joined(e):
... # e.connection_id, e.channel
@plugin.on_sse_disconnect
def left(e):
...
connectionId ist stabil für die Dauer einer Verbindung, sodass Sie eine Trennung mit der entsprechenden Verbindung kombinieren und denselben Zuschauer über mehrere Registerkarten hinweg zählen können. Beide Handler benötigen die http.sse-Berechtigung.
Tick
Owncast dispatcht etwa einmal pro Sekunde ein tick-Ereignis für jedes Plugin, das einen Tick-Handler definiert. Verwenden Sie es für periodische Arbeiten wie das Leeren von Zählern oder das Aktualisieren von zwischengespeicherten Daten. Die Definition des Handlers ist das, was Sie anmeldet, sodass Plugins, die ihn weglassen, nichts zahlen.
Periodisches Tick: tick
interface TickEvent {
now: number; // host wall-clock time in unix milliseconds when the tick fired
}
- JavaScript
- Python
module.exports = definePlugin({
onTick(e) {
/* e.now */
},
});
@plugin.on_tick
def each_second(e):
... # e.now
Für einmalige oder benutzerdefinierte zeitliche Planung verwenden Sie Timer (owncast.timer.setTimeout und setInterval) anstelle des Ticks. Es sind keine Berechtigungen erforderlich.
Plugin-zu-Plugin-Ereignisse
Custom events are directed hooks for plugin-to-plugin composition. A plugin declares a local hook name, and the host registers it as \<plugin-slug>.\<hook>. The slug comes from the receiving plugin's manifest, so another plugin cannot claim the same fully qualified hook. Declaring a hook requires no permission. Emitting to one requires events.emit.
- JavaScript
- Python
// In the plugin whose slug is "announcer":
module.exports = definePlugin({
on: {
'announcement.broadcast'(payload) {
/* react */
},
},
});
// Another plugin targets announcer's fully qualified hook:
owncast.events.emit('announcer.announcement.broadcast', { text: 'We are live' });
# In the plugin whose slug is "announcer":
@plugin.on("announcement.broadcast")
def announce(payload):
...
# Another plugin targets announcer's fully qualified hook:
owncast.events.emit(
"announcer.announcement.broadcast",
{"text": "We are live"},
)
The receiving handler uses only its local hook name. Emitters use the full
\<recipient-slug>.\<hook> target. Built-in event names remain canonical and
cannot be claimed as custom hooks.
Siehe Owncast APIs für die Emit-API.
Vollständige Handlerreferenz
Jede Zeile ist ein Laufzeitereignis. Der Handlername folgt der Konvention Ihres SDKs: CamelCase-Methoden (onChatMessage) in JavaScript, @plugin.*-Dekoratoren (@plugin.on_chat_message) in Python.
| Ereignis | Nutzlast | Permission |
|---|---|---|
chat.message.received | ChatNachricht | none |
chat.benutzer.beigetreten | Benutzer | none |
chat.benutzer.verlassen | Benutzer | none |
chat.benutzer.umbenannt | { benutzer, vorherigerName } | none |
chat.nachricht.moderiert | { nachrichtId, sichtbar, moderator} | none |
stream.ge gestartet | { gestartetAm, titel, zusammenfassung } | none |
stream.beendet | { beendetAm } | none |
stream.titel.geändert | { von, zu } | none |
fediverse.folgen | { akteur } | fediverse.eingehend |
fediverse.likes | { actor, target } | fediverse.eingehend |
fediverse.wiederposten | { akteur, ziel } | fediverse.eingehend |
fediverse.zitieren | FediverseQuote | fediverse.eingehend |
fediverse.erwähnen | FediverseInboundPost | fediverse.eingehend |
fediverse.antworten | FediverseInboundPost | fediverse.eingehend |
fediverse.aktivität | Raw ActivityPub JSON-Objekt | fediverse.eingehend |
| Chat-Nachrichtenfilter | ChatNachricht | chat.filter |
| HTTP-Anfrage | EingehendeHttpAnfrage | http.bedienen |
| auth Überprüfung | AuthCheckRequest | auth.tor |
sse.verbinden | SSEConnectionEvent | http.sse |
sse.trennen | SSEConnectionEvent | http.sse |
takt | { jetzt } | none |
| Tab-Inhalt | Inhaltsanfrage | none. Egal, welche APIs der Handler aufruft |
| Seiteninhalt | Inhaltsanfrage | none. Egal, welche APIs der Handler aufruft |
| custom hooks | (per-hook) | none to declare, events.emit to target one |
Subscribing to ungated built-in events and declaring custom hooks requires no permission. Eingeschränkte Hooks erfordern die in der Tabelle aufgeführten Berechtigungen. Das Aufrufen von Owncast APIs aus einem Handler erfordert ebenfalls die Berechtigung der API. Siehe Owncast APIs für das Verzeichnis der Methoden und welche Berechtigungen jede hat.
Improve this page
See something missing or incorrect? Edit the English version of this page or help improve translations.
