I have wrote an application which asks for the user id, and returns a link to the first available chat message:
Output
Enter user id:
322395
Fetching data...
http://chat.stackoverflow.com/transcript/17?m=231895#231895
Source code
module Main where
import Network.HTTP (simpleHTTP, getRequest, getResponseBody)
import Text.HTML.TagSoup
import Data.List (isInfixOf, isPrefixOf)
type Link = String
type UserID = String
hostname = "http://chat.stackoverflow.com"
getDivText :: String -> [Tag String] -> String
getDivText m = innerText
. takeWhile (~/= "</div>")
. dropWhile (~/= m)
getURLContent :: Link -> IO String
getURLContent lnk = simpleHTTP (getRequest lnk) >>= getResponseBody
getMessages :: UserID -> IO Integer
getMessages uid = do
contents <- getURLContent $ concat [ hostname
, "/users/"
, uid ]
let count = getDivText "<div class=user-message-count-xxl>"
$ (parseTags contents)
return (read count)
getFirstMessagePage :: UserID -> IO String
getFirstMessagePage uid = searchLast "" . ceiling . (/100)
=<< (fmap fromIntegral $ getMessages uid) where
searchLast body pg = do
let lnk = concat [ hostname
, "/users/"
, uid
, "/?tab=recent&pagesize=100&page="
, show pg ]
body' <- getURLContent lnk
if "monologue" `isInfixOf` body'
then return body'
else searchLast body (pg - 1)
getFirstMessage :: UserID -> IO Link
getFirstMessage ui = do
page <- getFirstMessagePage ui
let tags = filter step $ parseTags page
lnk = fromAttrib "href" $ last tags
return $ concat [ hostname, lnk ]
where step t = isTagOpen t
&& "/transcript" `isPrefixOf` fromAttrib "href" t
main :: IO ()
main = do
putStrLn "Enter user id:"
uid <- getLine
putStrLn "Fetching data..."
lnk <- getFirstMessage uid
putStrLn lnk
I tried to keep the HTTP requests to a minimum.
If the user has removed messages, than there will be a difference between the pages available and the number of messages in the profile.
To solve this, the app recursively lowers the page number till it finds the last message.