Bitbucket is a code hosting site with unlimited public and private repositories. We're also free for small teams!

Close

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 Portable Class Library supporting .NET 4 (and up) and the Windows Store.

Example Usage

Since all calls to Twitter should be authenticated, you'll need to start with the TwitterAuthenticator class. This class is essentially a factory for TwitterClient instances, from which all Twitter API calls can be made.

To create a new instance of TwitterAuthenticator, you'll need an implementation of the IPlatformAdaptor interface, as well as a Consumer Key and Secret from Twitter:

var auth = new TwitterAuthenticator(new MyPlatformAdaptor(), myConsumerKey, myConsumerSecret);

Implementing IPlatformAdaptor

Because Budgie is based on the Portable Code Library, it has no in-built way to generate a SHA1 hash for Twitter. It relies on you providing that code by implementing the IPlatformAdaptor interface.

Here are some example implementations:

WPF/Windows Forms/Console

// using System.Security.Cryptography;

internal class DesktopPlatformAdaptor : IPlatformAdaptor
{
    public string ComputeSha1Hash(string key, string buffer)
    {
        using (var hasher = new HMACSHA1(UTF8Encoding.UTF8.GetBytes(key)))
        {
            return Convert.ToBase64String(hasher.ComputeHash(UTF8Encoding.UTF8.GetBytes(buffer)));
        }
    }
}

Windows Store

// using Windows.Security.Cryptography;
// using Windows.Security.Cryptography.Core;

internal class StorePlatformAdaptor : IPlatformAdaptor
{
    public string ComputeSha1Hash(string key, string buffer)
    {
        var algorithm = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha1);
        var keymaterial = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
        var hmacKey = algorithm.CreateKey(keymaterial);

        return CryptographicBuffer.EncodeToBase64String(CryptographicEngine.Sign(
            hmacKey,
            CryptographicBuffer.ConvertStringToBinary(buffer, BinaryStringEncoding.Utf8)));
    }
}

TwitterClient

Now that you have an instance of TwitterAuthenticator, you're ready to authenticate and spin up a new TwitterClient instance:

The first way to do that is by requesting a key from Twitter. For example, using the PIN workflow:

// Step 1 - acquire a "request token" from Twitter.
var requestToken = await auth.GetRequestTokenAsync();

if (requestToken == null) return null; // 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".
Console.Write("PIN: ");
var pin = Console.ReadLine();

var clientResponse = await auth.AuthenticateAsync(requestToken, pin);
if (clientResponse.StatusCode != HttpStatusCode.OK)
{
    // handle the error
    return;
}
var client = clientResponse.Content;

... or if you're writing a Windows Store app you can use the WebAuthenticationBroker class to retrieve the pin:

public async Task<String> GetVerifier(TwitterRequestToken token)
{
    var response = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, token.AuthorizationUri);
    if (response.ResponseStatus == WebAuthenticationStatus.Success)
    {
        Uri u;
        if (!Uri.TryCreate(response.ResponseData, UriKind.Absolute, out u)) return null;

        var dec = new WwwFormUrlDecoder(u.Query);

        var result = dec.FirstOrDefault(v => v.Name == "oauth_verifier");
        if (result == null) return null;

        return result.Value;
    }
    return null;
}

The second way is with a pre-existing access token and access token secret:

var clientResponse = await auth.AuthenticateAsync(_accessSecret, _accessSecret);
if (clientResponse.StatusCode != HttpStatusCode.OK)
{
    // handle the error
    return;
}
var client = clientResponse.Content;

Both techniques wlil populate the User property of TwitterClient with at least the Id and Name of the authenticated user. If you need more detail in the User property, you can call TwitterClient.VerifyCredentialsAsync.

Searching Twitter

The easiest place to start is a simple search:

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

// check if the search succeeded
if (response.StatusCode == HttpStatusCode.OK)
{
    foreach (var tweet in response.Content)
    {
        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.

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 = await client.GetHomeTimelineAsync();

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

Count, Since, Max and DefaultPageSize

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

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

That'll get a maximum of 50 tweets, and only those tweets that have been posted after the tweet with the "since" Id but not after the tweet with the "max" 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, max: 237736023684165633);

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 variables containing the responses of the API calls:
var followersResponse = followersTask.Result;
var friendResponse = 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 response = await client.LookupUsersAsync(followerIds);

if (response.StatusCode == HttpStatusCode.OK)
{
    foreach (var user in response.Content)
    {
        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 response = await client.PostAsync("Hello, world!");

if (response.StatusCode == HttpStatusCode.OK)
{
    var tweet = response.Content;

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

You might want to reply to an existing tweet:

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

if (response.StatusCode == HttpStatusCode.OK)
{
    var tweet = response.Content;

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

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

var response = await client.RetweetAsync(191164523506438144);

if (response.StatusCode == HttpStatusCode.OK)
{
    var tweet = response.Content;

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

Recent activity

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.