packages feed

twitter-feed 0.1.1.1 → 0.1.1.2

raw patch · 4 files changed

+167/−139 lines, 4 filesdep +bytestringdep +twitter-feeddep ~HUnitdep ~aesondep ~authenticate-oauthPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: bytestring, twitter-feed

Dependency ranges changed: HUnit, aeson, authenticate-oauth, base, containers, http-conduit, test-framework-hunit

API changes (from Hackage documentation)

- Web.Twitter.Feed: Link :: Int -> Int -> String -> Link
- Web.Twitter.Feed: MediaEntity :: String -> BoundingIndices -> String -> MediaEntity
- Web.Twitter.Feed: URLEntity :: String -> BoundingIndices -> String -> URLEntity
- Web.Twitter.Feed: UserEntity :: String -> BoundingIndices -> UserEntity
- Web.Twitter.Feed: data Link
- Web.Twitter.Feed: data MediaEntity
- Web.Twitter.Feed: data Tweet
- Web.Twitter.Feed: data URLEntity
- Web.Twitter.Feed: data UserEntity
- Web.Twitter.Feed: displayMediaUrl :: MediaEntity -> String
- Web.Twitter.Feed: displayUrl :: URLEntity -> String
- Web.Twitter.Feed: endIndex :: Link -> Int
- Web.Twitter.Feed: instance Constructor C1_0Entities
- Web.Twitter.Feed: instance Constructor C1_0MediaEntity
- Web.Twitter.Feed: instance Constructor C1_0SimpleTweet
- Web.Twitter.Feed: instance Constructor C1_0Tweet
- Web.Twitter.Feed: instance Constructor C1_0URLEntity
- Web.Twitter.Feed: instance Constructor C1_0UserEntity
- Web.Twitter.Feed: instance Datatype D1Entities
- Web.Twitter.Feed: instance Datatype D1MediaEntity
- Web.Twitter.Feed: instance Datatype D1SimpleTweet
- Web.Twitter.Feed: instance Datatype D1Tweet
- Web.Twitter.Feed: instance Datatype D1URLEntity
- Web.Twitter.Feed: instance Datatype D1UserEntity
- Web.Twitter.Feed: instance Eq Link
- Web.Twitter.Feed: instance FromJSON Entities
- Web.Twitter.Feed: instance FromJSON MediaEntity
- Web.Twitter.Feed: instance FromJSON Tweet
- Web.Twitter.Feed: instance FromJSON URLEntity
- Web.Twitter.Feed: instance FromJSON UserEntity
- Web.Twitter.Feed: instance Generic Entities
- Web.Twitter.Feed: instance Generic MediaEntity
- Web.Twitter.Feed: instance Generic SimpleTweet
- Web.Twitter.Feed: instance Generic Tweet
- Web.Twitter.Feed: instance Generic URLEntity
- Web.Twitter.Feed: instance Generic UserEntity
- Web.Twitter.Feed: instance Selector S1_0_0Entities
- Web.Twitter.Feed: instance Selector S1_0_0MediaEntity
- Web.Twitter.Feed: instance Selector S1_0_0SimpleTweet
- Web.Twitter.Feed: instance Selector S1_0_0Tweet
- Web.Twitter.Feed: instance Selector S1_0_0URLEntity
- Web.Twitter.Feed: instance Selector S1_0_0UserEntity
- Web.Twitter.Feed: instance Selector S1_0_1Entities
- Web.Twitter.Feed: instance Selector S1_0_1MediaEntity
- Web.Twitter.Feed: instance Selector S1_0_1SimpleTweet
- Web.Twitter.Feed: instance Selector S1_0_1Tweet
- Web.Twitter.Feed: instance Selector S1_0_1URLEntity
- Web.Twitter.Feed: instance Selector S1_0_1UserEntity
- Web.Twitter.Feed: instance Selector S1_0_2Entities
- Web.Twitter.Feed: instance Selector S1_0_2MediaEntity
- Web.Twitter.Feed: instance Selector S1_0_2SimpleTweet
- Web.Twitter.Feed: instance Selector S1_0_2Tweet
- Web.Twitter.Feed: instance Selector S1_0_2URLEntity
- Web.Twitter.Feed: instance Selector S1_0_3Tweet
- Web.Twitter.Feed: instance Show Entities
- Web.Twitter.Feed: instance Show Link
- Web.Twitter.Feed: instance Show MediaEntity
- Web.Twitter.Feed: instance Show SimpleTweet
- Web.Twitter.Feed: instance Show Tweet
- Web.Twitter.Feed: instance Show URLEntity
- Web.Twitter.Feed: instance Show UserEntity
- Web.Twitter.Feed: instance ToJSON Entities
- Web.Twitter.Feed: instance ToJSON MediaEntity
- Web.Twitter.Feed: instance ToJSON SimpleTweet
- Web.Twitter.Feed: instance ToJSON Tweet
- Web.Twitter.Feed: instance ToJSON URLEntity
- Web.Twitter.Feed: instance ToJSON UserEntity
- Web.Twitter.Feed: mediaIndices :: MediaEntity -> BoundingIndices
- Web.Twitter.Feed: mediaUrl :: MediaEntity -> String
- Web.Twitter.Feed: newHtml :: Link -> String
- Web.Twitter.Feed: screenName :: UserEntity -> String
- Web.Twitter.Feed: startIndex :: Link -> Int
- Web.Twitter.Feed: urlIndices :: URLEntity -> BoundingIndices
- Web.Twitter.Feed: urlMessage :: URLEntity -> String
- Web.Twitter.Feed: userIndices :: UserEntity -> BoundingIndices
+ Web.Twitter.Types: Entities :: [UserEntity] -> [URLEntity] -> [MediaEntity] -> Entities
+ Web.Twitter.Types: Link :: Int -> Int -> String -> Link
+ Web.Twitter.Types: MediaEntity :: String -> BoundingIndices -> String -> MediaEntity
+ Web.Twitter.Types: SimpleTweet :: String -> String -> String -> SimpleTweet
+ Web.Twitter.Types: Tweet :: String -> String -> String -> Entities -> Tweet
+ Web.Twitter.Types: URLEntity :: String -> BoundingIndices -> String -> URLEntity
+ Web.Twitter.Types: UserEntity :: String -> BoundingIndices -> UserEntity
+ Web.Twitter.Types: body :: SimpleTweet -> String
+ Web.Twitter.Types: createdAt :: Tweet -> String
+ Web.Twitter.Types: created_at :: SimpleTweet -> String
+ Web.Twitter.Types: data Entities
+ Web.Twitter.Types: data Link
+ Web.Twitter.Types: data MediaEntity
+ Web.Twitter.Types: data SimpleTweet
+ Web.Twitter.Types: data Tweet
+ Web.Twitter.Types: data URLEntity
+ Web.Twitter.Types: data UserEntity
+ Web.Twitter.Types: displayMediaUrl :: MediaEntity -> String
+ Web.Twitter.Types: displayUrl :: URLEntity -> String
+ Web.Twitter.Types: endIndex :: Link -> Int
+ Web.Twitter.Types: entities :: Tweet -> Entities
+ Web.Twitter.Types: idStr :: Tweet -> String
+ Web.Twitter.Types: instance Constructor C1_0Entities
+ Web.Twitter.Types: instance Constructor C1_0MediaEntity
+ Web.Twitter.Types: instance Constructor C1_0SimpleTweet
+ Web.Twitter.Types: instance Constructor C1_0Tweet
+ Web.Twitter.Types: instance Constructor C1_0URLEntity
+ Web.Twitter.Types: instance Constructor C1_0UserEntity
+ Web.Twitter.Types: instance Datatype D1Entities
+ Web.Twitter.Types: instance Datatype D1MediaEntity
+ Web.Twitter.Types: instance Datatype D1SimpleTweet
+ Web.Twitter.Types: instance Datatype D1Tweet
+ Web.Twitter.Types: instance Datatype D1URLEntity
+ Web.Twitter.Types: instance Datatype D1UserEntity
+ Web.Twitter.Types: instance Eq Link
+ Web.Twitter.Types: instance FromJSON Entities
+ Web.Twitter.Types: instance FromJSON MediaEntity
+ Web.Twitter.Types: instance FromJSON Tweet
+ Web.Twitter.Types: instance FromJSON URLEntity
+ Web.Twitter.Types: instance FromJSON UserEntity
+ Web.Twitter.Types: instance Generic Entities
+ Web.Twitter.Types: instance Generic MediaEntity
+ Web.Twitter.Types: instance Generic SimpleTweet
+ Web.Twitter.Types: instance Generic Tweet
+ Web.Twitter.Types: instance Generic URLEntity
+ Web.Twitter.Types: instance Generic UserEntity
+ Web.Twitter.Types: instance Ord Link
+ Web.Twitter.Types: instance Selector S1_0_0Entities
+ Web.Twitter.Types: instance Selector S1_0_0MediaEntity
+ Web.Twitter.Types: instance Selector S1_0_0SimpleTweet
+ Web.Twitter.Types: instance Selector S1_0_0Tweet
+ Web.Twitter.Types: instance Selector S1_0_0URLEntity
+ Web.Twitter.Types: instance Selector S1_0_0UserEntity
+ Web.Twitter.Types: instance Selector S1_0_1Entities
+ Web.Twitter.Types: instance Selector S1_0_1MediaEntity
+ Web.Twitter.Types: instance Selector S1_0_1SimpleTweet
+ Web.Twitter.Types: instance Selector S1_0_1Tweet
+ Web.Twitter.Types: instance Selector S1_0_1URLEntity
+ Web.Twitter.Types: instance Selector S1_0_1UserEntity
+ Web.Twitter.Types: instance Selector S1_0_2Entities
+ Web.Twitter.Types: instance Selector S1_0_2MediaEntity
+ Web.Twitter.Types: instance Selector S1_0_2SimpleTweet
+ Web.Twitter.Types: instance Selector S1_0_2Tweet
+ Web.Twitter.Types: instance Selector S1_0_2URLEntity
+ Web.Twitter.Types: instance Selector S1_0_3Tweet
+ Web.Twitter.Types: instance Show Entities
+ Web.Twitter.Types: instance Show Link
+ Web.Twitter.Types: instance Show MediaEntity
+ Web.Twitter.Types: instance Show SimpleTweet
+ Web.Twitter.Types: instance Show Tweet
+ Web.Twitter.Types: instance Show URLEntity
+ Web.Twitter.Types: instance Show UserEntity
+ Web.Twitter.Types: instance ToJSON Entities
+ Web.Twitter.Types: instance ToJSON MediaEntity
+ Web.Twitter.Types: instance ToJSON SimpleTweet
+ Web.Twitter.Types: instance ToJSON Tweet
+ Web.Twitter.Types: instance ToJSON URLEntity
+ Web.Twitter.Types: instance ToJSON UserEntity
+ Web.Twitter.Types: mediaEntities :: Entities -> [MediaEntity]
+ Web.Twitter.Types: mediaIndices :: MediaEntity -> BoundingIndices
+ Web.Twitter.Types: mediaUrl :: MediaEntity -> String
+ Web.Twitter.Types: newHtml :: Link -> String
+ Web.Twitter.Types: screenName :: UserEntity -> String
+ Web.Twitter.Types: startIndex :: Link -> Int
+ Web.Twitter.Types: text :: Tweet -> String
+ Web.Twitter.Types: tweetId :: SimpleTweet -> String
+ Web.Twitter.Types: urlEntities :: Entities -> [URLEntity]
+ Web.Twitter.Types: urlIndices :: URLEntity -> BoundingIndices
+ Web.Twitter.Types: urlMessage :: URLEntity -> String
+ Web.Twitter.Types: userEntities :: Entities -> [UserEntity]
+ Web.Twitter.Types: userIndices :: UserEntity -> BoundingIndices

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014 Justin Leitgeb+Copyright (c) 2014 Stack Builders Inc.  MIT License 
src/Web/Twitter/Feed.hs view
@@ -1,127 +1,43 @@ {-# LANGUAGE OverloadedStrings, DeriveGeneric #-}  module Web.Twitter.Feed-  ( Tweet-  , Link (..)-  , URLEntity (..)-  , UserEntity (..)-  , MediaEntity (..)-  , timeline+  ( timeline   , addLink   , timelineUrl   , sortLinks-  )-where+  ) where +import qualified Data.ByteString.Lazy as BS+ import Network.HTTP.Conduit import Web.Authenticate.OAuth import Data.Aeson-import GHC.Generics (Generic)-import Control.Applicative-import Data.List (sortBy)-import Control.Monad (mzero)+import Data.List (elemIndices, sort) import Data.Char (toLower)--type BoundingIndices = [Int]--data SimpleTweet = SimpleTweet-    { body       :: String-    , tweetId    :: String-    , created_at :: String-    } deriving (Show, Generic)--data Tweet =  Tweet-  { text       :: String-  , createdAt  :: String-  , idStr      :: String-  , entities   :: Entities-  } deriving (Show, Generic)--data UserEntity = UserEntity-  { screenName  :: String-  , userIndices :: BoundingIndices-  } deriving (Show, Generic)--data URLEntity = URLEntity-  { urlMessage   :: String-  , urlIndices   :: BoundingIndices-  , displayUrl   :: String-  } deriving (Show, Generic)--data MediaEntity = MediaEntity-  { mediaUrl        :: String-  , mediaIndices    :: BoundingIndices-  , displayMediaUrl :: String-  } deriving (Show, Generic)--data Entities = Entities-  { userEntities  :: [UserEntity]-  , urlEntities   :: [URLEntity]-  , mediaEntities :: [MediaEntity]-  } deriving (Show, Generic)--data Link = Link-  { startIndex :: Int-  , endIndex   :: Int-  , newHtml    :: String-  } deriving (Show, Eq)--instance ToJSON SimpleTweet--instance ToJSON Tweet-instance FromJSON Tweet-  where parseJSON (Object v) = Tweet-                               <$> v .: "text"-                               <*> v .: "created_at"-                               <*> v .: "id_str"-                               <*> v .: "entities"-        parseJSON _          = mzero--instance ToJSON UserEntity-instance FromJSON UserEntity-  where parseJSON (Object v) = UserEntity-                               <$> v .: "screen_name"-                               <*> v .: "indices" .!= []-        parseJSON _          = mzero--instance ToJSON URLEntity-instance FromJSON URLEntity-  where parseJSON (Object v) = URLEntity-                               <$> v .: "url"-                               <*> v .: "indices" .!= []-                               <*> v .: "display_url"-        parseJSON _          = mzero--instance ToJSON MediaEntity-instance FromJSON MediaEntity-  where parseJSON (Object v) = MediaEntity-                               <$> v .: "url"-                               <*> v .: "indices" .!= []-                               <*> v .: "display_url"-        parseJSON _          = mzero--instance ToJSON Entities-instance FromJSON Entities-  where parseJSON (Object v) = Entities-                               <$> v .:? "user_mentions" .!= []-                               <*> v .:? "urls" .!= []-                               <*> v .:? "media" .!= []-        parseJSON _          = mzero+import Web.Twitter.Types  timeline :: OAuth -> Credential -> Int -> Bool -> String ->             IO (Either String [SimpleTweet]) timeline oauth credential count excludeReplies username = do-  req <- parseUrl $ timelineUrl username count excludeReplies-  res <- withManager $ \m -> do-           signedreq <- signOAuth oauth credential req-           httpLbs signedreq m+  req <- createRequest username count excludeReplies+  res <- getResponse oauth credential req+  return $+    case decodeTweets res of+      Left message -> Left message+      Right ts     -> Right $ map (simplifyTweet . linkifyTweet) ts -  let decoded = decode $ responseBody res+createRequest :: String -> Int -> Bool -> IO Request+createRequest username count excludeReplies = parseUrl $ timelineUrl username count excludeReplies -  case decoded of-    Nothing -> return $ Left "Unable to retrieve tweets!"-    Just ts -> return $ Right $ map (simplifyTweet . linkifyTweet) ts+getResponse :: OAuth -> Credential -> Request -> IO (Response BS.ByteString)+getResponse oauth credential req =+  withManager $ \m -> do+    signedreq <- signOAuth oauth credential req+    httpLbs signedreq m +decodeTweets :: Response BS.ByteString -> Either String [Tweet]+decodeTweets = eitherDecode . responseBody+ timelineUrl :: String -> Int -> Bool -> String timelineUrl user count excludeReplies =     "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=" ++@@ -138,21 +54,17 @@                            (entities tweet)  processText :: String -> [UserEntity] -> [URLEntity] -> [MediaEntity] -> String-processText message users urls medias = foldr addLink message-                                          (sortLinks urls users medias)+processText message users urls medias = foldr addLink message sortedLinks+  where sortedLinks = sortLinks urls users medias  sortLinks :: [URLEntity] -> [UserEntity] -> [MediaEntity] -> [Link]-sortLinks urls users medias = sortBy sortDesc (map makeURLLink   urls ++-                                               map makeUserLink  users ++-                                               map makeMediaLink medias)-  where sortDesc a b-          | startIndex a < startIndex b = LT-          | otherwise = GT+sortLinks urls users medias = sort (map makeURLLink   urls +++                                    map makeUserLink  users +++                                    map makeMediaLink medias)  makeURLLink :: URLEntity -> Link makeURLLink urlEntity = Link x y url-  where x       = head (urlIndices urlEntity)-        y       = urlIndices urlEntity !! 1+  where (x, y)  = urlIndices urlEntity         urlText = displayUrl urlEntity         href    = urlMessage urlEntity         url     = "<a target=\"_blank\" href=\"" ++ href ++ "\">"@@ -160,8 +72,7 @@  makeMediaLink :: MediaEntity -> Link makeMediaLink mediaEntity = Link x y url-  where x       = head (mediaIndices mediaEntity)-        y       = mediaIndices mediaEntity !! 1+  where (x, y)  = mediaIndices mediaEntity         urlText = displayMediaUrl mediaEntity         href    = mediaUrl mediaEntity         url     = "<a target=\"_blank\" href=\"" ++ href ++ "\">"@@ -169,8 +80,7 @@  makeUserLink :: UserEntity -> Link makeUserLink userEntity = Link x y mention-  where x        = head (userIndices userEntity)-        y        = userIndices userEntity !! 1+  where (x, y)   = userIndices userEntity         username = screenName userEntity         mention  = "<a target=\"_blank\" href=\"//twitter.com/" ++ username                    ++ "\">@" ++ username ++ "</a>"@@ -182,6 +92,10 @@                 , created_at = createdAt tweet }  addLink :: Link -> String -> String-addLink link tweet = before ++ newHtml link ++ after-  where before = fst (splitAt (startIndex link) tweet)-        after  = snd (splitAt (endIndex link) tweet)+addLink (Link 139 140 link) tweet = before ++ " " ++ link ++ after+  where before = fst (splitAt (lastBlank tweet) tweet)+        after  = snd (splitAt 140 tweet)+        lastBlank = last . elemIndices ' '+addLink (Link start end link) tweet = before ++ link ++ after+  where before = fst (splitAt start tweet)+        after  = snd (splitAt end tweet)
+ src/Web/Twitter/Types.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}++module Web.Twitter.Types+  ( Tweet(..)+  , SimpleTweet(..)+  , Link(..)+  , Entities(..)+  , URLEntity(..)+  , UserEntity(..)+  , MediaEntity(..)+  ) where++import Control.Applicative+import Data.Aeson+import Data.Aeson.Types+import Data.Ord (comparing)+import GHC.Generics (Generic)++type BoundingIndices = (Int, Int)++data SimpleTweet = SimpleTweet+  { body       :: String+  , tweetId    :: String+  , created_at :: String+  } deriving (Show, Generic)++data Tweet =  Tweet+  { text       :: String+  , createdAt  :: String+  , idStr      :: String+  , entities   :: Entities+  } deriving (Show, Generic)++data Entities = Entities+  { userEntities  :: [UserEntity]+  , urlEntities   :: [URLEntity]+  , mediaEntities :: [MediaEntity]+  } deriving (Show, Generic)++data UserEntity = UserEntity+  { screenName  :: String+  , userIndices :: BoundingIndices+  } deriving (Show, Generic)++data URLEntity = URLEntity+  { urlMessage   :: String+  , urlIndices   :: BoundingIndices+  , displayUrl   :: String+  } deriving (Show, Generic)++data MediaEntity = MediaEntity+  { mediaUrl        :: String+  , mediaIndices    :: BoundingIndices+  , displayMediaUrl :: String+  } deriving (Show, Generic)++data Link = Link+  { startIndex :: Int+  , endIndex   :: Int+  , newHtml    :: String+  } deriving (Show, Eq)++instance ToJSON SimpleTweet++instance ToJSON Tweet+instance FromJSON Tweet where+  parseJSON = withObject "Tweet" parseTweet++instance ToJSON Entities+instance FromJSON Entities where+  parseJSON = withObject "Entities" parseEntities++instance ToJSON UserEntity+instance FromJSON UserEntity where+  parseJSON = withObject "UserEntity" parseUserEntity++instance ToJSON URLEntity+instance FromJSON URLEntity where+  parseJSON = withObject "URLEntity" parseURLEntity++instance ToJSON MediaEntity+instance FromJSON MediaEntity where+  parseJSON  = withObject "MediaEntity" parseMediaEntity++instance Ord Link where+  compare = comparing startIndex++parseTweet :: Object -> Parser Tweet+parseTweet v = Tweet <$> v .: "text"+                     <*> v .: "created_at"+                     <*> v .: "id_str"+                     <*> v .: "entities"++parseUserEntity :: Object -> Parser UserEntity+parseUserEntity v = UserEntity <$> v .: "screen_name"+                               <*> v .: "indices"++parseURLEntity :: Object -> Parser URLEntity+parseURLEntity v = URLEntity <$> v .: "url"+                             <*> v .: "indices"+                             <*> v .: "display_url"++parseMediaEntity :: Object -> Parser MediaEntity+parseMediaEntity v = MediaEntity <$> v .: "url"+                                 <*> v .: "indices"+                                 <*> v .: "display_url"++parseEntities :: Object -> Parser Entities+parseEntities v = Entities <$> v .:? "user_mentions" .!= []+                           <*> v .:? "urls" .!= []+                           <*> v .:? "media" .!= []
twitter-feed.cabal view
@@ -1,5 +1,5 @@ name:                twitter-feed-version:             0.1.1.1+version:             0.1.1.2 synopsis:            Client for fetching Twitter timeline via Oauth description:         Fetches a user timeline from Twitter, and optionally linkifies the results using the Twitter entity API. homepage:            https://github.com/stackbuilders/twitter-feed@@ -18,28 +18,30 @@  library   exposed-modules:     Web.Twitter.Feed+                       Web.Twitter.Types   ghc-options:         -Wall-  build-depends:         base >=4.6 && <4.8-                       , authenticate-oauth >=1.4-                       , aeson >=0.7 && <0.8-                       , http-conduit >=1.4 && <2.0 +  build-depends:+    base               >= 4.6   && < 4.8,+    aeson              >= 0.8   && < 0.9,+    authenticate-oauth >= 1.5   && < 1.6,+    http-conduit       >= 2.1.4 && < 2.1.5,+    bytestring         >= 0.10  && < 0.11+   hs-source-dirs:      src   default-language:    Haskell2010  test-suite twitter-library   type: exitcode-stdio-1.0-  hs-source-dirs: test, src+  hs-source-dirs: test   main-is: Suite.hs   build-depends:-      base >=4.6 && <4.8-      , test-framework >=0.8 && <0.9-      , HUnit-      , test-framework-hunit-      , containers--      , authenticate-oauth >=1.4-      , aeson >=0.7 && <0.8-      , http-conduit >=1.4 && <2.0+    base,+    twitter-feed,+    containers           >= 0.5 && < 0.6,+    HUnit                >= 1.2 && < 1.3,+    test-framework       >= 0.8 && < 0.9,+    test-framework-hunit >= 0.3 && < 0.4    default-language:    Haskell2010+  ghc-options:         -Wall