{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Main (main) where
import Prelude ()
import BasicPrelude
import Data.Default (def)
import Text.Blaze ((!), customAttribute)
import Data.Time (getZonedTime, ZonedTime)
import Data.Time.Format.ISO8601 (iso8601ParseM, iso8601Show)
import Control.Monad.Error.Class (throwError)
import qualified Text.Blaze as Blaze
import qualified Text.Blaze.Internal as Blaze
import qualified Text.Blaze.Renderer.Text as Blaze
import qualified Dhall
import qualified Text.Pandoc as Pandoc
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TL
s :: (IsString s) => String -> s
s = fromString
data PandocSource = PandocSource {
source :: Text,
reader :: String
} deriving (Dhall.Generic, Dhall.FromDhall, Show)
data Author = Author {
name :: Text,
uri :: Text
} deriving (Dhall.Generic, Dhall.FromDhall, Show)
instance Blaze.ToMarkup Author where
toMarkup theAuthor = Blaze.customParent (s"author") $ do
Blaze.customParent (s"name") (Blaze.text $ name theAuthor)
Blaze.customParent (s"uri") (Blaze.text $ uri theAuthor)
data Time = Now | At Text deriving (Dhall.Generic, Dhall.FromDhall, Show)
zonedTime :: Time -> IO ZonedTime
zonedTime Now = getZonedTime
zonedTime (At time) = iso8601ParseM (textToString time)
data Enclosure = Enclosure {
type_ :: Text,
href_ :: Text,
title_ :: Text
} deriving (Dhall.Generic, Show)
instance Dhall.FromDhall Enclosure where
autoWith _ =
Dhall.genericAutoWith Dhall.defaultInterpretOptions
{ Dhall.fieldModifier = T.dropWhileEnd (=='_') }
instance Blaze.ToMarkup Enclosure where
toMarkup (Enclosure ty h ti) =
Blaze.customLeaf (s"link") True
! customAttribute (s"rel") (s"enclosure")
! customAttribute (s"type") (Blaze.toValue ty)
! customAttribute (s"title") (Blaze.toValue ti)
! customAttribute (s"href") (Blaze.toValue h)
data Config = Config {
id :: Text,
httpUri :: Maybe Text,
title :: Text,
author :: Author,
contentText :: Maybe Text,
contentXHTML :: Maybe PandocSource,
comments :: Bool,
published :: Time,
updated :: Time,
category :: [Text],
enclosures :: [Enclosure]
} deriving (Dhall.Generic, Dhall.FromDhall, Show)
pandocReader :: (Pandoc.PandocMonad m) =>
String
-> Text
-> m Pandoc.Pandoc
pandocReader readerSpec txt = do
(theReader, theExtensions) <- Pandoc.getReader (fromString readerSpec)
case theReader of
Pandoc.ByteStringReader _ -> throwError $
Pandoc.PandocAppError $ s"No support for binary formats"
Pandoc.TextReader r ->
r (def { Pandoc.readerExtensions = theExtensions }) txt
main :: IO ()
main = do
[service, node] <- getArgs
config <- getContents >>= Dhall.input Dhall.auto . TL.toStrict
xhtml <- case contentXHTML config of
Just content -> do
pandoc <- Pandoc.runIOorExplode (pandocReader (reader content) (source content))
xhtml <- Pandoc.runIOorExplode (Pandoc.writeHtml5 def pandoc)
return $ Just (xhtml, pandoc)
Nothing -> return Nothing
text <- case (contentText config, xhtml) of
(Just t, _) -> return $ Just t
(Nothing, Just (_, pandoc)) -> Just <$> Pandoc.runIOorExplode (Pandoc.writePlain def pandoc)
_ -> return Nothing
publishedZT <- zonedTime (published config)
updatedZT <- zonedTime (updated config)
let itemUri = s"xmpp:" ++ service ++ s"?;node=" ++ node ++ s";item=" ++ Main.id config
let commentUri = s"xmpp:" ++ service ++ s"?;node=" ++ node ++ s":comments/" ++ Main.id config
let entry =
Blaze.customParent (s"entry") ! customAttribute (s"xmlns") (s"http://www.w3.org/2005/Atom") $ do
Blaze.customParent (s"id")
$ Blaze.text itemUri
Blaze.customParent (s"title")
! customAttribute (s"type") (s"text")
$ Blaze.text $ title config
Blaze.toMarkup (author config)
Blaze.customLeaf (s"link") True
! customAttribute (s"rel") (s"alternate")
! customAttribute (s"href") (Blaze.toValue itemUri)
forM_ (httpUri config) $ \http ->
Blaze.customLeaf (s"link") True
! customAttribute (s"rel") (s"alternate")
! customAttribute (s"type") (s"text/html")
! customAttribute (s"href") (Blaze.toValue http)
when (comments config) $
Blaze.customLeaf (s"link") True
! customAttribute (s"title") (s"comments")
! customAttribute (s"rel") (s"replies")
! customAttribute (s"href") (Blaze.toValue commentUri)
forM_ (enclosures config) Blaze.toMarkup
forM_ text $ \txt ->
Blaze.customParent (s"content")
! customAttribute (s"type") (s"text")
$ Blaze.text txt
forM_ xhtml $ \(markup, _) ->
Blaze.customParent (s"content")
! customAttribute (s"type") (s"xhtml")
$ Blaze.customParent (s"div")
! customAttribute (s"xmlns") (s"http://www.w3.org/1999/xhtml")
$ markup
Blaze.customParent (s"published")
$ Blaze.string $ iso8601Show publishedZT
Blaze.customParent (s"updated")
$ Blaze.string $ iso8601Show updatedZT
forM_ (category config) $ \cat ->
Blaze.customLeaf (s"category") True
! customAttribute (s"term") (Blaze.toValue cat)
TL.putStrLn $ Blaze.renderMarkup $
Blaze.customParent (s"iq")
! customAttribute (s"to") (Blaze.toValue service)
! customAttribute (s"type") (s"set")
! customAttribute (s"id") (s"publishing")
$ Blaze.customParent (s"pubsub")
! customAttribute (s"xmlns") (s"http://jabber.org/protocol/pubsub")
$ Blaze.customParent (s"publish")
! customAttribute (s"node") (Blaze.toValue node)
$ Blaze.customParent (s"item")
! customAttribute (s"id") (Blaze.toValue $ Main.id config)
$ entry