tweet-hs 0.4.0.7 → 0.5.0.0
raw patch · 5 files changed
+59/−34 lines, 5 filesdep ~tweet-hs
Dependency ranges changed: tweet-hs
Files
- src/Web/Tweet.hs +4/−2
- src/Web/Tweet/Exec.hs +24/−8
- src/Web/Tweet/Types.hs +3/−3
- src/Web/Tweet/Utils.hs +26/−19
- tweet-hs.cabal +2/−2
src/Web/Tweet.hs view
@@ -32,6 +32,7 @@ , showTimeline , getProfile , showProfile+ , showBest , getDMs , showDMs , getRaw@@ -55,7 +56,6 @@ import Web.Authenticate.OAuth import Web.Tweet.Sign import Data.List.Utils-import qualified Data.Text as T -- | thread tweets together nicely. Takes a string, a list of handles to reply to, plus the ID of the status you're replying to. -- If you need to thread tweets without replying, pass a `Nothing` as the third argument.@@ -113,7 +113,7 @@ 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+ map (view text) . fromRight . getTweets . BSL.unpack <$> responseBS request manager -- | Get user profile given screen name and how many tweets to return getProfile screenName count filepath = do@@ -131,6 +131,8 @@ -- maximum is 3200), and whether to print them in color. showProfile :: Show t => String -> t -> Bool -> FilePath -> IO String showProfile screenName count color filepath = showTweets color <$> getProfile screenName count filepath++showBest screenName color filepath = showTweets color . (fmap (take 11 . hits)) <$> getProfile screenName 3200 filepath -- | Display user timeline showTimeline count color filepath = showTweets color <$> getTimeline count filepath
src/Web/Tweet/Exec.hs view
@@ -15,12 +15,13 @@ -- | 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 type for a -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 } +-- | Data type for a command+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 }+ | Sort { color :: Bool , screenName :: String } -- | query twitter to post stdin with no fancy options fromStdIn :: Int -> FilePath -> IO ()@@ -42,8 +43,8 @@ where opts = info (helper <*> program) (fullDesc- <> progDesc "SendInput from stdin!"- <> header "clit - a Command Line Interface SendInputer")+ <> progDesc "Tweet and view tweets"+ <> header "clit - a Command Line Interface Tweeter") -- | Executes program given parsed `Program` select :: Program -> IO ()@@ -87,6 +88,10 @@ 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 (Sort True name) (Just file)) = putStrLn =<< showBest name True file+select (Program (Sort True name) Nothing) = putStrLn =<< showBest name True =<< (++ "/.cred") <$> getHomeDirectory+select (Program (Sort False name) (Just file)) = putStrLn =<< showBest name False file+select (Program (Sort False name) Nothing) = putStrLn =<< showBest name False =<< (++ "/.cred") <$> getHomeDirectory select (Program (Raw name) Nothing) = do raw <- getRaw name =<< (++ "/.cred") <$> getHomeDirectory sequence_ $ putStrLn <$> raw@@ -102,7 +107,8 @@ <> 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 "raw" (info raw (progDesc "Grab tweetInputs en masse."))))+ <> command "raw" (info raw (progDesc "Grab tweets en masse."))+ <> command "hits" (info best (progDesc "View a user's top tweets.")))) <*> (optional $ strOption (long "cred" <> short 'c'@@ -141,6 +147,16 @@ (long "color" <> short 'l' <> help "Whether to display profile with colorized terminal output")+ <*> argument str+ (metavar "SCREEN_NAME"+ <> help "Screen name of user you want to view.")++best :: Parser Command+best = Sort+ <$> switch+ (long "color"+ <> short 'l'+ <> help "Display timeline with colorized terminal output.") <*> argument str (metavar "SCREEN_NAME" <> help "Screen name of user you want to view.")
src/Web/Tweet/Types.hs view
@@ -25,15 +25,15 @@ data TweetEntity = TweetEntity { _text :: String , _name :: String- , _screenName :: Maybe String+ , _screenName :: String , _tweetId :: Int- , _isQuoteStatus :: Bool+ , _quoted :: Maybe TweetEntity , _retweets :: Int , _favorites :: Int } deriving (Generic, Default) -- | Stores data like (name, text, favoriteCount, retweetCount)-type Timeline = [(String, String, String, String)]+type Timeline = [TweetEntity] makeLenses ''Tweet
src/Web/Tweet/Utils.hs view
@@ -22,55 +22,62 @@ -- | Display Timeline without color displayTimeline :: Timeline -> String-displayTimeline ((user,content,fave,rts):rest) = (user <> ":\n " <> content) <> "\n " <> "♥ " {-- ♡💛--} <> fave <> " ♺ " <> rts <> "\n\n" <> (displayTimeline rest) -- +displayTimeline ((TweetEntity content user _ _ Nothing fave rts):rest) = (user <> ":\n " <> content) <> "\n " <> "♥ " <> (show fave) <> " ♺ " <> (show rts) <> "\n\n" <> (displayTimeline rest) +displayTimeline ((TweetEntity content user _ _ (Just quoted) fave rts):rest) = (user <> ":\n " <> content) <> "\n " <> "♥ " <> (show fave) <> " ♺ " <> (show rts) <> "\n " <> (_name quoted) <> ": " <> (_text quoted) <> "\n\n" <> (displayTimeline rest) displayTimeline [] = [] -- | Display Timeline in color displayTimelineColor :: Timeline -> String-displayTimelineColor ((user,content,fave,rts):rest) = ((toYellow user) <> ":\n " <> content) <> "\n " <> (toRed "♥ ") {-- ♡💛--} <> fave <> (toGreen " ♺ ") <> rts <> "\n\n" <> (displayTimelineColor rest) -- +displayTimelineColor ((TweetEntity content user _ _ Nothing fave rts):rest) = ((toYellow user) <> ":\n " <> content) <> "\n " <> (toRed "♥ ") <> (show fave) <> (toGreen " ♺ ") <> (show rts) <> "\n\n" <> (displayTimelineColor rest) +displayTimelineColor ((TweetEntity content user _ _ (Just quoted) fave rts):rest) = ((toYellow user) <> ":\n " <> content) <> "\n " <> (toRed "♥ ") <> (show fave) <> (toGreen " ♺ ") <> (show rts) <> "\n " <> (toYellow $ _name quoted) <> ": " <> (_text quoted) <> "\n\n" <> (displayTimelineColor rest) displayTimelineColor [] = [] -- | Get a list of tweets from a response, returning author, favorites, retweets, and content. getTweets = parse parseTweet "" +-- TODO add feature to filter out quotes etc. Or make it a sub-thing?+sortTweets :: Timeline -> Timeline+sortTweets = sortBy compareTweet+ where compareTweet (TweetEntity _ _ _ _ _ f1 r1) (TweetEntity _ _ _ _ _ f2 r2) = compare (2*r2 + f2) (2*r1 + f1)+ -- | Parse some number of tweets parseTweet :: Parser Timeline-parseTweet = concat <$> many (try getData <|> (const (pure ("","","","")) <$> eof))+parseTweet = many (try getData <|> (const (TweetEntity "" "" "" 0 Nothing 0 0) <$> eof)) -hits = sortFaves . filterRTs+hits = sortTweets . filterRTs filterRTs :: Timeline -> Timeline-filterRTs = filter ((/="RT") . take 2 . (view _2))--sortFaves :: Timeline -> Timeline-sortFaves = sortBy compareFavorites- where compareFavorites = on compare ((read :: String -> Int) . (view _3))+filterRTs = filter ((/="RT @") . take 4 . (view text)) -- | Parse a single tweet's: name, text, fave count, retweet count-getData :: Parser [(String, String, String, String)]+getData :: Parser TweetEntity getData = do+ id <- read <$> filterStr "id" -- FIXME check it doesn't drop anything text <- filterStr "text" skipMentions name <- filterStr "name"+ screenName <- filterStr "screen_name" isQuote <- filterStr "is_quote_status" case isQuote of "false" -> do- rts <- filterStr "retweet_count"- faves <- filterStr "favorite_count"- pure $ pure (name, text, faves, rts)+ rts <- read <$> filterStr "retweet_count"+ faves <- read <$> filterStr "favorite_count"+ pure (TweetEntity text name screenName id Nothing rts faves) "true" -> do+ idQuoted <- read <$> filterStr "id" textQuoted <- filterStr "text" skipMentions nameQuoted <- filterStr "name"- rtsQuoted <- filterStr "retweet_count"- favesQuoted <- filterStr "favorite_count"- rts <- filterStr "retweet_count"- faves <- filterStr "favorite_count"- pure [(name, text, faves, rts), (nameQuoted, textQuoted, favesQuoted, rtsQuoted)]+ screenNameQuoted <- filterStr "screen_name"+ rtsQuoted <- read <$> filterStr "retweet_count"+ favesQuoted <- read <$> filterStr "favorite_count"+ rts <- read <$> filterStr "retweet_count"+ faves <- read <$> filterStr "favorite_count"+ pure $ TweetEntity text name screenName id (Just (TweetEntity textQuoted nameQuoted screenNameQuoted idQuoted Nothing rtsQuoted favesQuoted)) rts faves -- TODO make it work when user names include ] skipInsideBrackets :: Parser ()-skipInsideBrackets =void (between (char '[') (char ']') $ many (skipInsideBrackets <|> void (noneOf "[]")))+skipInsideBrackets = void (between (char '[') (char ']') $ many (skipInsideBrackets <|> void (noneOf "[]"))) skipMentions :: Parser () skipMentions = do
tweet-hs.cabal view
@@ -1,5 +1,5 @@ name: tweet-hs-version: 0.4.0.7+version: 0.5.0.0 cabal-version: >=1.10 build-type: Simple license: BSD3@@ -64,7 +64,7 @@ main-is: Main.hs build-depends: base >=4.9.1.0 && <4.10,- tweet-hs >=0.4.0.7 && <0.5+ tweet-hs >=0.5.0.0 && <0.6 default-language: Haskell2010 hs-source-dirs: app