packages feed

feed2lj-0.0.2: Feed2Lj.hs

-- vim: ts=2 sw=2 expandtab si ai :

import LjPost

import System.Environment (getArgs)
import System.Directory (renameFile)
import Control.Monad (liftM, mapM,ap)
import Maybe (fromJust, isNothing, isJust)
import Network.HTTP (urlEncode)

import Text.Regex.Posix ((=~))

import Network.Curl (curlGetString)
import Text.Feed.Import (parseFeedString)
import Text.Feed.Types (Feed, Item)
import Text.Feed.Query

import IO
import Codec.Binary.UTF8.String (encodeString)

--import Debug.Trace (trace)
--debug x = trace (show x) x

-- take first n sentences from string s
takeSentences n s
  | n > 0     = let (s',r) = takeSentence s
                in s' ++ takeSentences (n-1) r
  | otherwise = ""

takeSentence s =
  let ends = ".?!;"
      (first,rest) = break (`elem` ends) s
  in if not (null rest)
     then (first ++ [head rest],tail rest)
     else (first,[])

-- remove all html/xml tags, quick and dirty
eatTags :: String -> String
eatTags [] = []
eatTags s =
  let (b,t,a) = s =~ "</?[^>]*/?>" :: (String,String,String)
  in b ++ eatTags a

-- mini template engine
renderTemplate _ [] = []
renderTemplate alist s =
  let (b,t,a) = s =~ "%[a-z0-9]*%" :: (String,String,String)
      tagval t
         | t == "%%" = Just "%"
         | otherwise = let inner = take (length t - 2) $ drop 1 t
                       in  lookup inner alist
      val = tagval t
  in if isJust val
       then b ++ (fromJust val) ++ renderTemplate alist a
       else b ++ t ++ renderTemplate alist a

renderItem :: String -> Item -> String
renderItem t i =
  let title = ( fromJust . getItemTitle ) i
      link = ( fromJust . getItemLink ) i
      guid = ( fromJust . getItemId ) i
      summary = ( takeSentences 5 . eatTags . fromJust . getItemSummary) i
      tags = zip [ "title","link","text" ]
                 [ title, urlEncode link,summary ]
  in renderTemplate tags t

isNotSent sent i = ((snd . fromJust . getItemId) i) `notElem` sent

postItem u p t i = do
  let message = renderItem t i
  let subj = fromJust $ getItemTitle i
  r <- postToLj u p subj message
  if isSuccess r
    then putLjKey "url" r
    else putLjKey "errmsg" r

main = do
  url:_ <- getArgs
  (_,rawfeed) <- curlGetString url []

  ljuser <- return fromJust `ap` readLjSetting "username"
  ljpass <- return fromJust `ap` readLjSetting "password"
  sentfile <- return fromJust `ap` readLjSetting "sentfile"
  t <- return fromJust `ap` readLjSetting "template"
  sent_ids <- (return . lines) =<< readFile sentfile

  let feed = fromJust $ parseFeedString rawfeed
  let items = feedItems feed
  let newitems = reverse $ filter (isNotSent sent_ids) items
  let new_ids = map ( snd . fromJust . getItemId) newitems

  mapM_ (postItem ljuser ljpass t) newitems

  renameFile sentfile (sentfile ++ "~")
  writeFile sentfile $ unlines (sent_ids ++ new_ids)