indieweb-algorithms-0.1.1: library/Data/IndieWeb/SiloToMicroformats.hs
{-# LANGUAGE OverloadedStrings, UnicodeSyntax #-}
module Data.IndieWeb.SiloToMicroformats where
import Prelude
import Text.XML.Lens
import qualified Data.Text as T
import qualified Data.Text.Read as T
import Data.Aeson
import Data.Aeson.Lens (key)
import Data.Maybe
import Control.Applicative
import Control.Lens hiding ((.=))
import Control.Error.Util (hush)
import Data.Time.Format
import Data.Time.Clock.POSIX
import Data.Microformats2.Parser.HtmlUtil
import Data.Microformats2.Parser.Property (getImgSrc)
import Data.Microformats2.Parser (extractProperty, Mf2ParserSettings)
-- | Parses a twitter.com tweet into an h-entry value.
parseTwitter ∷ Mf2ParserSettings → Element → Maybe Value
parseTwitter s r = if isJust tweet && isJust username && isJust tweetText
then Just wrapper
else Nothing
where wrapper = object [ "type" .= [ String "h-entry" ]
, "properties" .= props ]
props = object [ "uid" .= [ permalink ]
, "url" .= [ permalink ]
, "content" .= [ tweetText ]
, "name" .= [ fromMaybe Null $ tweetText >>= (^? key "value") ]
, "published" .= [ str timestamp ]
, "author" .= [ author ]
, "comment" .= comments ]
author = object [ "type" .= [ String "h-card" ]
, "properties" .= object ([ "uid" .= [ profileUrl username ]
, "url" .= [ profileUrl username ]
, "name" .= [ str fullname ]
, "note" .= [ str bio ]
, "nickname" .= [ str username ]
, "photo" .= [ str avatar ] ] ++ pronouns) ]
comments = mapMaybe (parseTwitter s) $ r ^.. hasClass "permalink-replies" ... hasClass "tweet"
profileUrl (Just x) = String $ "https://twitter.com/" <> T.dropWhile (== '@') x
profileUrl _ = Null
tweetText = tweet >>= (^? hasClass "tweet-text") >>= return . extractProperty s "e"
fullname = tweet >>= (^? hasClass "fullname") >>= getInnerTextRaw
timestamp = tweet >>= (^? hasClass "_timestamp" . attr "data-time") >>= reformatTime
reformatTime x = T.pack <$> formatTime defaultTimeLocale (iso8601DateFormat $ Just "%H:%M:%S") <$>
posixSecondsToUTCTime <$> realToFrac <$> fst <$> (hush $ T.decimal x ∷ Maybe (Integer, T.Text))
username = tweet >>= (^? hasClass "username") >>= getInnerTextRaw
avatar = tweet >>= (^? hasClass "avatar") >>= getImgSrc
permalink = tweet >>= (^? hasClass "tweet-timestamp") >>= return . extractProperty s "u"
bio = (r ^? hasClass "ProfileHeaderCard-bio" ) >>= getInnerTextRaw
pronouns = parsePronouns [] $ fromMaybe [] $ T.splitOn "/" <$> r ^? hasClass "ProfileSidebar" . cosmos . named "a" . attributeSatisfies "title" ("pronoun.is/" `T.isInfixOf`) . attr "title"
parsePronouns result (w : ww : "pronoun.is" : n : o : _ : p : _) = parsePronouns (("x-pronoun-posessive" .= [ String p ]) : result) (w : ww : "pronoun.is" : n : o : [])
parsePronouns result (w : ww : "pronoun.is" : n : o : _) = parsePronouns (("x-pronoun-oblique" .= [ String o ]) : result) (w : ww : "pronoun.is" : n : [])
parsePronouns result (_ : _ : "pronoun.is" : n : _) = ("x-pronoun-nominative" .= [ String n ]) : result
parsePronouns result _ = result
tweet = r ^? hasClass "permalink-tweet" <|> r ^? hasClass "tweet"
hasClass c = cosmos . attributeSatisfies "class" (c `T.isInfixOf`)
str (Just x) = String x
str _ = Null