mirror of
https://github.com/usetrmnl/plugins.git
synced 2026-08-13 14:26:58 -07:00
101 lines
3.0 KiB
Ruby
101 lines
3.0 KiB
Ruby
module Plugins
|
|||
|
|
class RssFeed < Base
|
||
|
|
|
||
|
|
def locals
|
||
|
|
{ rss_feed: }
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def rss_feed
|
||
|
|
feed = process_feed
|
||
|
|
feed.is_a?(Array) ? feed : [feed]
|
||
|
|
end
|
||
|
|
|
||
|
|
def process_feed
|
||
|
|
validate_uri(settings['url'])
|
||
|
|
response = fetch(settings['url'].strip, headers:)
|
||
|
|
|
||
|
|
raise InvalidURL unless response.respond_to?(:code) && response.respond_to?(:body)
|
||
|
|
raise InvalidURL if response.code.to_i >= 400
|
||
|
|
return content_error(StandardError.new("Response Code: #{response.code}")) if response.code != 200
|
||
|
|
return content_error(StandardError.new("No Content")) if response.body.nil? || response.body.empty?
|
||
|
|
|
||
|
|
feed = RSS::Parser.parse(response.body, validate: false)
|
||
|
|
|
||
|
|
if layout == 'featured'
|
||
|
|
normalize_feed(feed&.items&.first)
|
||
|
|
elsif layout == 'list'
|
||
|
|
feed&.items&.[](0..7)&.map do |post|
|
||
|
|
normalize_feed(post, strip_to_text: true)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
rescue OpenURI::HTTPError, RSS::NotWellFormedError, RSS::TooMuchTagError => e
|
||
|
|
content_error(e)
|
||
|
|
rescue InvalidURL, URI::InvalidURIError, OpenSSL::SSL::SSLError => e
|
||
|
|
handle_erroring_state(e)
|
||
|
|
content_error(e)
|
||
|
|
end
|
||
|
|
|
||
|
|
def normalize_feed(post, strip_to_text: false)
|
||
|
|
content = if post.is_a?(RSS::Atom::Feed::Entry)
|
||
|
|
{
|
||
|
|
title: post&.title&.content,
|
||
|
|
content: post&.summary&.content || post&.content&.to_s
|
||
|
|
}.compact
|
||
|
|
else
|
||
|
|
{
|
||
|
|
title: post&.title,
|
||
|
|
content: post&.content_encoded || post&.description
|
||
|
|
}.compact
|
||
|
|
end
|
||
|
|
return content_error(StandardError.new("No Content")) if content.empty?
|
||
|
|
|
||
|
|
if strip_to_text
|
||
|
|
strip_html(content)
|
||
|
|
else
|
||
|
|
dither_image(content)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def validate_uri(url)
|
||
|
|
raise InvalidURL unless url =~ URI::DEFAULT_PARSER.make_regexp
|
||
|
|
end
|
||
|
|
|
||
|
|
# added 2025-01-08 per customer observation that some rss feeds prevent fetches without user-agent present
|
||
|
|
def headers
|
||
|
|
{
|
||
|
|
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
def dither_image(feed)
|
||
|
|
content = feed[:content]
|
||
|
|
return feed if content.nil?
|
||
|
|
|
||
|
|
content.gsub!(%r{<img(.*?)/?>}, '<img\1 class="image-dither w-full h-auto object-contain block mx-auto" />')
|
||
|
|
feed[:content] = content
|
||
|
|
feed
|
||
|
|
end
|
||
|
|
|
||
|
|
# Make content in the list view plaintext so we don't overflow.
|
||
|
|
def strip_html(feed)
|
||
|
|
content = feed[:content]
|
||
|
|
return feed if content.nil?
|
||
|
|
|
||
|
|
plain_text = ActionController::Base.helpers.strip_tags(content)
|
||
|
|
feed[:content] = plain_text.squish.truncate(200)
|
||
|
|
feed
|
||
|
|
end
|
||
|
|
|
||
|
|
def content_error(error)
|
||
|
|
{
|
||
|
|
title: 'Error while parsing RSS content',
|
||
|
|
content: "Message: #{error&.message}"
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
def layout = settings['layout'] || 'featured'
|
||
|
|
end
|
||
|
|
end
|