packages feed

indieweb-algorithms-0.1.1: library/Data/IndieWeb/MicroformatsUtil.hs

{-# LANGUAGE OverloadedStrings, UnicodeSyntax #-}

module Data.IndieWeb.MicroformatsUtil where

import           Control.Lens
import           Data.Maybe
import           Data.Aeson
import           Data.Aeson.Lens
import qualified Data.Vector as V
import qualified Data.HashMap.Strict as HMS
import qualified Data.Text as T

-- | Recursively finds microformats of a given type, also keeping the path (in reverse order) that led to them.
-- Returns Nothing when the given Value isn't an object with an 'items' key, ie. is not a result of Microformats 2 parsing.
allMicroformatsOfType ∷ T.Text → Value → Maybe [(Value, [Value])]
allMicroformatsOfType typeName mf = do
  items ← mf ^? key "items" . _Array
  let findOfType acc path v =
        let valToList (Array vec) = V.toList vec
            valToList _ = []
            childMfs = V.toList $ fromMaybe V.empty $ v ^? key "children" . _Array
            propMfs = concatMap valToList $ HMS.elems $ fromMaybe HMS.empty $ v ^? key "properties" . _Object
            acc' = acc ++ concatMap (findOfType acc $ v : path) (childMfs ++ propMfs) in
        if String typeName `V.elem` fromMaybe V.empty (v ^? key "type" . _Array)
           then (v, path) : acc'
           else acc'
  Just $ concatMap (findOfType [] []) items

-- | Tests whether a given Value is of a given microformat type (e.g. h-entry, h-feed).
isMf ∷ T.Text → Value → Bool
isMf t = (String t `V.elem`) . (fromMaybe V.empty) . (^? key "type" . _Array)

data EntryType = Repost | Like | Bookmark | RSVP | Reply | Checkin | Event | Audio | Photo | Article | Note
  deriving (Show, Eq)

-- | Detects a post type (https://indiewebcamp.com/posts#Kinds_of_Posts)
detectEntryType ∷ Value → EntryType
detectEntryType entry
  | isJust (entry ^? key "properties" . key "repost-of" . nth 0) = Repost
  | isJust (entry ^? key "properties" . key "like-of" . nth 0) = Like
  | isJust (entry ^? key "properties" . key "bookmark-of" . nth 0) = Bookmark
  | isJust (entry ^? key "properties" . key "rsvp" . nth 0) = RSVP
  | isJust (entry ^? key "properties" . key "in-reply-to" . nth 0) = Reply
  | isJust (entry ^? key "properties" . key "location" . nth 0) = Checkin
  | isJust (entry ^? key "properties" . key "event" . nth 0) = Event
  | isJust (entry ^? key "properties" . key "audio" . nth 0) = Audio
  | isJust (entry ^? key "properties" . key "photo" . nth 0) = Photo
  | isJust (entry ^? key "properties" . key "name" . nth 0) && (entry ^? key "properties" . key "name" . nth 0) /= (entry ^? key "properties" . key "content" . nth 0 . key "value") = Article
  | otherwise = Note