Introducing Budgie

You're probably aware that I wrote my own Twitter client application, called Halfwit. It has served me well and is still my favourite client to this day.

Budgie Logo

However, Halfwit is not without its problems. It relies on TweetSharp, which in turn relies on Hammock, and neither of those two projects are actively maintained anymore. In recent versions of Halfwit I've had the occasional crash or failed assertion, which is annoying at the best of times and super annoying if it happens in your own application because of code you don't own.

For kicks, I decided to see how hard it would be to write a Twitter client library for Halfwit to use. As it turns out, it wasn't that difficult. Sure, the OAuth side of things was a lot of trial and error, and I'm sure I've missed something along the way, but in under a week I have produced:

Budgie

You can check out the code over on the project page. I'll reproduce the readme in its current form here, to give you an idea of how you can use Budgie in your own applications.

I mean to keep Budgie alive as a project, so if you want to make suggestions or contribute code via a pull request, feel free.

As with all my projects, Budgie is released under the Microsoft Public License.

And yes, Budgie is on NuGet (currently in prerelease form).

PM> Install-Package Budgie -pre

What is Budgie?

Budgie is a very simple library to access Twitter via its HTTP API.

All methods in the class library are asynchronous, returning Task<T>, so you can await them if you're using C# 5.

Budgie is a .NET 4 Client Profile library for now.

Example Usage

Budgie is driven primarily from the TwitterClient class. To create a new instance of TwitterClient, you'll need a Consumer Key and Secret from Twitter:

var client = new TwitterClient(myConsumerKey, myConsumerSecret);

Searching Twitter

The easiest place to start is a simple search, which requires no authentication:

// "searcher" is a Task<ITwitterResponse<IEnumerable<TwitterStatus>>>! Phew! Thank goodness for "var"!
var searcher = client.SearchAsync("budgie");

// block and wait for the task to finish
var response = searcher.Result;

// check if the search succeeded
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    foreach (var tweet in response.Result)
    {
        Console.WriteLine(tweet.User.ScreenName + "\t" + tweet.Text);
    }
}

That's it! You now have a Console app that searches Twitter for the word "budgie" and displays the results.

Signing In

Now you might want to authenticate and do something with your own Twitter account. Right now, Budgie only supports PIN-based OAuth, which means there are two steps to authenticating:

// Step 1 - acquire a "request token" from Twitter.
var requestTask = client.GetRequestTokenAsync();
var requestToken = requestTask.Result;

if (requestToken == null) return; // something went wrong.

// Step 2 - open a browser so the user can sign into Twitter and obtain a PIN.
Process.Start(requestToken.AuthorizationUri.ToString());

// Step 3 - ask the user for the PIN and pass it back to Twitter for an "access token".
var pin = Console.ReadLine();

var accessTask = client.AuthenticateAsync(requestToken, pin);
var accessToken = accessTask.Result;

You'll want to save the Token and Secret properties of accessToken away for next time you run your program so you don't have to ask for a PIN each time.

If you already have an access token and just want to give them to the TwitterClient instance, you can use the Authenticate method:

client.Authenticate("my-access-token", "my-access-token-secret");

// You can optionally ask Twitter for your user details, if you didn't save them.
var verifyTask = client.VerifyCredentials();

var myDetails = verifyTask.Result;

Getting the Home Timeline

An obvious requirement once you're signed in is to pull down the list of tweets on your home timeline. That's reasonably straight forward:

// Get a task which is downloading the home timeline.
var timelineTask = client.GetHomeTimelineAsync();

// Block and wait for it to finish (or await it in C# 5).
var response = timelineTask.Result;

// check if the search succeeded and display the tweets.
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    foreach (var tweet in response.Result)
    {
        Console.WriteLine(tweet.User.ScreenName + "\t" + tweet.Text);
    }
}

Count, Since and DefaultPageSize

All of the "timeline" methods have a couple of optional parameters:

client.GetHomeTimelineAsync(count: 50, since: 191164523506438144);

That'll get a maximum of 50 tweets, and only those tweets that have been posted after the tweet with that Id.

To make things easier, TwitterClient has a property called DefaultPageSize which you can set once rather than specifying count on every timeline call:

client.DefaultPageSize = 50;

// Now this is effectively the same as the call above:
client.GetHomeTimelineAsync(since: 191164523506438144);

Getting Friends and Followers

Twitter provides a way to retrieve the Ids of users you follow and users who follow you, but it does so in a "paged" fashion using what it calls "cursors". Budgie wraps that functionality up for you into a couple of simple asynchronous methods:

var followersTask = client.GetFollowerIdsAsync();
var friendsTask = client.GetFriendIdsAsync();

// Just for kicks, let's wait for both of those to finish in one line.
Task.WaitAll(followersTask, friendsTask);

// A couple of long[] variables containing our follower and friend Ids:
var followerIds = followersTask.Result;
var friendIds = friendsTask.Result;

Having the Ids of your friends and followers might be enough, but if it's not, Budgie gives you a method you can call to look up the details of those users in one call:

var lookupTask = client.LookupUsersAsync(followerIds);

var response = lookupTask.Result;

if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    foreach (var user in response.Result)
    {
        Console.WriteLine(user.Name);
    }
}

Be aware that Twitter aggressively limits calls to its "lookup users" method (independently of normal rate limits), so you won't want to call it often.

Posting a Tweet

Tweeting is predictably easy:

var tweetTask = client.PostAsync("Hello, world!");

var response = tweetTask.Result;

if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    var tweet = response.Result;

    // do stuff with the tweet you just posted.
}

You might want to reply to an existing tweet:

var replyTask = client.ReplyToAsync(191164523506438144, "That's awesome!");

var response = replyTask.Result;

if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    var tweet = response.Result;

    // do stuff with the reply you just posted.
}

Or perhaps you're a retweeting kinda guy like me:

var retweetTask = client.RetweetAsync(191164523506438144);

var response = retweetTask.Result;

if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
    var tweet = response.Result;

    // do stuff with the retweet you just posted.
}
twitter budgie .net
Posted by: Matt Hamilton
Last revised: 20 Feb, 2017 08:20 PM History