pbcopy and pbpaste

May 5, 2009

Here’s a quick tip about two handy command line utilities for Mac OS X: pbcopy and pbpaste.

pbcopy is used to capture output from any command line program and place it into the pasteboard. An example:

$ cat hello.txt 
hello world!
$ cat hello.txt | pbcopy 

We can now paste the output from cat in the regular cmd-v fashion mostly anywhere.

pbpaste, on the other hand, outputs the contents of the pasteboard. An example:

$ pbpaste 
hello world!

In this way, pbcopy and pbpaste can be used to move data between command line programs and GUI applications.

pbcopy and pbpaste have a few tricks up their proverbial sleeves. You can read all about them in their man page, which is available online, or simply by entering man pbcopy on the command line.

Update: Boy genius Mattias Arrelid pointed out that to get pbcopy and pbpaste to play nicely with UTF-8, you need to set __CF_USER_TEXT_ENCODING correctly. Read the full scoop over at Mac OS X Hints.

GreenStripes: Ruby bindings for libspotify

April 15, 2009

About a week ago, Spotify released libspotify, a C API for writing applications that utilize their service.

Now, while I’m certainly not averse to C, I think that a more human-friendly language is a better fit for many tasks. So I whipped up a set of Ruby bindings that lets you write programs like this one:

session = GreenStripes::Session.new(APPLICATION_KEY, 'GreenStripes', 'tmp', 'tmp')
session.login(USERNAME, PASSWORD)
session.process_events until session.connection_state == GreenStripes::ConnectionState::LOGGED_IN

search = GreenStripes::Search.new(session, 'yakety sax', 0, 100)
session.process_events until search.loaded?
puts "found #{search.num_tracks} tracks"
if search.num_tracks > 0
  track = search.track(0)
  session.process_events until track.loaded? and track.artist(0).loaded?
  puts "the first one is #{track.name} by #{track.artist(0).name}"
end

session.logout
session.process_events until session.connection_state == GreenStripes::ConnectionState::LOGGED_OUT

GreenStripes is very much in a beta stage, lacks features and has bugs, but it’s gotten to a point where you can actually play around with it and build stuff.

Interested? GreenStripes is available in source or gem form from GitHub, where you can also read installation instructions and sign up to be notified of updates:

Cocoa sans Xcode and Interface Builder

March 3, 2009

Something that has always bugged me about Cocoa development is that it’s so tightly coupled with Xcode and Interface Builder. Virtually every single guide on the topic will use those two apps, and if you dare ask how one would go about without them, the answer will almost certainly be an exasperated “why would anyone want to do that?!”

And that’s something that bugs me even more. Good programmers love taking things apart to figure out what makes them tick, and I strive to be one. It’s not that I hate Xcode and Interface Builder, but rather that I like to understand what’s going on.

Turns out it’s not tricky at all.

Before we get started, let’s define what developing a Cocoa app without Xcode or Interface Builder actually means. No Xcode means we can use any editor and any build system we want. No Interface Builder means that we’ll be creating our views programmatically. Of course, these are three completely separate topics, and it’s quite possible to do just one or two of them. But let’s go the whole hog.

Objective-C, being a strict superset of C, has to obey every rule that C obeys. Hence, a truly minimal Objective-C program would be something along the lines of:

int main(int argc, char *argv[])
{
  return 0;
}

Of course, this doesn’t do anything interesting, and crucially, it’s not a Cocoa app.

Now, what makes a Cocoa app? Well, if you create an empty Cocoa app project in Xcode, main will contain a call to NSApplicationMain and nothing else. So, I suppose we could just stick that in our main, call it done and go out to lunch. But that would be cheating. Besides, what does NSApplicationMain do anyway?

It actually has an entry in the API reference, but that will not tell you much about what it does. That information is tucked away, for some reason, in the docs for the NSApplication class.

With this knowledge, and considering we’re not going to load any nibs, we can change the code for our minimal Cocoa app into something like this:

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
  [NSApplication sharedApplication];
  [NSApp run];
  return 0;
}

Save the above in a file called kakao.m and compile it with gcc like so:

$ gcc -framework Cocoa -o Kakao kakao.m

You can even run the app if you feel like it:

$ ./Kakao

Although, as you might have noticed, that won’t do much except hang until you kill it. So let’s add something more interesting, like a window.

After a quick look in the docs for the NSWindow class, we change the code for our app into this:

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
  [NSApplication sharedApplication];
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSUInteger style = NSTitledWindowMask
                   | NSClosableWindowMask
                   | NSMiniaturizableWindowMask
                   | NSResizableWindowMask;
  NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
                                                 styleMask:style
                                                   backing:NSBackingStoreBuffered
                                                     defer:NO];
  [window makeKeyAndOrderFront:nil];
  [pool drain];
  [NSApp run];
  return 0;
}

Note that we create an NSAutoreleasePool before we create the window, and drain it afterwards. This is something Cocoa will usually take care of, but since we are not yet in an event loop, we have to do it manually.

Compile and run the program like before, and lo, a window appears!

However, this is clearly not a trüe Cocoa app yet. It doesn’t get its own icon in the dock or in the cmd-tab view, and if you try launching it from the Finder, things just get plain silly.

Of course, this is something we can fix. Applications, as well as many other kinds of bundles, are nothing but directories with special names in Mac OS X.

If you’ve ever peeked inside a .app bundle (right-click, Show Package Contents), you know it contains a directory called Contents, which contains among other things a directory called MacOS, which contains the actual executable for the app.

So, without further ado:

$ mkdir -p Kakao.app/Contents/MacOS
$ mv Kakao Kakao.app/Contents/MacOS/

And presto! You have a bonafide Cocoa app, complete with icon and menu bar (which is empty, but still) that can be launched from the Finder.

Now, if you have been digging around .app bundles before, you know that there are two more files that should go in there: Info.plist and PkgInfo. And yes, if you’re developing an actual app you plan on having actual users for, you should create those files as well. But for our purposes, we’ll do fine without them as long as the executable has the same name as the bundle, minus the “.app” suffix.

Oh, and in case you’re wondering, “kakao” is Swedish for “cocoa”.

Recommended reading

This is based on a presentation I gave at CocoaHeads Stockholm. If you’re into Cocoa, and live in or near Stockholm, you should drop by and say hi.

Getting started with Spotify

I’ve introduced a lot of people to Spotify lately, and I tend to say pretty much the same things every time. So, in the interest of having something you can point a web browser at, I decided to sum it up in a blog post.

I’m not going to go over the basics, because I think the Spotify application does a pretty good job at explaining itself. If you’re new to Spotify, just play with it for an hour or two, and you should get the hang of it.

Done? Great!

Sharing playlists

Like most other things in Spotify, playlists have URIs. What this means, is that you can right-click on any of your playlists and select “Copy HTTP Link” or “Copy Spotify URI”, and you’ll get something you can paste on your blog, in an e-mail or chat message, or pretty much anywhere else. It works just like a link to a website, except it points to a playlist in Spotify.

Anyone who comes across one of these URIs can either click on it, or paste it into the search box in the Spotify application. Now, they too will be able to listen to your playlist, but they won’t be able to make any changes to it.

If you want that to happen, right-click on the playlist and select “Collaborative Playlist”. This is great for making playlists with your friends! Just remember that anyone who knows the URI of your playlist will be able to add or remove tracks to it now.

The Inbox

There is a special kind of collaborative playlist, which as far as I know was first seen here, and that is The Inbox.

From a technical point of view, there is nothing special about The Inbox. It’s simply a playlist which is called “Inbox” and marked as collaborative.

The idea behind it, however, is that you give the URI for it to all your friends (and, if you’re adventurous, complete strangers), and ask them to put music they think you might like in it. Sure, you might get the occasional spam track, but usually it works great. You should make one for yourself!

Here is my Spotify Inbox!

Last.fm

Last.fm is not directly related to Spotify, and is quite a bit older, but is awesome nonetheless.

Basically, it’s a website that keeps track of all the music you listen to, and creates a profile for you based on that. And this is where the magic starts. Not only can you get nice charts of your listening statistics, but also recommendations for music you might like and reminders for concerts and so much more. It can be a little iffy at first, but once you’ve scrobbled enough tracks, it really gets spot on.

And you can make it be the chocolate to Spotify’s peanut butter.

First off, you need to sign up for a Last.fm account. Once you’ve done that, go to the Preferences view in the Spotify application, and look for the Last.fm section. Here, make sure “Enable scrobbling to Last.fm” is checked, and put your Last.fm username and password in their respective fields.

And then just listen to music.

Here is my Last.fm Profile!