Add RSS/Atom feed for outbox
This commit is contained in:
parent
9c41c68958
commit
5b025a8e45
6 changed files with 200 additions and 2 deletions
|
@ -62,6 +62,7 @@ def save_outbox_object(
|
|||
relates_to_actor_id=relates_to_actor_id,
|
||||
activity_object_ap_id=ra.activity_object_ap_id,
|
||||
is_hidden_from_homepage=True if ra.in_reply_to else False,
|
||||
source=source,
|
||||
)
|
||||
db.add(outbox_object)
|
||||
db.commit()
|
||||
|
|
99
app/main.py
99
app/main.py
|
@ -3,6 +3,7 @@ import os
|
|||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from datetime import timezone
|
||||
from io import BytesIO
|
||||
from typing import Any
|
||||
from typing import Type
|
||||
|
@ -20,6 +21,7 @@ from fastapi.responses import PlainTextResponse
|
|||
from fastapi.responses import RedirectResponse
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from feedgen.feed import FeedGenerator # type: ignore
|
||||
from loguru import logger
|
||||
from PIL import Image
|
||||
from sqlalchemy.orm import Session
|
||||
|
@ -796,3 +798,100 @@ async def robots_file():
|
|||
Disallow: /followers
|
||||
Disallow: /following
|
||||
Disallow: /admin"""
|
||||
|
||||
|
||||
def _get_outbox_for_feed(db: Session) -> list[models.OutboxObject]:
|
||||
return (
|
||||
db.query(models.OutboxObject)
|
||||
.filter(
|
||||
models.OutboxObject.visibility == ap.VisibilityEnum.PUBLIC,
|
||||
models.OutboxObject.is_deleted.is_(False),
|
||||
models.OutboxObject.ap_type.in_(["Note", "Article", "Video"]),
|
||||
)
|
||||
.order_by(models.OutboxObject.ap_published_at.desc())
|
||||
.limit(20)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
@app.get("/feed.json")
|
||||
def json_feed(
|
||||
db: Session = Depends(get_db),
|
||||
) -> dict[str, Any]:
|
||||
outbox_objects = _get_outbox_for_feed(db)
|
||||
data = []
|
||||
for outbox_object in outbox_objects:
|
||||
if not outbox_object.ap_published_at:
|
||||
raise ValueError(f"{outbox_object} has no published date")
|
||||
data.append(
|
||||
{
|
||||
"id": outbox_object.public_id,
|
||||
"url": outbox_object.url,
|
||||
"content_html": outbox_object.content,
|
||||
"content_text": outbox_object.source,
|
||||
"date_published": outbox_object.ap_published_at.isoformat(),
|
||||
"attachments": [
|
||||
{"url": a.url, "mime_type": a.media_type}
|
||||
for a in outbox_object.attachments
|
||||
],
|
||||
}
|
||||
)
|
||||
return {
|
||||
"version": "https://jsonfeed.org/version/1",
|
||||
"title": f"{LOCAL_ACTOR.display_name}'s microblog'",
|
||||
"home_page_url": LOCAL_ACTOR.url,
|
||||
"feed_url": BASE_URL + "/feed.json",
|
||||
"author": {
|
||||
"name": LOCAL_ACTOR.display_name,
|
||||
"url": LOCAL_ACTOR.url,
|
||||
"avatar": LOCAL_ACTOR.icon_url,
|
||||
},
|
||||
"items": data,
|
||||
}
|
||||
|
||||
|
||||
def _gen_rss_feed(
|
||||
db: Session,
|
||||
):
|
||||
fg = FeedGenerator()
|
||||
fg.id(BASE_URL + "/feed.rss")
|
||||
fg.title(f"{LOCAL_ACTOR.display_name}'s microblog")
|
||||
fg.description(f"{LOCAL_ACTOR.display_name}'s microblog")
|
||||
fg.author({"name": LOCAL_ACTOR.display_name})
|
||||
fg.link(href=LOCAL_ACTOR.url, rel="alternate")
|
||||
fg.logo(LOCAL_ACTOR.icon_url)
|
||||
fg.language("en")
|
||||
|
||||
outbox_objects = _get_outbox_for_feed(db)
|
||||
for outbox_object in outbox_objects:
|
||||
if not outbox_object.ap_published_at:
|
||||
raise ValueError(f"{outbox_object} has no published date")
|
||||
fe = fg.add_entry()
|
||||
fe.id(outbox_object.url)
|
||||
fe.link(href=outbox_object.url)
|
||||
fe.title(outbox_object.url)
|
||||
fe.description(outbox_object.content)
|
||||
fe.content(outbox_object.content)
|
||||
fe.published(outbox_object.ap_published_at.replace(tzinfo=timezone.utc))
|
||||
|
||||
return fg
|
||||
|
||||
|
||||
@app.get("/feed.rss")
|
||||
def rss_feed(
|
||||
db: Session = Depends(get_db),
|
||||
) -> PlainTextResponse:
|
||||
return PlainTextResponse(
|
||||
_gen_rss_feed(db).rss_str(),
|
||||
headers={"Content-Type": "application/rss+xml"},
|
||||
)
|
||||
|
||||
|
||||
@app.get("/feed.atom")
|
||||
def atom_feed(
|
||||
db: Session = Depends(get_db),
|
||||
) -> PlainTextResponse:
|
||||
return PlainTextResponse(
|
||||
_gen_rss_feed(db).atom_str(),
|
||||
headers={"Content-Type": "application/atom+xml"},
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<meta content="{{ local_actor.url }}" property="og:url" />
|
||||
<meta content="{{ local_actor.display_name }}'s microblog" property="og:site_name" />
|
||||
<meta content="Homepage" property="og:title" />
|
||||
<meta content="{{ local_actor.summary | html2text }}" property="og:description" />
|
||||
<meta content="{{ local_actor.summary | html2text | trim }}" property="og:description" />
|
||||
<meta content="{{ local_actor.url }}" property="og:image" />
|
||||
<meta content="summary" property="twitter:card" />
|
||||
<meta content="{{ local_actor.handle }}" property="profile:username" />
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<link rel="alternate" title="{{ local_actor.display_name}}'s microblog" type="application/json" href="{{ url_for("json_feed") }}" />
|
||||
<link rel="alternate" href="{{ url_for("rss_feed") }}" type="application/rss+xml" title="{{ local_actor.display_name}}'s microblog">
|
||||
<link rel="alternate" href="{{ url_for("atom_feed") }}" type="application/atom+xml" title="{{ local_actor.display_name}}'s microblog">
|
||||
<style>
|
||||
{{ highlight_css }}
|
||||
</style>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue