Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions docs/PLUGIN_AUTHOR_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ module.exports = definePlugin({
/* {actor, target: {url}} */
},
onFediverseQuote(event) {
/* {actor, target: {url}}; target is the locally authored quoted post */
/* FediverseQuote; target is local, url is the remote quote post */
},

// Fediverse, inbound posts (with content)
Expand Down Expand Up @@ -266,7 +266,23 @@ privately to whoever sent a message, pass `msg` (or `msg.clientId`) to

### Fediverse engagement and raw activity

`onFediverseFollow` receives `{actor}`. `onFediverseLike`, `onFediverseRepost`, and `onFediverseQuote` receive `{actor, target}`. `actor` uses the SDK's `FediverseActor` shape. `target` is `{url: string}`. For a quote, it identifies the locally authored post that the remote actor quoted.
`onFediverseFollow` receives `{actor}`. `onFediverseLike` and `onFediverseRepost` receive `{actor, target}`. `actor` uses the SDK's `FediverseActor` shape. `target` is `{url: string}`.

`onFediverseQuote` receives a `FediverseQuote`. `target.url` identifies the locally authored post being quoted. `url` identifies the remote quote post. Content metadata is included when the requesting server embeds its quote `Note` in the `QuoteRequest`. Servers may send only the quote post IRI, so the content fields are optional.

```ts
interface FediverseQuote {
actor: FediverseActor;
target: { url: string };
content?: string;
contentText?: string;
url: string;
postedAt?: string;
inReplyTo?: string;
attachments?: { url: string; mediaType: string; alt?: string }[];
language?: string;
}
```

`onFediverse` receives the verified inbound ActivityPub activity after the host validates the HTTP signature and actor origin. In JavaScript, the payload is the raw JSON object. It fires in addition to a specialized handler when one applies. It also fires for verified activity types that have no specialized handler.

Expand Down
25 changes: 19 additions & 6 deletions docs/WIRE_PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,10 @@ not external HTTP webhooks.
`fediverse.activity` carries the verified inbound activity as a raw JSON
object. It fires alongside a matching specialized event and also covers
verified activity types without a specialized event. `fediverse.quote` carries
`{actor, target}`, where `target` is the quoted local post. Mentions and replies
are verified public `Create(Note)` activities tied to the local account or a
locally authored post.
a `FediverseQuote`. Its `target` is the quoted local post and its `url` is the
remote quote post. Content fields are present when the `QuoteRequest` embeds
the quote `Note`. Mentions and replies are verified public `Create(Note)`
activities tied to the local account or a locally authored post.

### ambient (no permission)

Expand Down Expand Up @@ -919,6 +920,18 @@ type FediverseInboundPost = {
language?: string;
};

type FediverseQuote = {
actor: FediverseActor;
target: FediverseTarget;
content?: string;
contentText?: string;
url: string;
postedAt?: string;
inReplyTo?: string;
attachments?: FediverseAttachment[];
language?: string;
};

type BrowserPushPayload = {
title: string;
body?: string;
Expand All @@ -934,9 +947,9 @@ type FediversePayload = {
```

`fediverse.activity` carries the verified ActivityPub object as an unrestricted
`JSONValue`. Follow carries `FediverseEngagement` without `target`. Like,
repost, and quote carry it with `target`. Mention and reply carry
`FediverseInboundPost`.
`JSONValue`. Follow carries `FediverseEngagement` without `target`. Like and
repost carry it with `target`. Quote carries `FediverseQuote`. Mention and
reply carry `FediverseInboundPost`.

### Storage and remaining host results

Expand Down
6 changes: 4 additions & 2 deletions examples/js/engagement-bot/__tests__/mod.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,15 @@
},
"target": {
"url": "https://demo.owncast.example/@demo/102"
}
},
"contentText": "Great stream",
"url": "https://social.example/@dana/quotes/102"
}
}
],
"expect": {
"discordPosts": [
"quote from @dana@social.example: https://demo.owncast.example/@demo/102"
"quote from @dana@social.example: Great stream\nhttps://social.example/@dana/quotes/102"
]
}
},
Expand Down
3 changes: 2 additions & 1 deletion examples/js/engagement-bot/src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ module.exports = definePlugin({
},

onFediverseQuote(event) {
const caption = event.contentText || "quoted your post";
owncast.notifications.discord(
`quote from ${event.actor.handle}: ${event.target.url}`,
`quote from ${event.actor.handle}: ${caption}\n${event.url}`,
);
},

Expand Down
6 changes: 4 additions & 2 deletions examples/python/engagement-bot/__tests__/mod.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,15 @@
},
"target": {
"url": "https://demo.owncast.example/@demo/102"
}
},
"contentText": "Great stream",
"url": "https://social.example/@dana/quotes/102"
}
}
],
"expect": {
"discordPosts": [
"quote from @dana@social.example: https://demo.owncast.example/@demo/102"
"quote from @dana@social.example: Great stream\nhttps://social.example/@dana/quotes/102"
]
}
},
Expand Down
3 changes: 2 additions & 1 deletion examples/python/engagement-bot/src/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def on_fediverse_repost(event):

@plugin.on_fediverse_quote
def on_fediverse_quote(event):
caption = event.content_text or "quoted your post"
owncast.notifications.discord(
f"quote from {event.actor.handle}: {event.target.url}"
f"quote from {event.actor.handle}: {caption}\n{event.url}"
)


Expand Down
21 changes: 19 additions & 2 deletions sdks/js/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,23 @@ export interface FediverseTargetedEngagement extends FediverseEngagement {
target: { url: string };
}

/** An accepted quote request. `target` identifies the local post being quoted,
* while `url` identifies the remote quote post. Content metadata is present
* when the requesting server embeds the quote Note in its request. */
export interface FediverseQuote extends FediverseTargetedEngagement {
content?: string; // HTML from the source instance
contentText?: string; // HTML stripped to plain text
url: string; // permalink to the remote quote post
postedAt?: string; // ISO-8601
inReplyTo?: string;
attachments?: {
url: string;
mediaType: string;
alt?: string;
}[];
language?: string;
}

/** Inbound fediverse post, a mention or reply that contains content the
* plugin can act on. Carries both the rendered content (which has the
* source instance's HTML) and a plain-text version (HTML stripped). */
Expand Down Expand Up @@ -446,8 +463,8 @@ export interface PluginDef {
onFediverseLike?(event: FediverseTargetedEngagement): void | Promise<void>;
/** Someone on the fediverse boosted (reposted) a streamer post. Requires `fediverse.inbound`. */
onFediverseRepost?(event: FediverseTargetedEngagement): void | Promise<void>;
/** Someone on the fediverse quoted a locally authored post. `target.url` identifies that quoted post. Requires `fediverse.inbound`. */
onFediverseQuote?(event: FediverseTargetedEngagement): void | Promise<void>;
/** Someone on the fediverse quoted a locally authored post. `target.url` identifies the local post and `url` identifies the remote quote post. Requires `fediverse.inbound`. */
onFediverseQuote?(event: FediverseQuote): void | Promise<void>;
/** Someone @-mentioned the streamer in a public post. Requires `fediverse.inbound`. */
onFediverseMention?(post: FediverseInboundPost): void | Promise<void>;
/** Someone replied to one of the streamer's federated posts. Requires `fediverse.inbound`. */
Expand Down
Loading