nonsensebot/app/modules/fediverse_preview.py

88 lines
3.3 KiB
Python
Raw Normal View History

2024-08-03 01:49:45 +01:00
"""
This module takes fediverse links (e.g.) and provides a preview in a reply.
2024-09-12 20:18:57 +01:00
By default, this will only work with fedi.transgender.ing, but if you set `[fediverse_preview.urls]` in your config,
you can add more. This module will use the Mastodon protocol, however it is designed to be used with misskey.
2024-08-03 01:49:45 +01:00
"""
2024-09-15 23:03:24 +01:00
2024-08-11 15:25:04 +01:00
import logging
2024-08-03 01:49:45 +01:00
import niobot
import httpx
import typing
import textwrap
from urllib.parse import urlparse
2024-09-15 23:03:24 +01:00
2024-08-03 01:49:45 +01:00
if typing.TYPE_CHECKING:
2024-09-15 23:03:24 +01:00
from ..main import NonsenseBot
2024-08-03 01:49:45 +01:00
class FediversePreviewModule(niobot.Module):
2024-09-15 23:03:24 +01:00
bot: "NonsenseBot"
2024-08-11 15:25:04 +01:00
log = logging.getLogger(__name__)
2024-08-03 01:49:45 +01:00
@niobot.event("message")
async def on_message(self, room: niobot.MatrixRoom, event: niobot.RoomMessage):
2024-09-15 20:25:42 +01:00
config = self.bot.cfg.get("fediverse_preview", {})
2024-08-15 11:34:38 +01:00
supported_prefixes = config.get("urls", ["https://fedi.transgender.ing"])
ignore = config.get("ignore", [])
2024-08-03 01:49:45 +01:00
if not isinstance(event, niobot.RoomMessageText):
return
2024-09-15 23:03:24 +01:00
if (
event.sender in ignore
or room.room_id in ignore
or event.sender == self.bot.user_id
):
return
2024-08-03 01:49:45 +01:00
sent = []
2024-08-11 15:21:37 +01:00
async with httpx.AsyncClient(
2024-09-15 23:03:24 +01:00
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0"
}
2024-08-11 15:21:37 +01:00
) as client:
2024-08-03 01:49:45 +01:00
for item in event.body.split():
2024-08-11 15:26:37 +01:00
if not item.startswith(tuple(supported_prefixes)):
2024-08-03 01:49:45 +01:00
return
parsed = urlparse(item)
post_id = parsed.path.split("/")[-1]
if post_id in sent:
2024-08-11 15:26:37 +01:00
self.log.info("Already sent post %s", post_id)
2024-08-03 01:49:45 +01:00
continue
elif len(sent) >= 5:
2024-08-11 15:26:37 +01:00
self.log.info("Already sent 5 posts, stopping")
2024-08-03 01:49:45 +01:00
break
2024-09-15 23:03:24 +01:00
resp = await client.get(
"https://%s/api/v1/statuses/%s" % (parsed.netloc, post_id)
)
2024-08-03 01:49:45 +01:00
if resp.status_code != 200:
2024-08-11 15:25:04 +01:00
self.log.error("Got HTTP %d from %s", resp.status_code, resp.url)
2024-08-03 01:49:45 +01:00
continue
data = resp.json()
2024-08-11 15:28:49 +01:00
self.log.info("Got data: %r", data)
2024-08-11 15:34:11 +01:00
username = data["account"]["username"]
2024-08-11 15:35:28 +01:00
if not (text := data.get("content")):
2024-08-11 15:25:04 +01:00
self.log.warning("No text for post %s", post_id)
2024-08-03 01:49:45 +01:00
continue
2024-08-03 19:19:55 +01:00
self.log.info("Detected fediverse post %s: %r", post_id, text)
2024-08-06 22:12:09 +01:00
rendered = await self.bot._markdown_to_html(text)
2024-08-03 19:19:55 +01:00
text_body = "<blockquote>%s</blockquote>" % rendered
2024-09-15 23:03:24 +01:00
body = '<a href="%s">@%s:</a><br>%s' % (
2024-08-03 01:55:38 +01:00
"https://%s/@%s" % (parsed.netloc, username),
2024-08-03 01:52:50 +01:00
username,
2024-08-03 01:57:52 +01:00
text_body,
2024-08-03 01:49:45 +01:00
)
if data.get("media_attachments"):
2024-09-15 23:03:24 +01:00
body += "<p>{:,} attachments</p>".format(
len(data["media_attachments"])
)
self.log.info("Sending fediverse post %s", post_id)
2024-08-03 01:52:50 +01:00
await self.bot.send_message(
room,
body,
reply_to=event,
2024-08-03 01:55:38 +01:00
content_type="html.raw",
2024-09-15 23:03:24 +01:00
override={"body": f"@{username}: {data['content']!r}"},
2024-08-03 01:52:50 +01:00
)
2024-08-03 01:49:45 +01:00
sent.append(post_id)