packages feed

clit 0.3.2.0 → 0.4.0.0

raw patch · 7 files changed

+152/−54 lines, 7 filesdep ~clit

Dependency ranges changed: clit

Files

README.md view
@@ -24,6 +24,20 @@  ## Use +### View Profiles and timelines++To get your timeline, simply type:++```+tweet view+```++To view a user's profile, type e.g.++```+tweet user pinepapplesmear --color+```+ ### Sending tweets To tweet from stderr, run a command that pipes stderr to stdin, i.e. 
bash/example view
@@ -1,1 +1,1 @@-stack install 2&>1 >/dev/null | tweet -c ~/.cred send -t3+stack install 2&>1 >/dev/null | tweet -c ~/.cred input -t3
clit.cabal view
@@ -1,5 +1,5 @@ name: clit-version: 0.3.2.0+version: 0.4.0.0 cabal-version: >=1.10 build-type: Simple license: BSD3@@ -65,7 +65,7 @@     main-is: Main.hs     build-depends:         base >=4.9.1.0 && <4.10,-        clit >=0.3.2.0 && <0.4+        clit >=0.4.0.0 && <0.5     default-language: Haskell2010     hs-source-dirs: app 
src/Web/Tweet.hs view
@@ -34,6 +34,7 @@     , showProfile     , getDMs     , showDMs+    , getRaw     ) where  import Network.HTTP.Client@@ -50,6 +51,7 @@ import Data.List.Split (chunksOf) import Data.Maybe import Control.Lens+import Control.Lens.Tuple import Web.Authenticate.OAuth import Web.Tweet.Sign import Data.List.Utils@@ -67,8 +69,7 @@         Nothing -> case content of             [] -> pure ()             [x] -> void $ basicTweet x filepath-            y@(x:xs) -> do-                thread' y hs (Just 0) num filepath+            y@(x:xs) -> thread' y hs (Just 0) num filepath  -- | Helper function to make `thread` easier to write.  thread' :: [String] -> [String] -> Maybe Int -> Int -> FilePath -> IO ()@@ -104,21 +105,30 @@     request <- signRequest filepath $ initialRequest { method = "POST" }     responseInt request manager +getRaw screenName filepath = do+    let requestString = "?screen_name=" ++ screenName ++ "&count=3200"+    manager <- newManager tlsManagerSettings+    initialRequest <- parseRequest ("https://api.twitter.com/1.1/statuses/user_timeline.json" ++ requestString)+    request <- signRequest filepath $ initialRequest { method = "GET"}+    let fromRight (Right a) = a+    map (view _2) . fromRight .  getTweets . BSL.unpack <$> responseBS request manager+ getProfile screenName count filepath = do     let requestString = "?screen_name=" ++ screenName ++ "&count=" ++ (show count)     manager <- newManager tlsManagerSettings     initialRequest <- parseRequest ("https://api.twitter.com/1.1/statuses/user_timeline.json" ++ requestString)     request <- signRequest filepath $ initialRequest { method = "GET"}+    responseBS request manager     getTweets . BSL.unpack <$> responseBS request manager  showDMs count color filepath = showTweets color <$> getDMs count filepath +showProfile :: Show t => [Char] -> t -> Bool -> FilePath -> IO String showProfile screenName count color filepath = showTweets color <$> getProfile screenName count filepath  showTimeline count color filepath = showTweets color <$> getTimeline count filepath -showTweets color = fromRight . (fmap (if color then displayTimelineColor else displayTimeline))-    where fromRight (Right a) = a+showTweets color = (either show id) . (fmap (if color then displayTimelineColor else displayTimeline))  getDMs count filepath = do     let requestString = "?count=" ++ (show count)@@ -137,21 +147,22 @@ deleteTweet id filepath = do     manager <- newManager tlsManagerSettings     initialRequest <- parseRequest ("https://api.twitter.com/1.1/statuses/destroy/" ++ (show id) ++ ".json")-    request <- signRequest filepath $ initialRequest { method = "GET" }+    request <- signRequest filepath $ initialRequest { method = "POST" }     void $ responseBS request manager  responseBS :: Request -> Manager -> IO BSL.ByteString responseBS request manager = do     response <- httpLbs request manager-    putStrLn $ "The status code was: " ++ show (statusCode $ responseStatus response)+    let code = statusCode $ responseStatus response+    putStr $ if (code == 200) then "" else "failed :(\n error code: " ++ (show code) ++ "\n"     pure . responseBody $ response  -- | print output of a request and return status id as an `Int`.  responseInt :: Request -> Manager -> IO Int responseInt request manager = do     response <- httpLbs request manager-    putStrLn $ "The status code was: " ++ show (statusCode $ responseStatus response)-    BSL.putStrLn $ responseBody response+    let code = statusCode $ responseStatus response+    putStrLn $ if (code == 200) then "POST succesful!" else "failed :(\n error code: " ++ (show code)     return $ (read . (takeWhile (/=',')) . (drop 52)) (BSL.unpack $ responseBody response)  -- | Convert a tweet to a percent-encoded url for querying an API
src/Web/Tweet/Exec.hs view
@@ -1,4 +1,4 @@--- | Provides IO action that parses command line options and tweets from stdin+-- | Provides IO action that parses command line options and tweetInputs from stdin module Web.Tweet.Exec ( exec                       , Program (Program)) where @@ -7,19 +7,27 @@ import qualified Data.ByteString.Char8 as BS import Control.Monad import Data.Foldable (fold)+import Data.List import Data.Monoid import System.Directory --- | Data type for our program: one optional path to a credential file, (optionally) the number of tweets to make, the id of the status you're replying to, and a list of users you wish to mention.+-- | Data type for our program: one optional path to a credential file, (optionally) the number of tweetInputs to make, the id of the status you're replying to, and a list of users you wish to mention. data Program = Program { subcommand :: Command , cred :: Maybe FilePath } -data Command = Timeline { count :: Maybe Int , color :: Bool } | Send { tweets :: Maybe Int, replyId :: Maybe String, replyHandles :: Maybe [String] } | Profile { count :: Maybe Int , color :: Bool , screenName :: String }+data Command = Timeline { count :: Maybe Int , color :: Bool } +    | SendInput { tweetInputs :: Maybe Int, replyId :: Maybe String, replyHandles :: Maybe [String] } +    | Profile { count :: Maybe Int , color :: Bool , screenName :: String } +    | Raw { screenName :: String } +    | Send { tweets :: Maybe Int , replyId :: Maybe String , replyHandles :: Maybe [String] , userInput :: String }  -- | query twitter to post stdin with no fancy options fromStdIn :: Int -> FilePath -> IO () fromStdIn = threadStdIn [] Nothing --- | Threaded tweets from stdIn+fromCLI :: String -> Int -> FilePath -> IO ()+fromCLI str = thread str [] Nothing++-- | Threaded tweetInputs from stdIn threadStdIn :: [String] -> Maybe Int -> Int -> FilePath -> IO () threadStdIn hs idNum num filepath = do     contents <- getContents@@ -31,23 +39,35 @@     where         opts = info (helper <*> program)             (fullDesc-            <> progDesc "Send from stdin!"-            <> header "clit - a Command Line Interface Sender")+            <> progDesc "SendInput from stdin!"+            <> header "clit - a Command Line Interface SendInputer")  -- | Executes program select :: Program -> IO ()-select (Program (Send (Just n) Nothing Nothing) Nothing) = fromStdIn n =<< (++ "/.cred") <$> getHomeDirectory-select (Program (Send Nothing Nothing Nothing) Nothing) = fromStdIn 4  =<< (++ "/.cred") <$> getHomeDirectory-select (Program (Send (Just n) Nothing Nothing) (Just file))  = fromStdIn n file-select (Program (Send Nothing Nothing Nothing) (Just file) ) = fromStdIn 4 file-select (Program (Send (Just n) (Just id) (Just handles)) Nothing) = threadStdIn handles (read id) n  =<< (++ "/.cred") <$> getHomeDirectory-select (Program (Send (Just n) (Just id) (Just handles)) (Just file)) = threadStdIn handles (pure . read $ id) n file-select (Program (Send Nothing (Just id) (Just handles)) (Just file))  = threadStdIn handles (pure . read $ id) 4 file-select (Program (Send (Just n) (Just id) Nothing) Nothing) = threadStdIn [] (pure . read $ id) n  =<< (++ "/.cred") <$> getHomeDirectory-select (Program (Send Nothing (Just id) Nothing) Nothing) = threadStdIn [] (pure . read $ id) 4  =<< (++ "/.cred") <$> getHomeDirectory-select (Program (Send Nothing (Just id) (Just handles)) Nothing) = threadStdIn handles (pure . read $ id) 4  =<< (++ "/.cred") <$> getHomeDirectory-select (Program (Send (Just n) (Just id) Nothing) (Just file)) = threadStdIn [] (pure . read $ id) n file-select (Program (Send (Just n) Nothing (Just handles)) (Just file)) = threadStdIn handles Nothing n file+select (Program (Send (Just n) Nothing Nothing input) Nothing) = fromCLI input n =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Send Nothing Nothing Nothing input) Nothing) = fromCLI input 15  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Send (Just n) Nothing Nothing input) (Just file))  = fromCLI input n file+select (Program (Send Nothing Nothing Nothing input) (Just file)) = fromCLI input 15 file+select (Program (Send (Just n) (Just id) (Just handles) input) Nothing) = thread input handles (read id) n  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Send (Just n) (Just id) (Just handles) input) (Just file)) = thread input handles (pure . read $ id) n file+select (Program (Send Nothing (Just id) (Just handles) input) (Just file)) = thread input handles (pure . read $ id) 15 file+select (Program (Send (Just n) (Just id) Nothing input) Nothing) = (thread input [] (pure . read $ id) n)  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Send Nothing (Just id) Nothing input) Nothing) = thread input [] (pure . read $ id) 15  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Send Nothing (Just id) (Just handles) input) Nothing) = thread input handles (pure . read $ id) 15  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Send (Just n) (Just id) Nothing input) (Just file)) = thread input [] (pure . read $ id) n file+select (Program (Send (Just n) Nothing (Just handles) input) (Just file)) = thread input handles Nothing n file+select (Program (SendInput (Just n) Nothing Nothing) Nothing) = fromStdIn n =<< (++ "/.cred") <$> getHomeDirectory+select (Program (SendInput Nothing Nothing Nothing) Nothing) = fromStdIn 15  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (SendInput (Just n) Nothing Nothing) (Just file))  = fromStdIn n file+select (Program (SendInput Nothing Nothing Nothing) (Just file) ) = fromStdIn 15 file+select (Program (SendInput (Just n) (Just id) (Just handles)) Nothing) = threadStdIn handles (read id) n  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (SendInput (Just n) (Just id) (Just handles)) (Just file)) = threadStdIn handles (pure . read $ id) n file+select (Program (SendInput Nothing (Just id) (Just handles)) (Just file))  = threadStdIn handles (pure . read $ id) 15 file+select (Program (SendInput (Just n) (Just id) Nothing) Nothing) = threadStdIn [] (pure . read $ id) n  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (SendInput Nothing (Just id) Nothing) Nothing) = threadStdIn [] (pure . read $ id) 15  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (SendInput Nothing (Just id) (Just handles)) Nothing) = threadStdIn handles (pure . read $ id) 15  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (SendInput (Just n) (Just id) Nothing) (Just file)) = threadStdIn [] (pure . read $ id) n file+select (Program (SendInput (Just n) Nothing (Just handles)) (Just file)) = threadStdIn handles Nothing n file select (Program (Timeline Nothing False) Nothing) = putStrLn =<< showTimeline 8 False  =<< (++ "/.cred") <$> getHomeDirectory select (Program (Timeline Nothing False) (Just file)) = putStrLn =<< showTimeline 8 False file select (Program (Timeline (Just n) False) (Just file)) = putStrLn =<< showTimeline 8 False file@@ -64,14 +84,22 @@ select (Program (Profile Nothing False name) (Just file)) = putStrLn =<< showProfile name 12 False file select (Program (Profile (Just n) False name) Nothing) = putStrLn =<< showProfile name n False  =<< (++ "/.cred") <$> getHomeDirectory select (Program (Profile Nothing False name) Nothing) = putStrLn =<< showProfile name 12 False  =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Raw name) Nothing) = do+    raw <- getRaw name =<< (++ "/.cred") <$> getHomeDirectory+    sequence_ $ putStrLn <$> raw+select (Program (Raw name) (Just file)) = do+    raw <- getRaw name file+    sequence_ $ putStrLn <$> raw --fix this idk  -- | Parser to return a program datatype program :: Parser Program program = Program     <$> (hsubparser-        (command "send" (info tweet (progDesc "Send a tweet"))+        (command "send" (info tweet (progDesc "Send a tweet from the command-line"))+        <> command "input" (info tweetInput (progDesc "Send a tweet from stdIn"))         <> command "view" (info timeline (progDesc "Get your timeline"))-        <> command "user" (info profile (progDesc "Get a user's profile"))))+        <> command "user" (info profile (progDesc "Get a user's profile"))+        <> command "raw" (info raw (progDesc "Grab tweetInputs en masse."))))     <*> (optional $ strOption         (long "cred"         <> short 'c'@@ -84,19 +112,25 @@         (long "count"         <> short 'n'         <> metavar "NUM"-        <> help "number of tweets to fetch, default 5"))+        <> help "number of tweetInputs to fetch, default 5"))     <*> switch         (long "color"         <> short 'l'         <> help "Display timeline with colorized terminal output.") +raw :: Parser Command+raw = Raw+  <$> argument str+    (metavar "SCREEN_NAME"+    <> help "Screen name of user whose tweetInputs you want in bulk.")+ profile :: Parser Command profile = Profile     <$> (optional $ read <$> strOption         (long "count"         <> short 'n'         <> metavar "NUM"-        <> help "Number of tweets to fetch, default 12"))+        <> help "Number of tweetInputs to fetch, default 12"))     <*> switch         (long "color"         <> short 'l'@@ -111,11 +145,31 @@         (long "tweets"         <> short 't'         <> metavar "NUM"-        <> help "Number of tweets in a row, default 4"))+        <> help "Number of tweetInputs in a row, default 15"))     <*> (optional $ strOption         (long "reply"         <> short 'r'         <> help "id of status to reply to - be sure to include their handle, e.g. @my_build_errors"))-    <*> (optional $ some $ argument str+    <*> (optional $ (some $ strOption $+        (long "handle"+        <> short 'h'+        <> metavar "HANDLE1"+        <> help "Handles to include in replies")))+    <*> (intercalate " " <$> (some $ argument str+        (metavar "TEXT"+        <> help "text of tweet to be sent")))++tweetInput :: Parser Command+tweetInput = SendInput+    <$> (optional $ read <$> strOption+        (long "tweets"+        <> short 't'+        <> metavar "NUM"+        <> help "Number of tweets in a row, default 15"))+    <*> (optional $ strOption+        (long "reply"+        <> short 'r'+        <> help "id of status to reply to - be sure to include their handle, e.g. @my_build_errors"))+    <*> (optional $ (some $ argument str         (metavar "HANDLE1"-        <> help "handles to include in replies"))+        <> help "handles to include in replies")))
src/Web/Tweet/Types.hs view
@@ -22,8 +22,8 @@     , _replyID  :: Maybe Int     } deriving (Generic, Default) --- | Stores data like (text, screenName)-type Timeline = [(String, String)]+-- | Stores data like (text, screenName, favoriteCount, retweetCount)+type Timeline = [(String, String, String, String)]  makeLenses ''Tweet 
src/Web/Tweet/Utils.hs view
@@ -5,9 +5,11 @@ import Text.Megaparsec.String import Text.Megaparsec import Data.Monoid+import Data.Maybe import Web.Tweet.Types import Control.Monad import Text.PrettyPrint.ANSI.Leijen hiding ((<$>), char, (<>), string)+import Control.Lens.Tuple  -- example text -- Emma Watson, seins nus dans \u00abVanity Fair\u00bb, f\u00e9ministe ou hypocrite? \u27a1\ufe0f https:\/\/t.co\/MIPx1EpRSK https:\/\/t.co\/uSnLayoPi6@@ -18,31 +20,48 @@ parseDMs = zip <$> (extractEvery 2 <$> filterStr "screen_name") <*> (filterStr "text")     where extractEvery n = map snd . filter ((== n) . fst) . zip (cycle [1..n]) +displayTimeline :: Timeline -> String+displayTimeline ((user,content,fave,rts):rest) = (user <> ":\n    " <> content) <> "\n    " <> "♡ " {-- 💛--} <> fave <> "\n" <> (displayTimeline rest)+displayTimeline [] = []+ displayTimelineColor :: Timeline -> String-displayTimelineColor ((user,content):rest) = ((show . yellow . text $ user) <> ":\n    " <> content <> "\n") <> (displayTimelineColor rest)+displayTimelineColor ((user,content,fave,rts):rest) = ((show . yellow . text $ user) <> ":\n    " <> content) <> "\n    " <> (show . red . text $ "♥ ") {-- ♡💛--} <> fave <> (show . green . text $ " ♺ ") <> rts <> "\n" <> (displayTimelineColor rest) --  displayTimelineColor [] = [] -displayTimeline :: Timeline -> String-displayTimeline ((user,content):rest) = (user <> ":\n    " <> content <> "\n") <> (displayTimeline rest) -- color should be configurable at least! -displayTimeline [] = []+-- | Get tweets from a response, disgarding all but author, favorites, retweets, and content+getTweets = parse parseTweet ""  --- | Get tweets from a response, disgarding all but author and content-getTweets str = zip <$> (parse (filterStr "name") "" str) <*> (parse (filterStr "text") "" str)+parseTweet :: Parser Timeline+parseTweet = many (try getData <|> (const ("","","","") <$> eof)) -filterTl :: Parser Timeline-filterTl = zip <$> (filterStr "name") <*> (filterStr "text")+getData :: Parser (String, String, String, String)+getData = do+    text <- filterStr "text"+    userMentions <- filterStr "user_mentions"+    name <- if userMentions == "[]" then filterStr "name" else filterStr "name" >> filterStr "name"+    isQuote <- filterStr "is_quote_status"+    case isQuote of+        "false" -> do+            rts <- filterStr "retweet_count"+            faves <- filterStr "favorite_count"+            pure (name, text, faves, rts)+        "true" -> do+            rts <- filterStr "retweet_count" >> filterStr "retweet_count"+            faves <- filterStr "favorite_count"+            pure (name, text, faves, rts) -filterStr :: String -> Parser [String]-filterStr str = (fmap (filter (/=""))) . many $-    filterTag str <|> (const "" <$> anyChar)+filterStr :: String -> Parser String+filterStr str = do+    many $ try $ anyChar >> notFollowedBy (string ("\"" <> str <> "\":"))+    char ','+    filterTag str  filterTag :: String -> Parser String filterTag str = do-    string $ "\"" <> str <> "\""-    char ':'-    char '\"'-    want <- many $ noneOf "\\\"" <|> specialChar '\"' <|> specialChar '/' <|> specialChar 'n' <|> specialChar 'u'-    char '\"'+    string $ "\"" <> str <> "\":"+    open <- optional $ char '\"'+    let forbidden = if (isJust open) then "\\\"" else "\\\","+    want <- many $ noneOf forbidden <|> specialChar '\"' <|> specialChar '/' <|> specialChar 'n' <|> specialChar 'u'     pure want  specialChar :: Char -> Parser Char