{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UnicodeSyntax #-}

-- | Feed data structures.
module Imm.Feed (
  -- * Types
  FeedLocation (..),
  UID,
  FeedQuery (..),
  FeedDefinition (..),
  FeedItem (..),
  Author (..),

  -- * Parsers
  parseFeed,
  feedC,
  parseFeedItem,

  -- * Utilities
  getMainLink,
  areSameItem,
)
where

-- {{{ Imports
import Conduit
import Control.Exception.Safe
import Data.Aeson.Extended
import Data.Text as Text (null)
import Data.Time
import Data.XML.Types
import Imm.Link
import Imm.Pretty
import Refined
import Safe
import Text.Atom.Conduit.Parse
import Text.Atom.Types
import Text.RSS.Conduit.Parse
import Text.RSS.Extensions.Content
import Text.RSS.Extensions.DublinCore
import Text.RSS.Types
import Text.RSS1.Conduit.Parse
import Text.XML.Stream.Parse as XML hiding (content)
import URI.ByteString.Extended

-- }}}

-- | Feed location identifies a feed. It is either:
-- - the feed URI
-- - a webpage URI that refers to the feed through an alternate link, in which case an optional feed title can be provided to disambiguate multiple such links
data FeedLocation = FeedLocation URI Text
  deriving (FeedLocation -> FeedLocation -> Bool
(FeedLocation -> FeedLocation -> Bool)
-> (FeedLocation -> FeedLocation -> Bool) -> Eq FeedLocation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FeedLocation -> FeedLocation -> Bool
== :: FeedLocation -> FeedLocation -> Bool
$c/= :: FeedLocation -> FeedLocation -> Bool
/= :: FeedLocation -> FeedLocation -> Bool
Eq, (forall x. FeedLocation -> Rep FeedLocation x)
-> (forall x. Rep FeedLocation x -> FeedLocation)
-> Generic FeedLocation
forall x. Rep FeedLocation x -> FeedLocation
forall x. FeedLocation -> Rep FeedLocation x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FeedLocation -> Rep FeedLocation x
from :: forall x. FeedLocation -> Rep FeedLocation x
$cto :: forall x. Rep FeedLocation x -> FeedLocation
to :: forall x. Rep FeedLocation x -> FeedLocation
Generic, Eq FeedLocation
Eq FeedLocation =>
(FeedLocation -> FeedLocation -> Ordering)
-> (FeedLocation -> FeedLocation -> Bool)
-> (FeedLocation -> FeedLocation -> Bool)
-> (FeedLocation -> FeedLocation -> Bool)
-> (FeedLocation -> FeedLocation -> Bool)
-> (FeedLocation -> FeedLocation -> FeedLocation)
-> (FeedLocation -> FeedLocation -> FeedLocation)
-> Ord FeedLocation
FeedLocation -> FeedLocation -> Bool
FeedLocation -> FeedLocation -> Ordering
FeedLocation -> FeedLocation -> FeedLocation
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: FeedLocation -> FeedLocation -> Ordering
compare :: FeedLocation -> FeedLocation -> Ordering
$c< :: FeedLocation -> FeedLocation -> Bool
< :: FeedLocation -> FeedLocation -> Bool
$c<= :: FeedLocation -> FeedLocation -> Bool
<= :: FeedLocation -> FeedLocation -> Bool
$c> :: FeedLocation -> FeedLocation -> Bool
> :: FeedLocation -> FeedLocation -> Bool
$c>= :: FeedLocation -> FeedLocation -> Bool
>= :: FeedLocation -> FeedLocation -> Bool
$cmax :: FeedLocation -> FeedLocation -> FeedLocation
max :: FeedLocation -> FeedLocation -> FeedLocation
$cmin :: FeedLocation -> FeedLocation -> FeedLocation
min :: FeedLocation -> FeedLocation -> FeedLocation
Ord, Int -> FeedLocation -> ShowS
[FeedLocation] -> ShowS
FeedLocation -> [Char]
(Int -> FeedLocation -> ShowS)
-> (FeedLocation -> [Char])
-> ([FeedLocation] -> ShowS)
-> Show FeedLocation
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FeedLocation -> ShowS
showsPrec :: Int -> FeedLocation -> ShowS
$cshow :: FeedLocation -> [Char]
show :: FeedLocation -> [Char]
$cshowList :: [FeedLocation] -> ShowS
showList :: [FeedLocation] -> ShowS
Show, Typeable)

instance Pretty FeedLocation where
  pretty :: forall ann. FeedLocation -> Doc ann
pretty (FeedLocation URI
uri Text
title) =
    URI -> Doc ann
forall a b. URIRef a -> Doc b
prettyURI URI
uri
      Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> if Text -> Bool
Text.null Text
title then Doc ann
forall a. Monoid a => a
mempty else Doc ann
forall ann. Doc ann
space Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
brackets (Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
title)

instance ToJSON FeedLocation where
  toJSON :: FeedLocation -> Value
toJSON (FeedLocation URI
uri Text
title) =
    [Pair] -> Value
object
      [ Key
"uri" Key -> Value -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= JsonURI -> Value
forall a. ToJSON a => a -> Value
toJSON (URI -> JsonURI
JsonURI URI
uri)
      , Key
"title" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
title
      ]

instance FromJSON FeedLocation where
  parseJSON :: Value -> Parser FeedLocation
parseJSON = [Char]
-> (Object -> Parser FeedLocation) -> Value -> Parser FeedLocation
forall a. [Char] -> (Object -> Parser a) -> Value -> Parser a
withObject [Char]
"FeedLocation" ((Object -> Parser FeedLocation) -> Value -> Parser FeedLocation)
-> (Object -> Parser FeedLocation) -> Value -> Parser FeedLocation
forall a b. (a -> b) -> a -> b
$ \Object
v  do
    URI -> Text -> FeedLocation
FeedLocation (URI -> Text -> FeedLocation)
-> Parser URI -> Parser (Text -> FeedLocation)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (JsonURI -> URI
_unwrapURI (JsonURI -> URI) -> Parser JsonURI -> Parser URI
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Object
v Object -> Key -> Parser JsonURI
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"uri")) Parser (Text -> FeedLocation) -> Parser Text -> Parser FeedLocation
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"title")

-- | Database identifier for a feed
type UID = Int

-- | A query describes a set of feeds through some criteria.
data FeedQuery = QueryByUID UID | QueryAll
  deriving (FeedQuery -> FeedQuery -> Bool
(FeedQuery -> FeedQuery -> Bool)
-> (FeedQuery -> FeedQuery -> Bool) -> Eq FeedQuery
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FeedQuery -> FeedQuery -> Bool
== :: FeedQuery -> FeedQuery -> Bool
$c/= :: FeedQuery -> FeedQuery -> Bool
/= :: FeedQuery -> FeedQuery -> Bool
Eq, Eq FeedQuery
Eq FeedQuery =>
(FeedQuery -> FeedQuery -> Ordering)
-> (FeedQuery -> FeedQuery -> Bool)
-> (FeedQuery -> FeedQuery -> Bool)
-> (FeedQuery -> FeedQuery -> Bool)
-> (FeedQuery -> FeedQuery -> Bool)
-> (FeedQuery -> FeedQuery -> FeedQuery)
-> (FeedQuery -> FeedQuery -> FeedQuery)
-> Ord FeedQuery
FeedQuery -> FeedQuery -> Bool
FeedQuery -> FeedQuery -> Ordering
FeedQuery -> FeedQuery -> FeedQuery
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: FeedQuery -> FeedQuery -> Ordering
compare :: FeedQuery -> FeedQuery -> Ordering
$c< :: FeedQuery -> FeedQuery -> Bool
< :: FeedQuery -> FeedQuery -> Bool
$c<= :: FeedQuery -> FeedQuery -> Bool
<= :: FeedQuery -> FeedQuery -> Bool
$c> :: FeedQuery -> FeedQuery -> Bool
> :: FeedQuery -> FeedQuery -> Bool
$c>= :: FeedQuery -> FeedQuery -> Bool
>= :: FeedQuery -> FeedQuery -> Bool
$cmax :: FeedQuery -> FeedQuery -> FeedQuery
max :: FeedQuery -> FeedQuery -> FeedQuery
$cmin :: FeedQuery -> FeedQuery -> FeedQuery
min :: FeedQuery -> FeedQuery -> FeedQuery
Ord, ReadPrec [FeedQuery]
ReadPrec FeedQuery
Int -> ReadS FeedQuery
ReadS [FeedQuery]
(Int -> ReadS FeedQuery)
-> ReadS [FeedQuery]
-> ReadPrec FeedQuery
-> ReadPrec [FeedQuery]
-> Read FeedQuery
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS FeedQuery
readsPrec :: Int -> ReadS FeedQuery
$creadList :: ReadS [FeedQuery]
readList :: ReadS [FeedQuery]
$creadPrec :: ReadPrec FeedQuery
readPrec :: ReadPrec FeedQuery
$creadListPrec :: ReadPrec [FeedQuery]
readListPrec :: ReadPrec [FeedQuery]
Read, Int -> FeedQuery -> ShowS
[FeedQuery] -> ShowS
FeedQuery -> [Char]
(Int -> FeedQuery -> ShowS)
-> (FeedQuery -> [Char])
-> ([FeedQuery] -> ShowS)
-> Show FeedQuery
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FeedQuery -> ShowS
showsPrec :: Int -> FeedQuery -> ShowS
$cshow :: FeedQuery -> [Char]
show :: FeedQuery -> [Char]
$cshowList :: [FeedQuery] -> ShowS
showList :: [FeedQuery] -> ShowS
Show, Typeable)

instance Pretty FeedQuery where
  pretty :: forall ann. FeedQuery -> Doc ann
pretty FeedQuery
QueryAll = Doc ann
"All subscribed feeds"
  pretty (QueryByUID Int
k) = Doc ann
"Feed" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Int -> Doc ann
forall ann. Int -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Int
k

newtype FeedDefinition = FeedDefinition
  { FeedDefinition -> Text
_feedTitle  Text
  }
  deriving (FeedDefinition -> FeedDefinition -> Bool
(FeedDefinition -> FeedDefinition -> Bool)
-> (FeedDefinition -> FeedDefinition -> Bool) -> Eq FeedDefinition
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FeedDefinition -> FeedDefinition -> Bool
== :: FeedDefinition -> FeedDefinition -> Bool
$c/= :: FeedDefinition -> FeedDefinition -> Bool
/= :: FeedDefinition -> FeedDefinition -> Bool
Eq, (forall x. FeedDefinition -> Rep FeedDefinition x)
-> (forall x. Rep FeedDefinition x -> FeedDefinition)
-> Generic FeedDefinition
forall x. Rep FeedDefinition x -> FeedDefinition
forall x. FeedDefinition -> Rep FeedDefinition x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FeedDefinition -> Rep FeedDefinition x
from :: forall x. FeedDefinition -> Rep FeedDefinition x
$cto :: forall x. Rep FeedDefinition x -> FeedDefinition
to :: forall x. Rep FeedDefinition x -> FeedDefinition
Generic, Eq FeedDefinition
Eq FeedDefinition =>
(FeedDefinition -> FeedDefinition -> Ordering)
-> (FeedDefinition -> FeedDefinition -> Bool)
-> (FeedDefinition -> FeedDefinition -> Bool)
-> (FeedDefinition -> FeedDefinition -> Bool)
-> (FeedDefinition -> FeedDefinition -> Bool)
-> (FeedDefinition -> FeedDefinition -> FeedDefinition)
-> (FeedDefinition -> FeedDefinition -> FeedDefinition)
-> Ord FeedDefinition
FeedDefinition -> FeedDefinition -> Bool
FeedDefinition -> FeedDefinition -> Ordering
FeedDefinition -> FeedDefinition -> FeedDefinition
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: FeedDefinition -> FeedDefinition -> Ordering
compare :: FeedDefinition -> FeedDefinition -> Ordering
$c< :: FeedDefinition -> FeedDefinition -> Bool
< :: FeedDefinition -> FeedDefinition -> Bool
$c<= :: FeedDefinition -> FeedDefinition -> Bool
<= :: FeedDefinition -> FeedDefinition -> Bool
$c> :: FeedDefinition -> FeedDefinition -> Bool
> :: FeedDefinition -> FeedDefinition -> Bool
$c>= :: FeedDefinition -> FeedDefinition -> Bool
>= :: FeedDefinition -> FeedDefinition -> Bool
$cmax :: FeedDefinition -> FeedDefinition -> FeedDefinition
max :: FeedDefinition -> FeedDefinition -> FeedDefinition
$cmin :: FeedDefinition -> FeedDefinition -> FeedDefinition
min :: FeedDefinition -> FeedDefinition -> FeedDefinition
Ord, ReadPrec [FeedDefinition]
ReadPrec FeedDefinition
Int -> ReadS FeedDefinition
ReadS [FeedDefinition]
(Int -> ReadS FeedDefinition)
-> ReadS [FeedDefinition]
-> ReadPrec FeedDefinition
-> ReadPrec [FeedDefinition]
-> Read FeedDefinition
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS FeedDefinition
readsPrec :: Int -> ReadS FeedDefinition
$creadList :: ReadS [FeedDefinition]
readList :: ReadS [FeedDefinition]
$creadPrec :: ReadPrec FeedDefinition
readPrec :: ReadPrec FeedDefinition
$creadListPrec :: ReadPrec [FeedDefinition]
readListPrec :: ReadPrec [FeedDefinition]
Read, Int -> FeedDefinition -> ShowS
[FeedDefinition] -> ShowS
FeedDefinition -> [Char]
(Int -> FeedDefinition -> ShowS)
-> (FeedDefinition -> [Char])
-> ([FeedDefinition] -> ShowS)
-> Show FeedDefinition
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FeedDefinition -> ShowS
showsPrec :: Int -> FeedDefinition -> ShowS
$cshow :: FeedDefinition -> [Char]
show :: FeedDefinition -> [Char]
$cshowList :: [FeedDefinition] -> ShowS
showList :: [FeedDefinition] -> ShowS
Show, Typeable)

feedDefinitionOptions  Options
feedDefinitionOptions :: Options
feedDefinitionOptions =
  Options
defaultOptions
    { fieldLabelModifier = camelTo2 '_' . drop (length @[] "_feed")
    , omitNothingFields = True
    }

instance ToJSON FeedDefinition where
  toJSON :: FeedDefinition -> Value
toJSON = Options -> FeedDefinition -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
feedDefinitionOptions
  toEncoding :: FeedDefinition -> Encoding
toEncoding = Options -> FeedDefinition -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
feedDefinitionOptions

instance FromJSON FeedDefinition where
  parseJSON :: Value -> Parser FeedDefinition
parseJSON = Options -> Value -> Parser FeedDefinition
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON Options
feedDefinitionOptions

instance Pretty FeedDefinition where
  pretty :: forall ann. FeedDefinition -> Doc ann
pretty FeedDefinition
definition = Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (Text -> Doc ann) -> Text -> Doc ann
forall a b. (a -> b) -> a -> b
$ FeedDefinition -> Text
_feedTitle FeedDefinition
definition

instance Pretty (PrettyName FeedDefinition) where
  pretty :: forall ann. PrettyName FeedDefinition -> Doc ann
pretty (PrettyName FeedDefinition
definition) = Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (Text -> Doc ann) -> Text -> Doc ann
forall a b. (a -> b) -> a -> b
$ FeedDefinition -> Text
_feedTitle FeedDefinition
definition

data Author = Author
  { Author -> Text
_authorName  Text
  , Author -> Text
_authorEmail  Text
  , Author -> Maybe AnyURI
_authorURI  Maybe AnyURI
  }
  deriving (Author -> Author -> Bool
(Author -> Author -> Bool)
-> (Author -> Author -> Bool) -> Eq Author
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Author -> Author -> Bool
== :: Author -> Author -> Bool
$c/= :: Author -> Author -> Bool
/= :: Author -> Author -> Bool
Eq, (forall x. Author -> Rep Author x)
-> (forall x. Rep Author x -> Author) -> Generic Author
forall x. Rep Author x -> Author
forall x. Author -> Rep Author x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Author -> Rep Author x
from :: forall x. Author -> Rep Author x
$cto :: forall x. Rep Author x -> Author
to :: forall x. Rep Author x -> Author
Generic, Eq Author
Eq Author =>
(Author -> Author -> Ordering)
-> (Author -> Author -> Bool)
-> (Author -> Author -> Bool)
-> (Author -> Author -> Bool)
-> (Author -> Author -> Bool)
-> (Author -> Author -> Author)
-> (Author -> Author -> Author)
-> Ord Author
Author -> Author -> Bool
Author -> Author -> Ordering
Author -> Author -> Author
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Author -> Author -> Ordering
compare :: Author -> Author -> Ordering
$c< :: Author -> Author -> Bool
< :: Author -> Author -> Bool
$c<= :: Author -> Author -> Bool
<= :: Author -> Author -> Bool
$c> :: Author -> Author -> Bool
> :: Author -> Author -> Bool
$c>= :: Author -> Author -> Bool
>= :: Author -> Author -> Bool
$cmax :: Author -> Author -> Author
max :: Author -> Author -> Author
$cmin :: Author -> Author -> Author
min :: Author -> Author -> Author
Ord, Int -> Author -> ShowS
[Author] -> ShowS
Author -> [Char]
(Int -> Author -> ShowS)
-> (Author -> [Char]) -> ([Author] -> ShowS) -> Show Author
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Author -> ShowS
showsPrec :: Int -> Author -> ShowS
$cshow :: Author -> [Char]
show :: Author -> [Char]
$cshowList :: [Author] -> ShowS
showList :: [Author] -> ShowS
Show, Typeable)

authorOptions  Options
authorOptions :: Options
authorOptions =
  Options
defaultOptions
    { fieldLabelModifier = camelTo2 '_' . drop (length @[] "_author")
    , omitNothingFields = True
    }

instance ToJSON Author where
  toJSON :: Author -> Value
toJSON = Options -> Author -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
authorOptions
  toEncoding :: Author -> Encoding
toEncoding = Options -> Author -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
authorOptions

instance FromJSON Author where
  parseJSON :: Value -> Parser Author
parseJSON = Options -> Value -> Parser Author
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON Options
authorOptions

instance Pretty Author where
  pretty :: forall ann. Author -> Doc ann
pretty Author{Maybe AnyURI
Text
_authorName :: Author -> Text
_authorEmail :: Author -> Text
_authorURI :: Author -> Maybe AnyURI
_authorName :: Text
_authorEmail :: Text
_authorURI :: Maybe AnyURI
..} = Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
_authorName Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
brackets (Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
_authorEmail)

data FeedItem = FeedItem
  { FeedItem -> Maybe UTCTime
_itemDate  Maybe UTCTime
  , FeedItem -> Text
_itemTitle  Text
  , FeedItem -> Text
_itemContent  Text
  , FeedItem -> [Link]
_itemLinks  [Link]
  , FeedItem -> Text
_itemIdentifier  Text
  , FeedItem -> [Author]
_itemAuthors  [Author]
  }
  deriving (FeedItem -> FeedItem -> Bool
(FeedItem -> FeedItem -> Bool)
-> (FeedItem -> FeedItem -> Bool) -> Eq FeedItem
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FeedItem -> FeedItem -> Bool
== :: FeedItem -> FeedItem -> Bool
$c/= :: FeedItem -> FeedItem -> Bool
/= :: FeedItem -> FeedItem -> Bool
Eq, (forall x. FeedItem -> Rep FeedItem x)
-> (forall x. Rep FeedItem x -> FeedItem) -> Generic FeedItem
forall x. Rep FeedItem x -> FeedItem
forall x. FeedItem -> Rep FeedItem x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FeedItem -> Rep FeedItem x
from :: forall x. FeedItem -> Rep FeedItem x
$cto :: forall x. Rep FeedItem x -> FeedItem
to :: forall x. Rep FeedItem x -> FeedItem
Generic, Eq FeedItem
Eq FeedItem =>
(FeedItem -> FeedItem -> Ordering)
-> (FeedItem -> FeedItem -> Bool)
-> (FeedItem -> FeedItem -> Bool)
-> (FeedItem -> FeedItem -> Bool)
-> (FeedItem -> FeedItem -> Bool)
-> (FeedItem -> FeedItem -> FeedItem)
-> (FeedItem -> FeedItem -> FeedItem)
-> Ord FeedItem
FeedItem -> FeedItem -> Bool
FeedItem -> FeedItem -> Ordering
FeedItem -> FeedItem -> FeedItem
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: FeedItem -> FeedItem -> Ordering
compare :: FeedItem -> FeedItem -> Ordering
$c< :: FeedItem -> FeedItem -> Bool
< :: FeedItem -> FeedItem -> Bool
$c<= :: FeedItem -> FeedItem -> Bool
<= :: FeedItem -> FeedItem -> Bool
$c> :: FeedItem -> FeedItem -> Bool
> :: FeedItem -> FeedItem -> Bool
$c>= :: FeedItem -> FeedItem -> Bool
>= :: FeedItem -> FeedItem -> Bool
$cmax :: FeedItem -> FeedItem -> FeedItem
max :: FeedItem -> FeedItem -> FeedItem
$cmin :: FeedItem -> FeedItem -> FeedItem
min :: FeedItem -> FeedItem -> FeedItem
Ord, Int -> FeedItem -> ShowS
[FeedItem] -> ShowS
FeedItem -> [Char]
(Int -> FeedItem -> ShowS)
-> (FeedItem -> [Char]) -> ([FeedItem] -> ShowS) -> Show FeedItem
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FeedItem -> ShowS
showsPrec :: Int -> FeedItem -> ShowS
$cshow :: FeedItem -> [Char]
show :: FeedItem -> [Char]
$cshowList :: [FeedItem] -> ShowS
showList :: [FeedItem] -> ShowS
Show, Typeable)

feedItemOptions  Options
feedItemOptions :: Options
feedItemOptions =
  Options
defaultOptions
    { fieldLabelModifier = camelTo2 '_' . drop (length @[] "_item")
    , omitNothingFields = True
    }

instance ToJSON FeedItem where
  toJSON :: FeedItem -> Value
toJSON = Options -> FeedItem -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
feedItemOptions
  toEncoding :: FeedItem -> Encoding
toEncoding = Options -> FeedItem -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
feedItemOptions

instance FromJSON FeedItem where
  parseJSON :: Value -> Parser FeedItem
parseJSON = Options -> Value -> Parser FeedItem
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON Options
feedItemOptions

instance Pretty (PrettyName FeedItem) where
  pretty :: forall ann. PrettyName FeedItem -> Doc ann
pretty (PrettyName FeedItem
item) = Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (FeedItem -> Text
_itemTitle FeedItem
item)

instance Pretty FeedItem where
  pretty :: forall ann. FeedItem -> Doc ann
pretty FeedItem{[Link]
[Author]
Maybe UTCTime
Text
_itemDate :: FeedItem -> Maybe UTCTime
_itemTitle :: FeedItem -> Text
_itemContent :: FeedItem -> Text
_itemLinks :: FeedItem -> [Link]
_itemIdentifier :: FeedItem -> Text
_itemAuthors :: FeedItem -> [Author]
_itemDate :: Maybe UTCTime
_itemTitle :: Text
_itemContent :: Text
_itemLinks :: [Link]
_itemIdentifier :: Text
_itemAuthors :: [Author]
..} = Doc ann -> (UTCTime -> Doc ann) -> Maybe UTCTime -> Doc ann
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Doc ann
"<unknown>" UTCTime -> Doc ann
forall a. UTCTime -> Doc a
prettyTime Maybe UTCTime
_itemDate Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> Text -> Doc ann
forall ann. Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Text
_itemTitle

parseFeed  MonadCatch m  Text  m (FeedDefinition, [FeedItem])
parseFeed :: forall (m :: * -> *).
MonadCatch m =>
Text -> m (FeedDefinition, [FeedItem])
parseFeed Text
text = ConduitT () Void m (FeedDefinition, [FeedItem])
-> m (FeedDefinition, [FeedItem])
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit (ConduitT () Void m (FeedDefinition, [FeedItem])
 -> m (FeedDefinition, [FeedItem]))
-> ConduitT () Void m (FeedDefinition, [FeedItem])
-> m (FeedDefinition, [FeedItem])
forall a b. (a -> b) -> a -> b
$ ParseSettings -> ByteString -> ConduitT () Event m ()
forall (m :: * -> *) i.
MonadThrow m =>
ParseSettings -> ByteString -> ConduitT i Event m ()
parseLBS ParseSettings
forall a. Default a => a
def (Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 Text
text) ConduitT () Event m ()
-> ConduitT Event Void m (FeedDefinition, [FeedItem])
-> ConduitT () Void m (FeedDefinition, [FeedItem])
forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| [Char]
-> ConduitT Event Void m (Maybe (FeedDefinition, [FeedItem]))
-> ConduitT Event Void m (FeedDefinition, [FeedItem])
forall (m :: * -> *) a.
MonadThrow m =>
[Char] -> m (Maybe a) -> m a
XML.force [Char]
"Invalid feed" ConduitT Event Void m (Maybe (FeedDefinition, [FeedItem]))
forall (m :: * -> *) o.
MonadCatch m =>
ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
feedC

parseAtomFeed  AtomFeed  (FeedDefinition, [FeedItem])
parseAtomFeed :: AtomFeed -> (FeedDefinition, [FeedItem])
parseAtomFeed AtomFeed
feed = (FeedDefinition
definition, [FeedItem]
items)
 where
  definition :: FeedDefinition
definition = Text -> FeedDefinition
FeedDefinition (Doc Any -> Text
forall b a. (Show a, IsString b) => a -> b
show (Doc Any -> Text) -> Doc Any -> Text
forall a b. (a -> b) -> a -> b
$ AtomText -> Doc Any
forall a. AtomText -> Doc a
prettyAtomText (AtomText -> Doc Any) -> AtomText -> Doc Any
forall a b. (a -> b) -> a -> b
$ AtomFeed -> AtomText
feedTitle AtomFeed
feed)
  items :: [FeedItem]
items = AtomEntry -> FeedItem
parseAtomItem (AtomEntry -> FeedItem) -> [AtomEntry] -> [FeedItem]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AtomFeed -> [AtomEntry]
feedEntries AtomFeed
feed

parseRssFeed  RssDocument (ContentModule (DublinCoreModule NoExtensions))  (FeedDefinition, [FeedItem])
parseRssFeed :: RssDocument (ContentModule (DublinCoreModule NoExtensions))
-> (FeedDefinition, [FeedItem])
parseRssFeed RssDocument (ContentModule (DublinCoreModule NoExtensions))
doc = (FeedDefinition
definition, [FeedItem]
items)
 where
  definition :: FeedDefinition
definition = Text -> FeedDefinition
FeedDefinition (RssDocument (ContentModule (DublinCoreModule NoExtensions)) -> Text
forall extensions. RssDocument extensions -> Text
channelTitle RssDocument (ContentModule (DublinCoreModule NoExtensions))
doc)
  items :: [FeedItem]
items = RssItem (ContentModule (DublinCoreModule NoExtensions)) -> FeedItem
parseRssItem (RssItem (ContentModule (DublinCoreModule NoExtensions))
 -> FeedItem)
-> [RssItem (ContentModule (DublinCoreModule NoExtensions))]
-> [FeedItem]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RssDocument (ContentModule (DublinCoreModule NoExtensions))
-> [RssItem (ContentModule (DublinCoreModule NoExtensions))]
forall extensions. RssDocument extensions -> [RssItem extensions]
channelItems RssDocument (ContentModule (DublinCoreModule NoExtensions))
doc

-- | Conduit version of 'parseFeed'
feedC  MonadCatch m  ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
feedC :: forall (m :: * -> *) o.
MonadCatch m =>
ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
feedC = [ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))]
-> ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall (m :: * -> *) o a.
Monad m =>
[ConduitT Event o m (Maybe a)] -> ConduitT Event o m (Maybe a)
choose [ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall {o}. ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
atom, ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall {o}. ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
rss, ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall {o}. ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
rss1]
 where
  atom :: ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
atom = (AtomFeed -> (FeedDefinition, [FeedItem]))
-> Maybe AtomFeed -> Maybe (FeedDefinition, [FeedItem])
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap AtomFeed -> (FeedDefinition, [FeedItem])
parseAtomFeed (Maybe AtomFeed -> Maybe (FeedDefinition, [FeedItem]))
-> ConduitT Event o m (Maybe AtomFeed)
-> ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ConduitT Event o m (Maybe AtomFeed)
forall (m :: * -> *) o.
MonadThrow m =>
ConduitM Event o m (Maybe AtomFeed)
atomFeed
  rss :: ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
rss = (RssDocument (ContentModule (DublinCoreModule NoExtensions))
 -> (FeedDefinition, [FeedItem]))
-> Maybe
     (RssDocument (ContentModule (DublinCoreModule NoExtensions)))
-> Maybe (FeedDefinition, [FeedItem])
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RssDocument (ContentModule (DublinCoreModule NoExtensions))
-> (FeedDefinition, [FeedItem])
parseRssFeed (Maybe
   (RssDocument (ContentModule (DublinCoreModule NoExtensions)))
 -> Maybe (FeedDefinition, [FeedItem]))
-> ConduitT
     Event
     o
     m
     (Maybe
        (RssDocument (ContentModule (DublinCoreModule NoExtensions))))
-> ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ConduitT
  Event
  o
  m
  (Maybe
     (RssDocument (ContentModule (DublinCoreModule NoExtensions))))
forall e (m :: * -> *) o.
(ParseRssExtension e, MonadThrow m) =>
ConduitM Event o m (Maybe (RssDocument e))
rssDocument
  rss1 :: ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
rss1 = (RssDocument (ContentModule (DublinCoreModule NoExtensions))
 -> (FeedDefinition, [FeedItem]))
-> Maybe
     (RssDocument (ContentModule (DublinCoreModule NoExtensions)))
-> Maybe (FeedDefinition, [FeedItem])
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RssDocument (ContentModule (DublinCoreModule NoExtensions))
-> (FeedDefinition, [FeedItem])
parseRssFeed (Maybe
   (RssDocument (ContentModule (DublinCoreModule NoExtensions)))
 -> Maybe (FeedDefinition, [FeedItem]))
-> ConduitT
     Event
     o
     m
     (Maybe
        (RssDocument (ContentModule (DublinCoreModule NoExtensions))))
-> ConduitT Event o m (Maybe (FeedDefinition, [FeedItem]))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ConduitT
  Event
  o
  m
  (Maybe
     (RssDocument (ContentModule (DublinCoreModule NoExtensions))))
forall e (m :: * -> *) o.
(ParseRssExtension e, MonadCatch m) =>
ConduitM Event o m (Maybe (RssDocument e))
rss1Document

parseFeedItem  MonadCatch m  Text  m FeedItem
parseFeedItem :: forall (m :: * -> *). MonadCatch m => Text -> m FeedItem
parseFeedItem Text
text = ConduitT () Void m FeedItem -> m FeedItem
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit (ConduitT () Void m FeedItem -> m FeedItem)
-> ConduitT () Void m FeedItem -> m FeedItem
forall a b. (a -> b) -> a -> b
$ ParseSettings -> ByteString -> ConduitT () Event m ()
forall (m :: * -> *) i.
MonadThrow m =>
ParseSettings -> ByteString -> ConduitT i Event m ()
parseLBS ParseSettings
forall a. Default a => a
def (Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8 Text
text) ConduitT () Event m ()
-> ConduitT Event Void m FeedItem -> ConduitT () Void m FeedItem
forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| [Char]
-> ConduitT Event Void m (Maybe FeedItem)
-> ConduitT Event Void m FeedItem
forall (m :: * -> *) a.
MonadThrow m =>
[Char] -> m (Maybe a) -> m a
XML.force [Char]
"Invalid feed element" ([ConduitT Event Void m (Maybe FeedItem)]
-> ConduitT Event Void m (Maybe FeedItem)
forall (m :: * -> *) o a.
Monad m =>
[ConduitT Event o m (Maybe a)] -> ConduitT Event o m (Maybe a)
choose [(AtomEntry -> FeedItem) -> Maybe AtomEntry -> Maybe FeedItem
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap AtomEntry -> FeedItem
parseAtomItem (Maybe AtomEntry -> Maybe FeedItem)
-> ConduitT Event Void m (Maybe AtomEntry)
-> ConduitT Event Void m (Maybe FeedItem)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ConduitT Event Void m (Maybe AtomEntry)
forall (m :: * -> *) o.
MonadThrow m =>
ConduitM Event o m (Maybe AtomEntry)
atomEntry, (RssItem (ContentModule (DublinCoreModule NoExtensions))
 -> FeedItem)
-> Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions)))
-> Maybe FeedItem
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RssItem (ContentModule (DublinCoreModule NoExtensions)) -> FeedItem
parseRssItem (Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions)))
 -> Maybe FeedItem)
-> ConduitT
     Event
     Void
     m
     (Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions))))
-> ConduitT Event Void m (Maybe FeedItem)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ConduitT
  Event
  Void
  m
  (Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions))))
forall e (m :: * -> *) o.
(ParseRssExtension e, MonadThrow m) =>
ConduitM Event o m (Maybe (RssItem e))
rssItem, (RssItem (ContentModule (DublinCoreModule NoExtensions))
 -> FeedItem)
-> Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions)))
-> Maybe FeedItem
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RssItem (ContentModule (DublinCoreModule NoExtensions)) -> FeedItem
parseRssItem (Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions)))
 -> Maybe FeedItem)
-> ConduitT
     Event
     Void
     m
     (Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions))))
-> ConduitT Event Void m (Maybe FeedItem)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ConduitT
  Event
  Void
  m
  (Maybe (RssItem (ContentModule (DublinCoreModule NoExtensions))))
forall e (m :: * -> *) o.
(ParseRssExtension e, MonadCatch m) =>
ConduitM Event o m (Maybe (RssItem e))
rss1Item])

parseAtomItem  AtomEntry  FeedItem
parseAtomItem :: AtomEntry -> FeedItem
parseAtomItem AtomEntry
entry = Maybe UTCTime
-> Text -> Text -> [Link] -> Text -> [Author] -> FeedItem
FeedItem Maybe UTCTime
date Text
title Text
content [Link]
links Text
identifier [Author]
authors
 where
  date :: Maybe UTCTime
date = UTCTime -> Maybe UTCTime
forall a. a -> Maybe a
Just (UTCTime -> Maybe UTCTime) -> UTCTime -> Maybe UTCTime
forall a b. (a -> b) -> a -> b
$ AtomEntry -> UTCTime
entryUpdated AtomEntry
entry
  title :: Text
title = Doc Any -> Text
forall b a. (Show a, IsString b) => a -> b
show (Doc Any -> Text) -> Doc Any -> Text
forall a b. (a -> b) -> a -> b
$ AtomText -> Doc Any
forall a. AtomText -> Doc a
prettyAtomText (AtomText -> Doc Any) -> AtomText -> Doc Any
forall a b. (a -> b) -> a -> b
$ AtomEntry -> AtomText
entryTitle AtomEntry
entry
  content :: Text
content = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"<empty>" (Maybe Text -> Text) -> Maybe Text -> Text
forall a b. (a -> b) -> a -> b
$ Maybe Text
rawContent Maybe Text -> Maybe Text -> Maybe Text
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe Text
summary
  rawContent :: Maybe Text
rawContent = Doc Any -> Text
forall b a. (Show a, IsString b) => a -> b
show (Doc Any -> Text)
-> (AtomContent -> Doc Any) -> AtomContent -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AtomContent -> Doc Any
forall a. AtomContent -> Doc a
prettyAtomContent (AtomContent -> Text) -> Maybe AtomContent -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AtomEntry -> Maybe AtomContent
entryContent AtomEntry
entry
  summary :: Maybe Text
summary = Doc Any -> Text
forall b a. (Show a, IsString b) => a -> b
show (Doc Any -> Text) -> (AtomText -> Doc Any) -> AtomText -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AtomText -> Doc Any
forall a. AtomText -> Doc a
prettyAtomText (AtomText -> Text) -> Maybe AtomText -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AtomEntry -> Maybe AtomText
entrySummary AtomEntry
entry
  links :: [Link]
links = AtomLink -> Link
parseLink (AtomLink -> Link) -> [AtomLink] -> [Link]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> AtomEntry -> [AtomLink]
entryLinks AtomEntry
entry
  parseLink :: AtomLink -> Link
parseLink AtomLink
link = Maybe Relation -> Text -> Maybe MediaType -> AnyURI -> Link
Link (Relation -> Maybe Relation
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Relation -> Maybe Relation) -> Relation -> Maybe Relation
forall a b. (a -> b) -> a -> b
$ Relation -> Maybe Relation -> Relation
forall a. a -> Maybe a -> a
fromMaybe Relation
Alternate (Maybe Relation -> Relation) -> Maybe Relation -> Relation
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Relation
parseRelation (Text -> Maybe Relation) -> Text -> Maybe Relation
forall a b. (a -> b) -> a -> b
$ AtomLink -> Text
linkRel AtomLink
link) (AtomLink -> Text
linkTitle AtomLink
link) (Text -> Maybe MediaType
forall s. Stream s Identity Char => s -> Maybe MediaType
parseMediaType (Text -> Maybe MediaType) -> Text -> Maybe MediaType
forall a b. (a -> b) -> a -> b
$ AtomLink -> Text
linkType AtomLink
link) ((forall a. URIRef a -> AnyURI) -> AtomURI -> AnyURI
forall b. (forall a. URIRef a -> b) -> AtomURI -> b
withAtomURI URIRef a -> AnyURI
forall a. URIRef a -> AnyURI
AnyURI (AtomURI -> AnyURI) -> AtomURI -> AnyURI
forall a b. (a -> b) -> a -> b
$ AtomLink -> AtomURI
linkHref AtomLink
link)
  identifier :: Text
identifier = AtomEntry -> Text
entryId AtomEntry
entry
  authors :: [Author]
authors = [Text -> Text -> Maybe AnyURI -> Author
Author (Refined (Not Null) Text -> Text
forall {k} (p :: k) x. Refined p x -> x
unrefine Refined (Not Null) Text
name) Text
email ((forall a. URIRef a -> AnyURI) -> AtomURI -> AnyURI
forall b. (forall a. URIRef a -> b) -> AtomURI -> b
withAtomURI URIRef a -> AnyURI
forall a. URIRef a -> AnyURI
AnyURI (AtomURI -> AnyURI) -> Maybe AtomURI -> Maybe AnyURI
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe AtomURI
uri) | AtomPerson Refined (Not Null) Text
name Text
email Maybe AtomURI
uri  AtomEntry -> [AtomPerson]
entryAuthors AtomEntry
entry]

parseRssItem  RssItem (ContentModule (DublinCoreModule NoExtensions))  FeedItem
parseRssItem :: RssItem (ContentModule (DublinCoreModule NoExtensions)) -> FeedItem
parseRssItem RssItem (ContentModule (DublinCoreModule NoExtensions))
item = Maybe UTCTime
-> Text -> Text -> [Link] -> Text -> [Author] -> FeedItem
FeedItem Maybe UTCTime
date Text
title Text
content [Link]
links Text
identifier [Author]
authors
 where
  date :: Maybe UTCTime
date = RssItem (ContentModule (DublinCoreModule NoExtensions))
-> Maybe UTCTime
forall extensions. RssItem extensions -> Maybe UTCTime
itemPubDate RssItem (ContentModule (DublinCoreModule NoExtensions))
item Maybe UTCTime -> Maybe UTCTime -> Maybe UTCTime
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (RssItem (ContentModule (DublinCoreModule NoExtensions))
item RssItem (ContentModule (DublinCoreModule NoExtensions))
-> (RssItem (ContentModule (DublinCoreModule NoExtensions))
    -> RssItemExtension
         (ContentModule (DublinCoreModule NoExtensions)))
-> RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
forall a b. a -> (a -> b) -> b
& RssItem (ContentModule (DublinCoreModule NoExtensions))
-> RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
forall extensions.
RssItem extensions -> RssItemExtension extensions
itemExtensions RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
-> (RssItemExtension
      (ContentModule (DublinCoreModule NoExtensions))
    -> RssItemExtension (DublinCoreModule NoExtensions))
-> RssItemExtension (DublinCoreModule NoExtensions)
forall a b. a -> (a -> b) -> b
& RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
-> RssItemExtension (DublinCoreModule NoExtensions)
forall a. RssItemExtension (ContentModule a) -> RssItemExtension a
itemContentOther RssItemExtension (DublinCoreModule NoExtensions)
-> (RssItemExtension (DublinCoreModule NoExtensions) -> DcMetaData)
-> DcMetaData
forall a b. a -> (a -> b) -> b
& RssItemExtension (DublinCoreModule NoExtensions) -> DcMetaData
forall a. RssItemExtension (DublinCoreModule a) -> DcMetaData
itemDcMetaData DcMetaData -> (DcMetaData -> Maybe UTCTime) -> Maybe UTCTime
forall a b. a -> (a -> b) -> b
& DcMetaData -> Maybe UTCTime
elementDate)
  title :: Text
title = RssItem (ContentModule (DublinCoreModule NoExtensions)) -> Text
forall extensions. RssItem extensions -> Text
itemTitle RssItem (ContentModule (DublinCoreModule NoExtensions))
item
  content :: Text
content = if Bool -> Bool
not (Text -> Bool
Text.null Text
rawContent) then Text
rawContent else RssItem (ContentModule (DublinCoreModule NoExtensions)) -> Text
forall extensions. RssItem extensions -> Text
itemDescription RssItem (ContentModule (DublinCoreModule NoExtensions))
item
  rawContent :: Text
rawContent = RssItem (ContentModule (DublinCoreModule NoExtensions))
item RssItem (ContentModule (DublinCoreModule NoExtensions))
-> (RssItem (ContentModule (DublinCoreModule NoExtensions))
    -> RssItemExtension
         (ContentModule (DublinCoreModule NoExtensions)))
-> RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
forall a b. a -> (a -> b) -> b
& RssItem (ContentModule (DublinCoreModule NoExtensions))
-> RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
forall extensions.
RssItem extensions -> RssItemExtension extensions
itemExtensions RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
-> (RssItemExtension
      (ContentModule (DublinCoreModule NoExtensions))
    -> Text)
-> Text
forall a b. a -> (a -> b) -> b
& RssItemExtension (ContentModule (DublinCoreModule NoExtensions))
-> Text
forall a. RssItemExtension (ContentModule a) -> Text
itemContent
  links :: [Link]
links = [Maybe Relation -> Text -> Maybe MediaType -> AnyURI -> Link
Link (Relation -> Maybe Relation
forall a. a -> Maybe a
Just Relation
Alternate) Text
forall a. Monoid a => a
mempty Maybe MediaType
forall a. Maybe a
forall (m :: * -> *) a. MonadPlus m => m a
mzero ((forall a. URIRef a -> AnyURI) -> RssURI -> AnyURI
forall b. (forall a. URIRef a -> b) -> RssURI -> b
withRssURI URIRef a -> AnyURI
forall a. URIRef a -> AnyURI
AnyURI RssURI
uri) | RssURI
uri  Maybe RssURI -> [RssURI]
forall a. Maybe a -> [a]
maybeToList (Maybe RssURI -> [RssURI]) -> Maybe RssURI -> [RssURI]
forall a b. (a -> b) -> a -> b
$ RssItem (ContentModule (DublinCoreModule NoExtensions))
-> Maybe RssURI
forall extensions. RssItem extensions -> Maybe RssURI
itemLink RssItem (ContentModule (DublinCoreModule NoExtensions))
item]
  identifier :: Text
identifier = RssItem (ContentModule (DublinCoreModule NoExtensions))
-> Maybe RssGuid
forall extensions. RssItem extensions -> Maybe RssGuid
itemGuid RssItem (ContentModule (DublinCoreModule NoExtensions))
item Maybe RssGuid -> (RssGuid -> Doc Any) -> Maybe (Doc Any)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> RssGuid -> Doc Any
forall a. RssGuid -> Doc a
prettyGuid Maybe (Doc Any) -> (Maybe (Doc Any) -> Text) -> Text
forall a b. a -> (a -> b) -> b
& Text -> (Doc Any -> Text) -> Maybe (Doc Any) -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
forall a. Monoid a => a
mempty Doc Any -> Text
forall b a. (Show a, IsString b) => a -> b
show
  authors :: [Author]
authors = [Text -> Text -> Maybe AnyURI -> Author
Author (RssItem (ContentModule (DublinCoreModule NoExtensions)) -> Text
forall extensions. RssItem extensions -> Text
itemAuthor RssItem (ContentModule (DublinCoreModule NoExtensions))
item) Text
forall a. Monoid a => a
mempty Maybe AnyURI
forall a. Maybe a
forall (m :: * -> *) a. MonadPlus m => m a
mzero]

-- TODO: replace headMay with singleMay
getMainLink  FeedItem  Maybe Link
getMainLink :: FeedItem -> Maybe Link
getMainLink FeedItem
item = FeedItem -> [Link]
_itemLinks FeedItem
item [Link] -> ([Link] -> [Link]) -> [Link]
forall a b. a -> (a -> b) -> b
& (Link -> Bool) -> [Link] -> [Link]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Link
l  Link -> Maybe Relation
_linkRelation Link
l Maybe Relation -> Maybe Relation -> Bool
forall a. Eq a => a -> a -> Bool
== Relation -> Maybe Relation
forall a. a -> Maybe a
Just Relation
Alternate) [Link] -> ([Link] -> Maybe Link) -> Maybe Link
forall a b. a -> (a -> b) -> b
& [Link] -> Maybe Link
forall a. [a] -> Maybe a
headMay

haveSameIdentifier  FeedItem  FeedItem  Maybe Bool
haveSameIdentifier :: FeedItem -> FeedItem -> Maybe Bool
haveSameIdentifier FeedItem
item1 FeedItem
item2 = case (FeedItem -> Text
_itemIdentifier FeedItem
item1, FeedItem -> Text
_itemIdentifier FeedItem
item2) of
  (Text
"", Text
"")  Maybe Bool
forall a. Maybe a
Nothing
  (Text
a, Text
b)  Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
b)

haveSameLink  FeedItem  FeedItem  Maybe Bool
haveSameLink :: FeedItem -> FeedItem -> Maybe Bool
haveSameLink FeedItem
item1 FeedItem
item2 = case (FeedItem -> Maybe Link
getMainLink FeedItem
item1, FeedItem -> Maybe Link
getMainLink FeedItem
item2) of
  (Just Link
a, Just Link
b)  Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Link
a Link -> Link -> Bool
forall a. Eq a => a -> a -> Bool
== Link
b)
  (Maybe Link
Nothing, Maybe Link
Nothing)  Maybe Bool
forall a. Maybe a
Nothing
  (Maybe Link, Maybe Link)
_  Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False

haveSameTitle  FeedItem  FeedItem  Maybe Bool
haveSameTitle :: FeedItem -> FeedItem -> Maybe Bool
haveSameTitle FeedItem
item1 FeedItem
item2 = case (FeedItem -> Text
_itemTitle FeedItem
item1, FeedItem -> Text
_itemTitle FeedItem
item2) of
  (Text
""  Text, Text
""  Text)  Maybe Bool
forall a. Maybe a
Nothing
  (Text
a, Text
b)  Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
b)

areSameItem  FeedItem  FeedItem  Bool
areSameItem :: FeedItem -> FeedItem -> Bool
areSameItem FeedItem
a FeedItem
b = Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe ((FeedItem -> Text) -> FeedItem -> FeedItem -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing FeedItem -> Text
_itemContent FeedItem
a FeedItem
b Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
EQ) (Maybe Bool -> Bool) -> Maybe Bool -> Bool
forall a b. (a -> b) -> a -> b
$ FeedItem -> FeedItem -> Maybe Bool
haveSameIdentifier FeedItem
a FeedItem
b Maybe Bool -> Maybe Bool -> Maybe Bool
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> FeedItem -> FeedItem -> Maybe Bool
haveSameLink FeedItem
a FeedItem
b Maybe Bool -> Maybe Bool -> Maybe Bool
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> FeedItem -> FeedItem -> Maybe Bool
haveSameTitle FeedItem
a FeedItem
b