packages feed

VKHS-0.5.2: src/VKNews.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}

module Main where

import Control.Applicative
import Control.Concurrent (threadDelay)
import Control.Monad.Trans
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Error
import Control.Monad
import Data.Aeson
import Data.Maybe
import Data.Either
import Data.Monoid
import Data.Time.Clock
import Options.Applicative
import System.Environment
import System.Exit
import System.IO
import Text.Printf
import Text.RegexPR
import Web.VKHS as VK hiding (api,api')
import Web.VKHS.API.Monad as VK
import Network.CURL730

data Options = Options
  { verb :: Verbosity
  , application_id :: String
  , access_token :: String
  , vk_poll_interval_sec :: Int
  , username :: String
  , password :: String
  -- , vk_group_id :: String
  } deriving(Show)

data Pirozhok = Pirozhok
  { plines :: String
  , pdate :: UTCTime
  }

pprint p = liftIO $ do
  -- putStrLn (show $ pdate p)
  putStr (plines p)

type PState a = StateT UTCTime (VKAPI IO) a

instance Error (String,Maybe a) where
  strMsg s = (s,Nothing)

pirozhok d' wr@(WR _ _ _ t _) = Pirozhok <$> poetry <*> date
  where
    poetry = txt >>= nonempty >>= four >>=
             maxlet >>= (pure . unlines)
    date = check (publishedAt wr) where
      check d | d <= d' = oops $ "older than " ++ (show d')
              | otherwise = pure d
    txt = pure $ lines $ gsubRegexPR "<br>" "\n" $ takeWhile (/= '©') t
    nonempty ls = pure $ filter (/=[]) ls
    four ls | length ls >4 = oops "more than 4 lines"
            | otherwise = pure ls
    maxlet ls | (sum $ map length ls) > 250 = oops "more than 250 letters"
              | otherwise = pure ls
    oops s = throwError (s, Just wr)

env_var_name = "VKNEWS_ACCESS_TOKEN"

opts at = Options
  <$> flag Normal Debug (long "verbose" <> help "Be verbose")
  <*> strOption (long "application-id" <> short 'a' <> value vkhs_app_id <> help (printf "Application ID (can be set via %s)" env_var_name))
  <*> strOption (long "access-token" <> short 't' <> value at <> help "Access token")
  <*> option (long "poll-interval" <> short 'i' <> value 20 <> help "Poll interval [sec]")
  <*> argument str (metavar "USERNAME" <> help "User name")
  <*> strOption (metavar "STR" <> long "password" <> short 'p' <> value "-" <> help "Password")
  -- <*> argument str (metavar "GROUPID" <> help "Vkontakte ID of the group to read the news from")
  where
    vkhs_app_id = "3128877"

pirozhki = do
  Response (SL len ws) <- lift $ VK.api' "wall.get" [("owner_id",gid_piro)]
  d <- get
  e <- ask
  let ps = map (pirozhok d) ws
  let d' = maxtime d (map pdate $ rights ps)
  forM (lefts ps) $ \(s,wr) -> do
    when (verbose e >= Trace) $ do
      liftIO $ hPutStrLn stderr $ printf "Rejecting record %s. Reason: %s" (maybe "?" (show . wid) wr) s
  when (d' > d) $ do
    when (verbose e >= Trace) $ do
      liftIO $ hPutStrLn stderr $ printf "Updating time to %s" (show d')
    (put d')
  return (rights ps)
  where
    maxtime d [] = d
    maxtime d ps = maximum ps
    gid_piro = "-28122932"

cmd :: Options -> IO ()
cmd (Options v apid at pollint u pass) = run $ do
  forever $ do
    ps <- pirozhki
    forM ps $ \p -> do
        pprint p
        pmsg []
    sleep_sec pollint

    where

      run vk = do
        t <- getCurrentTime
        let e = (VK.env apid u pass VK.allAccess) { verbose = v }
        let ma = runStateT vk t
        r <- runVKAPI ma ([],[],[]) e
        case r of
          Left er -> do
            perror (show er)
            exitFailure
          Right ((a,_),_) -> return a

      perror s = liftIO $ hPutStrLn stderr s

      pmsg s = liftIO $ putStrLn s

      sleep_sec s = liftIO $ threadDelay (1000 * 1000 * s)


main :: IO ()
main = withlib CURL730 $ do
  hSetBuffering stdout NoBuffering
  hSetBuffering stderr NoBuffering
  at <- fromMaybe [] <$> lookupEnv env_var_name
  execParser (info (opts at) idm) >>= cmd