diff --git a/lib/volumen/feed_helpers.rb b/lib/volumen/feed_helpers.rb new file mode 100644 index 0000000..60e94b2 --- /dev/null +++ b/lib/volumen/feed_helpers.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +module Volumen + # RSS, JSON Feed, and sitemap helpers extracted from Server to keep the + # main class focused on configuration and routing. + module FeedHelpers + private + + def feed_xml + site = config.site + items = published_posts.first(20).map { |post| feed_item(post) }.join("\n") + <<~XML + + + + #{escape(site["title"])} + #{escape(base_url)} + #{escape(site["description"])} + #{escape(site["language"])} + #{items} + + + XML + end + + def feed_item(post) + link = "#{base_url}/#{post.slug}" + pub = if post.metadata["date"] + "\n #{escape(rfc822_date(post))}" + else + "" + end + creator = post.fediverse_creator + creator_tag = creator ? "\n #{escape(creator)}" : "" + <<~XML.chomp + + #{escape(post.title)} + #{escape(link)} + #{escape(link)} + #{escape(post.excerpt)}#{pub}#{creator_tag} + + XML + end + + def rfc822_date(post) + value = post.metadata["date"] + case value + when Date then value.to_time.rfc822 + when Time then value.rfc822 + end + end + + def feed_json + site = config.site + feed_url = "#{base_url}/api/volumen/feed.json" + { + "version" => "https://jsonfeed.org/version/1.1", + "title" => site["title"], + "home_page_url" => base_url, + "feed_url" => feed_url, + "description" => site["description"], + "language" => site["language"], + "items" => published_posts.first(20).map { |post| json_feed_item(post) } + } + end + + def json_feed_item(post) + link = "#{base_url}/#{post.slug}" + item = { + "id" => link, + "url" => link, + "title" => post.title, + "content_html" => post.html, + "summary" => post.excerpt, + "date_published" => iso_date(post.metadata["date"]), + "tags" => post.tags + } + author = post.fediverse_creator || site_fediverse_creator + item["authors"] = [{ "name" => author }] if author + item.reject { |_k, v| v.nil? || v == "" || v == [] } + end + + def iso_date(value) + case value + when Date then value.iso8601 + when Time then value.to_date.iso8601 + end + end + + def sitemap_xml + urls = published_posts.map do |post| + url = " #{escape("#{base_url}/#{post.slug}")}" + url << "#{escape(post.date_string)}" if post.date_string + url << "" + end.join("\n") + <<~XML + + + #{urls} + + XML + end + end +end diff --git a/lib/volumen/server.rb b/lib/volumen/server.rb index dc83dc7..b55779f 100644 --- a/lib/volumen/server.rb +++ b/lib/volumen/server.rb @@ -10,6 +10,7 @@ require_relative "markdown" require_relative "password" require_relative "api_routes" require_relative "admin_routes" +require_relative "feed_helpers" module Volumen # Sinatra application: the public JSON API at /api/volumen and the @@ -25,6 +26,7 @@ module Volumen register ApiRoutes register AdminRoutes + helpers FeedHelpers configure do set :show_exceptions, false @@ -167,101 +169,6 @@ module Volumen config.site["base_url"].to_s.chomp("/") end - def feed_xml - site = config.site - items = published_posts.first(20).map { |post| feed_item(post) }.join("\n") - <<~XML - - - - #{escape(site["title"])} - #{escape(base_url)} - #{escape(site["description"])} - #{escape(site["language"])} - #{items} - - - XML - end - - def feed_item(post) - link = "#{base_url}/#{post.slug}" - pub = if post.metadata["date"] - "\n #{escape(rfc822_date(post))}" - else - "" - end - creator = post.fediverse_creator - creator_tag = creator ? "\n #{escape(creator)}" : "" - <<~XML.chomp - - #{escape(post.title)} - #{escape(link)} - #{escape(link)} - #{escape(post.excerpt)}#{pub}#{creator_tag} - - XML - end - - def rfc822_date(post) - value = post.metadata["date"] - case value - when Date then value.to_time.rfc822 - when Time then value.rfc822 - end - end - - def feed_json - site = config.site - feed_url = "#{base_url}/api/volumen/feed.json" - { - "version" => "https://jsonfeed.org/version/1.1", - "title" => site["title"], - "home_page_url" => base_url, - "feed_url" => feed_url, - "description" => site["description"], - "language" => site["language"], - "items" => published_posts.first(20).map { |post| json_feed_item(post) } - } - end - - def json_feed_item(post) - link = "#{base_url}/#{post.slug}" - item = { - "id" => link, - "url" => link, - "title" => post.title, - "content_html" => post.html, - "summary" => post.excerpt, - "date_published" => iso_date(post.metadata["date"]), - "tags" => post.tags - } - author = post.fediverse_creator || site_fediverse_creator - item["authors"] = [{ "name" => author }] if author - item.reject { |_k, v| v.nil? || v == "" || v == [] } - end - - def iso_date(value) - case value - when Date then value.iso8601 - when Time then value.to_date.iso8601 - end - end - - def sitemap_xml - urls = published_posts.map do |post| - url = " #{escape("#{base_url}/#{post.slug}")}" - url << "#{escape(post.date_string)}" if post.date_string - url << "" - end.join("\n") - <<~XML - - - #{urls} - - XML - end - def escape(text) Rack::Utils.escape_html(text.to_s) end