summaryrefslogtreecommitdiff
path: root/src/Hakyll/Web/Feed.hs
diff options
context:
space:
mode:
authorJasper Van der Jeugt <jaspervdj@gmail.com>2011-01-18 13:29:42 +0100
committerJasper Van der Jeugt <jaspervdj@gmail.com>2011-01-18 13:29:42 +0100
commit0bbc01f0128f0c9e0a217f1d33f876ab03d29905 (patch)
tree6fed4e40ba3928149f193d0cd3664b99f72e63ac /src/Hakyll/Web/Feed.hs
parent821dd38c138e33194105162f7ad4140c9c46fcf2 (diff)
downloadhakyll-0bbc01f0128f0c9e0a217f1d33f876ab03d29905.tar.gz
Backports feeds
Diffstat (limited to 'src/Hakyll/Web/Feed.hs')
-rw-r--r--src/Hakyll/Web/Feed.hs122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/Hakyll/Web/Feed.hs b/src/Hakyll/Web/Feed.hs
new file mode 100644
index 0000000..25f31db
--- /dev/null
+++ b/src/Hakyll/Web/Feed.hs
@@ -0,0 +1,122 @@
+-- | A Module that allows easy rendering of RSS feeds.
+--
+-- The main rendering functions (@renderRss@, @renderAtom@) all assume that
+-- you pass the list of items so that the most recent entry in the feed is the
+-- first item in the list.
+--
+-- Also note that the pages should have (at least) the following fields to
+-- produce a correct feed:
+--
+-- - @$title@: Title of the item
+--
+-- - @$description@: Description to appear in the feed
+--
+-- - @$url@: URL to the item - this is usually set automatically.
+--
+-- In addition, the posts should be named according to the rules for
+-- 'Hakyll.Page.Metadata.renderDateField'.
+--
+module Hakyll.Web.Feed
+ ( FeedConfiguration (..)
+ , renderRss
+ , renderAtom
+ ) where
+
+import Prelude hiding (id)
+import Control.Category (id)
+import Control.Arrow ((>>>), arr, (&&&))
+import Control.Monad ((<=<))
+import Data.Maybe (fromMaybe, listToMaybe)
+
+import Hakyll.Core.Compiler
+import Hakyll.Web.Page
+import Hakyll.Web.Page.Metadata
+import Hakyll.Web.Template
+
+import Paths_hakyll
+
+-- | This is a data structure to keep the configuration of a feed.
+data FeedConfiguration = FeedConfiguration
+ { -- | Title of the feed.
+ feedTitle :: String
+ , -- | Description of the feed.
+ feedDescription :: String
+ , -- | Name of the feed author.
+ feedAuthorName :: String
+ , -- | Absolute root URL of the feed site (e.g. @http://jaspervdj.be@)
+ feedRoot :: String
+ }
+
+-- | This is an auxiliary function to create a listing that is, in fact, a feed.
+-- The items should be sorted on date. The @$timestamp@ field should be set.
+--
+createFeed :: Template -- ^ Feed template
+ -> Template -- ^ Item template
+ -> String -- ^ URL of the feed
+ -> FeedConfiguration -- ^ Feed configuration
+ -> [Page String] -- ^ Items to include
+ -> String -- ^ Resulting feed
+createFeed feedTemplate itemTemplate url configuration items =
+ pageBody $ applyTemplate feedTemplate
+ $ setField "timestamp" timestamp
+ $ setField "title" (feedTitle configuration)
+ $ setField "description" (feedDescription configuration)
+ $ setField "authorName" (feedDescription configuration)
+ $ setField "root" (feedRoot configuration)
+ $ setField "url" url
+ $ fromBody body
+ where
+ -- Preprocess items
+ items' = flip map items $ applyTemplate itemTemplate
+ . setField "root" (feedRoot configuration)
+
+ -- Body: concatenated items
+ body = concat $ map pageBody items'
+
+ -- Take the first timestamp, which should be the most recent
+ timestamp = fromMaybe "Unknown" $ do
+ p <- listToMaybe items
+ return $ getField "timestamp" p
+
+
+-- | Abstract function to render any feed.
+--
+renderFeed :: FilePath -- ^ Feed template
+ -> FilePath -- ^ Item template
+ -> FeedConfiguration -- ^ Feed configuration
+ -> Compiler [Page String] String -- ^ Feed compiler
+renderFeed feedTemplate itemTemplate configuration =
+ id &&& getRoute >>> renderFeed'
+ where
+ -- Arrow rendering the feed from the items and the URL
+ renderFeed' = unsafeCompiler $ \(items, url) -> do
+ feedTemplate' <- loadTemplate feedTemplate
+ itemTemplate' <- loadTemplate itemTemplate
+ let url' = fromMaybe noUrl url
+ return $ createFeed feedTemplate' itemTemplate' url' configuration items
+
+ -- Auxiliary: load a template from a datafile
+ loadTemplate = fmap readTemplate . readFile <=< getDataFileName
+
+ -- URL is required to have a valid field
+ noUrl = error "Hakyll.Web.Feed.renderFeed: no route specified"
+
+-- | Render an RSS feed with a number of items.
+--
+renderRss :: FeedConfiguration -- ^ Feed configuration
+ -> Compiler [Page String] String -- ^ Feed compiler
+renderRss configuration = arr (map renderDate)
+ >>> renderFeed "templates/rss.xml" "templates/rss-item.xml" configuration
+ where
+ renderDate = renderDateField "timestamp" "%a, %d %b %Y %H:%M:%S UT"
+ "No date found."
+
+-- | Render an Atom feed with a number of items.
+--
+renderAtom :: FeedConfiguration -- ^ Feed configuration
+ -> Compiler [Page String] String -- ^ Feed compiler
+renderAtom configuration = arr (map renderDate)
+ >>> renderFeed "templates/atom.xml" "templates/atom-item.xml" configuration
+ where
+ renderDate = renderDateField "timestamp" "%Y-%m-%dT%H:%M:%SZ"
+ "No date found."