lucienne-0.0.1: Lucienne/Fetch.hs
module Lucienne.Fetch
(fetchFeedByUrl,fetchFeed)
where
import Data.Maybe (fromMaybe)
import Data.List (find)
import qualified Data.ByteString.Char8 as BS
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import qualified Network.HTTP as HTTP
import Network.URI (URI)
import qualified Network.URI as URI
import qualified Text.Feed.Import as TFI
import qualified Text.Feed.Types as TFT
import qualified Text.Atom.Feed as TFAtom
import qualified Text.RSS.Syntax as TFRss
import Lucienne.Model.FeedItem (FeedItem)
import qualified Lucienne.Model.FeedItem as FI
import Lucienne.Model.Feed (Feed)
import qualified Lucienne.Model.Feed as F
fetchFeedByUrl :: String -> IO (Either String (Feed,[FeedItem]))
fetchFeedByUrl url =
case URI.parseURI url of
Nothing -> return $ Left $ concat ["'",url,"' is no valid URL"]
Just uri -> fetchAndProcessFeed uri $ parseFeed uri
fetchFeed :: Feed -> IO (Either String (Feed,[FeedItem]))
fetchFeed = fetchFeedByUrl . F.url
parseFeed :: URI -> String -> Either String (Feed,[FeedItem])
parseFeed feedUri content =
let textFeed = TFI.parseFeedString content
in
case textFeed of
Nothing -> Left "Can not parse feed items"
Just (TFT.AtomFeed f) -> Right $ parseAtomFeed feedUri f
Just (TFT.RSSFeed f) -> Right $ parseRssFeed feedUri f
Just _ -> Left "Unsupported feed format"
parseAtomFeed :: URI -> TFAtom.Feed -> (Feed,[FeedItem])
parseAtomFeed feedUri feed =
let parseFeedItems entry =
let title = TFAtom.txtToString $ TFAtom.entryTitle entry
url = chooseAtomLink $ TFAtom.entryLinks entry
content = maybe "" TFAtom.txtToString $ TFAtom.entrySummary entry
in
FI.newItem title url content
feedTitle = TFAtom.txtToString $ TFAtom.feedTitle feed
in
( F.newFeed feedTitle $ show feedUri
, map parseFeedItems $ TFAtom.feedEntries feed
)
chooseAtomLink :: [TFAtom.Link] -> String
chooseAtomLink links =
let selfLink = find (\l -> case TFAtom.linkRel l of
Just (Right "self") -> True
Just (Left "self") -> True
_ -> False)
in
TFAtom.linkHref $ fromMaybe (head links) $ selfLink links
parseRssFeed :: URI -> TFRss.RSS -> (Feed,[FeedItem])
parseRssFeed feedUri feed =
let parseFeedItems item =
let title = fromMaybe "" $ TFRss.rssItemTitle item
url = fromMaybe "" $ TFRss.rssItemLink item
content = fromMaybe "" $ TFRss.rssItemDescription item
in
FI.newItem title url content
feedTitle = TFRss.rssTitle $ TFRss.rssChannel feed
in
( F.newFeed feedTitle $ show feedUri
, map parseFeedItems $ TFRss.rssItems $ TFRss.rssChannel feed
)
fetchAndProcessFeed :: URI -> (String -> Either String a) -> IO (Either String a)
fetchAndProcessFeed uri f = do
result <- HTTP.simpleHTTP request
return $ case result of
Left connectionError -> Left $ show connectionError
Right response -> f $ T.unpack . E.decodeUtf8 $ HTTP.rspBody response
where
request = HTTP.Request uri HTTP.GET [] BS.empty