Attach multiple images to RSS (#411)

This commit is contained in:
TAKAHASHI Shuuji 2023-01-15 02:34:31 +09:00 committed by GitHub
parent 71ab6b98a6
commit feb7a673eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -6,8 +6,9 @@ from django.contrib.syndication.views import Feed
from django.core import validators from django.core import validators
from django.http import Http404, JsonResponse from django.http import Http404, JsonResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import feedgenerator
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.feedgenerator import Rss201rev2Feed
from django.utils.xmlutils import SimplerXMLGenerator
from django.views.decorators.vary import vary_on_headers from django.views.decorators.vary import vary_on_headers
from django.views.generic import FormView, ListView, TemplateView, View from django.views.generic import FormView, ListView, TemplateView, View
@ -93,6 +94,50 @@ class ViewIdentity(ListView):
return context return context
class FeedWithImages(Rss201rev2Feed):
"""Extended Feed class to attach multiple images."""
def rss_attributes(self):
attrs = super().rss_attributes()
attrs["xmlns:media"] = "http://search.yahoo.com/mrss/"
attrs["xmlns:webfeeds"] = "http://webfeeds.org/rss/1.0"
return attrs
def add_root_elements(self, handler: SimplerXMLGenerator):
super().add_root_elements(handler)
handler.startElement("image", {})
handler.addQuickElement("url", self.feed["image"]["url"])
handler.addQuickElement("title", self.feed["image"]["title"])
handler.addQuickElement("link", self.feed["image"]["link"])
handler.endElement("image")
handler.addQuickElement(
"webfeeds:icon",
self.feed["image"]["url"],
)
def add_item_elements(self, handler: SimplerXMLGenerator, item):
super().add_item_elements(handler, item)
for image in item["images"]:
handler.startElement(
"media:content",
{
"url": image["url"],
"type": image["mime_type"],
"fileSize": image["length"],
"medium": "image",
},
)
if image["description"]:
handler.addQuickElement(
"media:description", image["description"], {"type": "plain"}
)
handler.endElement("media:content")
for hashtag in item["hashtags"]:
handler.addQuickElement("category", hashtag)
@method_decorator( @method_decorator(
cache_page("cache_timeout_identity_feed", public_only=True), name="__call__" cache_page("cache_timeout_identity_feed", public_only=True), name="__call__"
) )
@ -101,6 +146,8 @@ class IdentityFeed(Feed):
Serves a local user's Public posts as an RSS feed Serves a local user's Public posts as an RSS feed
""" """
feed_type = FeedWithImages
def get_object(self, request, handle): def get_object(self, request, handle):
return by_handle_or_404( return by_handle_or_404(
request, request,
@ -117,6 +164,18 @@ class IdentityFeed(Feed):
def link(self, identity: Identity): def link(self, identity: Identity):
return identity.absolute_profile_uri() return identity.absolute_profile_uri()
def feed_extra_kwargs(self, identity: Identity):
"""
Return attached images data to allow `FeedWithImages.add_item_elements()`
to attach multiple images for each `<item>`.
"""
image = {
"url": identity.local_icon_url().absolute,
"title": identity.name,
"link": identity.absolute_profile_uri(),
}
return {"image": image}
def items(self, identity: Identity): def items(self, identity: Identity):
return TimelineService(None).identity_public(identity)[:20] return TimelineService(None).identity_public(identity)[:20]
@ -129,17 +188,23 @@ class IdentityFeed(Feed):
def item_pubdate(self, item: Post): def item_pubdate(self, item: Post):
return item.published return item.published
def item_enclosures(self, item: Post): def item_extra_kwargs(self, item: Post):
attachment = item.attachments.first() """
if attachment is None: Return attached images data to allow `FeedWithImages.add_root_elements()`
return [] to add `<image>` as RSS feed icon.
"""
enc = feedgenerator.Enclosure( images = []
url=attachment.full_url().absolute, for attachment in item.attachments.all():
length=str(attachment.file.size), images.append(
mime_type=attachment.mimetype, {
"url": attachment.full_url().absolute,
"length": (str(attachment.file.size)),
"mime_type": (attachment.mimetype),
"description": (attachment.name),
}
) )
return [enc]
return {"images": images, "hashtags": item.hashtags or []}
class IdentityFollows(ListView): class IdentityFollows(ListView):
@ -203,7 +268,6 @@ class ActionIdentity(View):
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")
class SelectIdentity(TemplateView): class SelectIdentity(TemplateView):
template_name = "identity/select.html" template_name = "identity/select.html"
def get_context_data(self): def get_context_data(self):
@ -228,7 +292,6 @@ class ActivateIdentity(View):
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")
class CreateIdentity(FormView): class CreateIdentity(FormView):
template_name = "identity/create.html" template_name = "identity/create.html"
class form_class(forms.Form): class form_class(forms.Form):