Good news for Twitter and no so good for developers:
Today(2013-06-11), we(Twitter) are retiring API v1 and fully transitioning to API v1.1.
What does it all mean? This means that all old services are no longer available. Twitter switched to new ones with mandatory OAuth authentication. From now, to work with twitter services we must register new apps and use OAuth.
Also, it means that:
As I know, there are two alternatives available instead of Twitterizer:
- Tweetsharp (TweetSharp is a fast, clean wrapper around the Twitter API.)
- LINQ to Twitter (An open source 3rd party LINQ Provider for the Twitter micro-blogging service.)
I have chosen Tweetsharp because its API similar to Twitterizer. This is a new F# Weekly under the hood script:
#r "Newtonsoft.Json.dll"
#r "Hammock.ClientProfile.dll"
#r "TweetSharp.dll"
open TweetSharp
open System
open System.Net
open System.Text.RegularExpressions
let service = new TwitterService(_consumerKey, _consumerSecret)
service.AuthenticateWith(_accessToken, _accessTokenSecret)
let getTweets query =
let rec collect maxId =
let options = SearchOptions(Q = query, Count =Nullable(100), MaxId = Nullable(maxId),
Resulttype = Nullable(TwitterSearchResultType.Recent))
printfn "Loading %s under id %d" query maxId
let results = service.Search(options).Statuses |> Seq.toList
printfn "\t Loaded %d tweets" results.Length
if (results.Length = 0)
then List.empty
else
let lastTweet = results |> List.rev |> List.head
if (lastTweet.Id < maxId) then results |> List.append (collect (lastTweet.Id))
else results
collect (Int64.MaxValue) |> List.rev
let urlRegexp = Regex("http://([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?", RegexOptions.IgnoreCase);
let filterUniqLinks (tweets: TwitterStatus list) =
let hash = new System.Collections.Generic.HashSet();
tweets |> List.fold
(fun acc t ->
let mathces = urlRegexp.Matches(t.Text)
if (mathces.Count = 0) then acc
else let urls =
[0 .. (mathces.Count-1)]
|> List.map (fun i -> mathces.[i].Value)
|> List.filter (fun url -> not(hash.Contains(url)))
if (List.isEmpty urls) then acc
else urls |> List.iter(fun url -> hash.Add(url) |> ignore)
t :: acc)
[]Â |>Â List.rev
let tweets =
["#fsharp";"#fsharpx";"@dsyme";"#websharper";"@c4fsharp"]
|> List.map getTweets
|>Â List.concat
|> List.sortBy (fun t -> t.CreatedDate)
|>Â filterUniqLinks
let printTweetsInHtml filename (tweets: TwitterStatus list) =
let formatTweet (text:string) =
let matches = urlRegexp.Matches(text)
seq {0 .. (matches.Count-1)}
|> Seq.fold (
fun (t:string) i ->
let url = matches.[i].Value
t.Replace(url, (sprintf "<a href="\"%s\"" target="\"_blank\"">%s</a>" url url)))
text
let rows =
tweets
|> List.mapi (fun i t ->
let id = (tweets.Length - i)
let text = formatTweet(t.Text)
sprintf "</pre>
<table id="\"%d\"">
<tbody>
<tr>
<td rowspan="\"2\"" width="\"30\"">%d</td>
<td rowspan="\"2\"" width="\"80\""><a href="\"javascript:remove('%d')\"">Remove</a></td>
<td rowspan="\"2\""><a href="\"https://twitter.com/%s\"" target="\"_blank\""><img alt="" src="\"%s\"/" /></a></td>
<td><b>%s</b></td>
</tr>
<tr>
<td>Created : %s</td>
</tr>
</tbody>
</table>
<pre>
"
id id id t.Author.ScreenName t.Author.ProfileImageUrl text (t.CreatedDate.ToString()))
|> List.fold (fun s r -> s+" "+r) ""
let html = sprintf "<script type="text/javascript">// <![CDATA[
function remove(id){return (elem=document.getElementById(id)).parentNode.removeChild(elem);}
// ]]></script>%s"Â rows
System.IO.File.WriteAllText(filename, html)
printTweetsInHtml "d:\\tweets.html" tweets