packages feed

scrapbook-0.3.2: src/ScrapBook/Feed/RSS.hs

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedLabels  #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds         #-}
{-# LANGUAGE TypeFamilies      #-}
{-# LANGUAGE TypeOperators     #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module ScrapBook.Feed.RSS
  ( fromRSSFeed
  , fromEntry
  ) where

import           RIO
import qualified RIO.Text                 as T

import           Data.Extensible
import           ScrapBook.Data.Site
import           ScrapBook.Fetch.Internal (Fetch (..), fetchHtml,
                                           throwFetchError)
import           ScrapBook.Internal.Utils (formatTimeFromRFC822)
import           Text.Feed.Import         (parseFeedString)
import           Text.Feed.Types          (Feed (..))
import           Text.RSS.Syntax          (RSS, RSSItem)
import qualified Text.RSS.Syntax          as RSS

instance Fetch ("rss" >: Text) where
  fetchFrom _ site feedUrl = do
    resp <- T.unpack <$> fetchHtml feedUrl
    case parseFeedString resp of
      Just (RSSFeed feed) -> pure $ fromRSSFeed site feed
      _                   -> throwFetchError (Right "can't parse rss feed.")

fromRSSFeed :: IsSiteFields xs => Record xs -> RSS -> [Post (Record xs)]
fromRSSFeed site feed = fromEntry site <$> RSS.rssItems (RSS.rssChannel feed)

fromEntry :: IsSiteFields xs => Record xs -> RSSItem -> Post (Record xs)
fromEntry site entry
    = #title   @= fromMaybe "" (RSS.rssItemTitle entry)
   <: #url     @= toUrl site entry
   <: #date    @= fromMaybe "" (formatTimeFromRFC822 =<< RSS.rssItemPubDate entry)
   <: #summary @= HtmlSummary <$> RSS.rssItemDescription entry
   <: #site    @= site
   <: nil

toUrl :: IsSiteFields xs => Record xs -> RSSItem -> Text
toUrl site entry =
  maybe "" (toAbsoluteUrl site) (RSS.rssItemLink entry)