Add an Atom feed builder helper

This commit is contained in:
Samantaz Fox 2021-11-16 18:21:19 +01:00
parent 042ff8da64
commit 1062cd4fe3
No known key found for this signature in database
GPG key ID: F42821059186176E

95
src/invidious/rss_atom.cr Normal file
View file

@ -0,0 +1,95 @@
require "xml"
require "http/server"
module Invidious::RssAtom
extend self
# TODO: Merge all of those in a single type
alias AnyVideo = SearchVideo | ChannelVideo | PlaylistVideo
alias AltLinks = NamedTuple(type: String, url: String)
#
# Atom Feed builder
#
def atom_feed_builder(
# Mandatory parameters
env : HTTP::Server::Context,
videos : Array(AnyVideo),
*, # All parameters after this must be named
id : String,
title : String,
# Optional parameters
icon_url : String = "",
author : String = "",
author_url : String = "",
date_updated : Time | String = Time.utc,
date_published : Time | String | Nil = nil,
alt_links : Array(AltLinks) | Nil = nil
)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
params = HTTP::Params.parse(env.params.query["params"]? || "")
return XML.build(indent: " ", encoding: "UTF-8") do |xml|
xml.element("feed",
xmlns: "http://www.w3.org/2005/Atom",
"xmlns:media": "http://search.yahoo.com/mrss/",
"xml:lang": "en-US"
) do
# The id must be unique, and an IANA-approved IRI, so use "ni://"
# Relevant RFC documents:
# - https://datatracker.ietf.org/doc/html/rfc4287#section-4.2.6
# - https://datatracker.ietf.org/doc/html/rfc6920
#
xml.element("id") { xml.text "ni://invidious/sha-256;" + sha256(id) }
# Feed title. Use author name if no title was provided
xml.element("title") do
xml.text(title.empty? ? author : title)
end
if !icon_url.empty?
icon_url = "#{HOST_URL}/gghpt" + URI.parse(icon_url).request_target
xml.element("icon") { xml.text icon_url }
xml.element("logo") { xml.text icon_url }
end
# Feed creation (if available) and update (mandatory) dates
date_published = date_published.to_rfc3339 if date_published.is_a?(Time)
xml.element("published") { xml.text date_published } if date_published
date_updated = date_updated.to_rfc3339 if date_updated.is_a?(Time)
xml.element("updated") { xml.text date_updated }
# Links
xml.element("link", rel: "self",
type: "application/atom+xml",
href: "#{HOST_URL}#{env.request.resource}"
)
if alt_links
alt_links.each do |link|
xml.element("link", rel: "alternate", type: link[:type], href: link[:url])
end
end
# Author infos
xml.element("author") do
xml.element("name") { xml.text author }
xml.element("uri") { xml.text author_url } if !author_url.empty?
end
# Video entries
# TODO: Unify `.to_xml` methods
videos.each do |video|
case video
when .is_a?(PlaylistVideo) then video.to_xml(xml)
when .is_a?(ChannelVideo) then video.to_xml(locale, params, xml)
when .is_a?(SearchVideo) then video.to_xml(false, params, xml)
end
end
end
end
end
end