Tweet your Favorite Tracks, automagically

Earlier this week, I wrote a tiny little app, which tweets my favorite music. You can read more about the concept here. This is a technical post to explain how you can leverage this app for your own enjoyment.

First, you will need to download the code. Then you will need to obtain the following items:

Once you have obtained these items, you will need a computer that is always plugged into the internet or a web server where you can run cron jobs. I am running the script on this server.

Open the track_lover.php file, which you should have gotten from here, and update the following lines, replacing ‘xxx’ with real values:

    // TWITTER
    define("TWITTER_USERNAME", "xxx");
    define("TWITTER_PASSWORD", "xxx");
 
    // last.fm
    define("LASTFM_USER", "xxx");    
    define("LASTFM_API", "xxx");    
 
    // bit.ly via j.mp
    define("BITLY_USER", "xxx");
    define("BITLY_API", "xxx");

Once you save the file, you will be all set to turn on The cron job entry may look as follows

# run every two minutes
*/2 * * * * /usr/local/bin/php /path/to/the/script/trackLover/track_lover.php > /dev/null 2>&1

That’s it, you should be up and running tweeting your favorite tracks. Enjoy!

Intersection of Geek and Music

I absolutely love the intersection of geek and music.

Recently, I wrote a tiny little app that does for me something that is irritating to do manually, sharing my favorite music at this moment. Essentially, it tweets to the world the track I have listened to a track at least 3 times in the last hour.

I am leveraging several APIs to create this app. The always wonderful last.fm API, as well as the bit.ly (awesome) API and the Twitter API. The real trick is taking advantage of the upcoming version 3 API from bit.ly. In the latest bit.ly API, bit.ly returns a boolean whether the recently shortened track is a new ‘hash’ or not. Meaning, if it has not been shortened by me before, it returns true. Instead of needing to attach a database to this app, I am just checking this boolean. Normally, I would consider this abusive, however, with all the preconditions of my script, I rarely even ask bit.ly if this shorten is ‘new’.

If it wasn’t for the descriptive potential of bit.ly, I would need to establish a flat file, or database to handle this logic check. Eventually, if they alter the API, this will become a nessecity, but for the time being I am leveraging this functionality.

Shortly, I will attempt to release a new wordpress plugin or cron that leverages all three APIs, but for the time being the code is a bit messy. If you are interested, please reach out in the comments below with an email address and I am happy to share the code. Otherwise, enjoy my twitter stream and all the music I am addicted too.

All the Cool Kids use bitly.tv

It was a huge week at bit.ly. At the beginning of the week Google and Facebook launched URL shorteners at the same time we were launching bit.ly pro. As if that wasn’t exciting enough, I also launched my first product experience for bit.ly known as bitly.tv.

The response to bitly.tv has been very exciting and positive. It launched as part of labs.bit.ly, where I hope to be involved in many future experiments with bit.ly data. The bitly.tv User Interface is very fun and extremely different from anything I have built in the last few years, I had the opportunity to really flex my AJAX application skills.

The app uses quite a few of my favorite libraries and JavaScript projects, including jQuery, SWF Address, SWF Object and a few plugins I wrote specifically for bitly.tv. I also got my first taste of writing Python for a production level project as well as using the Tornado framework. In addition, I got the opportunity to finally use the new Google Closure Compiler. All in all, I think all of these technologies are excellent and make writing apps fun.

I also learned some extremely valuable lessons about the jQuery animation code and DOM interface. During the prototyping phase of bitly.tv, I noticed that jQuery was consuming a considerable about of memory because my architecture was not caching references to DOM elements. Essentially, I was crawling the DOM looking for the correct rows and columns to transition on every mouse over and mouse out. This was very slow in FireFox, but not very noticeable from a user experience point of view in Chrome and Safari. To help alleviate this issue, I began storing the references to each row and column in an array then did a simple jQuery.inArray(); check to skip the DOM API completely. This reduced the number of internal jQuery calls from around 32,000 to around 4,000.

In addition to the above, I also helped speed up the jQuery animation code by skipping the standard jQuery().animate(); and going directly to jQuery.fx();, which also had a considerable impact on the number of internal calls jQuery needed to make. I don’t recommend doing this, however, as it could cause compatibly issues with future releases of jQuery.

Take a few minutes and check out bitly.tv. We are already planning bitly.tv 2.0, and I would love to include your feedback.

Newish Music, Portugal The Man

My friend Dan has been raving about this band, Portugal, The Man for a while now. He said their latest CD, The Satanic Satanist, could be his album of the year. So, as usual I didnt bother listening to it, because he spends a great deal of time trying to convince me of things. I finally put it on my iPod, and I have to say its very good. I sort of hate it when he is right, but I do love good music.

bit.ly Bookmarklet API Hack

I recently started using bit.ly for storing my bookmarks instead of delicious. While bit.ly isn’t entirely ready to be a bookmarking service for everyone, it does have some cool features, such as a public history, and saves me a hop for sites that I want to bookmark plus need a short URL in order to tweet.

In order to facilitate my new, higher volume, usage of bit.ly, I wrote a little bookmarklet hack that throws the current page into bit.ly and alerts back the shortened URL in case I need it.

I put together this form that will let anyone take advantage of the hack. You’ll just need to input your user name and bit.ly API key. Then you never have to worry about logging in again. Enjoy.

My Next Big Thing

Just a quick note to say I started last week at bit.ly as the Lead Front-end Engineer. It’s my second attempt at a startup and so far it’s amazing. I’m very excited about learning Python and having a chance to own the products I work on. Unfortunately, new jobs usually mean significantly fewer blog updates for the first few months, but I hope to put together more tutorials like my extremely popular ffmpeg install post by the first of the year.

Adding Docs for iPython on Mac OSX Leopard

I have been playing with iPython as part of my exploration into Python. A friend tipped me off that iPython is a little more sophisticated than the standard Python interactive prompt.

One of the features of iPython is an interactive help guide for the language. It’s pretty sweet, however, on the standard Python Mac build, it doesn’t include all the documentation. This means some of the help guide is also missing parts. In order to add the HTML docs for Python 2.5, I ended up needing to compile the docs. This required me to install a few items, which are listed below.

Essentially, the docs need to be compiled as HTML from LaTeX. I had to install LaTeX for Mac, LaTeX2HTML and Darwin Ports (aka Mac Ports). This wasn’t too difficult, but I had a few missteps along the way. The directions are mostly for my own benefit, but if you find them useful or need a correction please let me know.

Goal: Create a link to the Python Docs for use with iPython.

  • Install Darwin Ports
  • Install LaTeX for Mac
  • Intall LaTeX2HTML
  • Download Python 2.5
  • Copy compiled HTML docs to Standard Location
  • Create env variable PYTHONDOCS for iPython help reference

Notes: I am running Mac OSX 10.5.4 with Python 2.5.1 and iPython 0.10. The $ is simply my prompt in Terminal.

Installing Darwin ports is very fast and easy, just visit http://darwinports.com/ and grab the latest version. Once you get it downloaded, it’s only 1.4 megs, just click and install. It’s a very quick step.

For LaTeX, you have two choices that are outlined in this guide. I chose the simple method, which results in downloading a fairly large file (1.2 gigs) but I didn’t want to spend my day debugging LaTeX install issues, after all this is to help me learning Python!

After downloading LaTeX, it’s a basic package installer. This is the version I used.

The next requirement is the LaTeX2HTML program. It converts the doc files to HTML that will be used by iPython. You can read more about it here. I found the installation instructions were not exactly what I needed. I had to add the /opt/local/bin to my Bash path in order to install LaTeX2HTML. I did this permanently by altering .bash_profile, but for the purpose of this instructions, I have done this temporarily.

# adding to Path
$ PATH = $PATH:/opt/local/bin
$ cd  /opt/local/bin
$ sudo mkdir -p portslocation/dports/latex2html/
$ cd portslocation/dports/latex2html/
# install latex2html
$ sudo port install latex2html

This process takes a little while, so grab a cup of coffee while it’s installing. After it finishes, you’re all set to compile the doc files for Python. First, you need to download the entire Python package. Take a look at the releases here. Here is the specific process I followed.

$ cd ~; mkdir tmp; cd tmp
$ curl -O http://www.python.org/ftp/python/2.5/Python-2.5.tgz
$ tar -zxf Python-2.5.tgz
$ cd Python-2.5/Doc
$ make

This will compile the docs. Specifically, we are interested in the HTML version it creates via LaTeX2HTML. Once it’s complete, you need to place the HTML files somewhere more permanent.

$ sudo cp -r html/ /usr/share/doc/python-2.5-html

Now it’s time to set PYTHONDOCS to the location we just moved the HTML files too. You can do this a few ways, the best method is adding it to the .bash_profile.

$ vi ~/.bash_profile
## Add the following
# export PYTHONDOCS=/usr/share/doc/python-2.5-html
# Save the file and exit
$ source ~/.bash_profile

You’re now ready to start using the doc files with iPython. For convenience, I have attached the compiled files here. Have fun!

Mobile, Mobile, Mobile

Talk of the mobile internet is all the rage these days. From a post by a prominent VC to iPhone ‘killers’ to Jack Dorsey’s new dongle. The web is buzzing about the mobile web. And I have to say it makes sense. Being able to take the virtual world with you is a sexy idea.

Here’s what needs to come of age for mobile to become a reality. Data plans need to be cheaper, much cheaper and screens need to get bigger. Right now, most people use SMS / MMS. While the iPhone has had an impact on mobile web usage, it makes up 16.6 percent* of the smartphone market. It’s a good first step, but a hardly a dominating position of the total cell phone market or even the smartphone market.

A use case for detachment, Friendfeed
Friendfeed was one of the most prominent sites that established real time. Big names like Robert Scoble and Louis Gray sang it’s praises, after Friendfeed made it’s exit (good for them) now one of those A-listers is shaming it.

This is the problem with early adopters, they are the hipsters of the web. Just like the music geeks who love a band until it gets big, these bloggers love it and leave it. Scoble recently claimed that FriendFeed would go the way of Dodgeball or Jaiku. While this most likely will happen, if prominent A-listers abandon the service it may well be a self fulfilling prophecy.

This is the danger of the mobile web. Unless mobile products serve a real need and are not pandering to the fantasies of over-hyped bloggers with super sized megaphones, they’ll never be a true adoption of mobile. We’ve had the mobile Internet for years. Data plans have been available on standard handsets for at least the last 9 years. But the mobile Internet has yet to take off.

People want a rich, interactive, experience. Currently, only one mobile device even begins to meet this need. One of the biggest reasons, in my opinion, the iPhone is a success is the large, color screen. It’s not the app store, it’s the ability to have an immersive experience that drives consumers to the iPhone. This is what pundits need to understand about mobile. The mere ability to get information, or be connected, isn’t enough to cause the explosion of mobile. It has to be so much more. It has to serve a legitimate need and be more enticing than the currently established markets.

I am looking forward to a mobile explosion one day, but for the foreseeable future, I see more services like Twitter having a lasting effect on mobile usage. Twitter’s SMS interface is brilliantly simple. If I was a developer, and I am, I would be developing more products that can be accessed and utilized via SMS and MMS.


Sources:

jQuery Plugins Architecture, An initial overview

I have been dabbling in different styles of jQuery plugin architecture for a few months now. At first, I tried to find a definitive style to emulate, but the jQuery docs don’t express much more than how to leverage the basic API for plugins. The conflict I was having about approach is jQuery is a DOM-centric library, however, not all plugins solely manipulate the DOM. Choosing the best pattern has been a struggle. Below I outline some of the pros and cons of three different formats. I have been using the last pattern for the last few weeks and currently prefer it.

At the office, I began using the below basic skeleton.

//<![CDATA[
 
/*
	name : pluginname
	file : jquery.pluginname.js
	author : gregory tomlinson
	(c) Copyright 2009 AOL LLC
	///////////////////////////
	///////////////////////////		
	dependencies : jQuery 1.3.2
	///////////////////////////
	///////////////////////////
 
*/
 
(function($) {
 
	$.fn.pluginname = function( options ) {
 
		var defaults = {
		    // declare all plugin defaults here
		};			
		var ClassName = {
 
			options : {},
			ui : {
				bx : null
			},
			init : function( obj, options ) {
				this.options = options;
				this.ui.bx = obj;
			}
 
		}, class_options = $.extend(true, defaults, options),
		   j_obj = $(this);
 
		ClassName.init( j_obj, class_options );
		return j_obj;
	}
 
})(jQuery);
 
//]]>

This approach definitely has its strengths. Coming from a background of developing MooTools classes in the past, it was very familiar to me. What I liked about it is it allows me to instantiate multiple instances of the plugin without collision and control the scope very easily.

As you can see, I cache the original value of this into my ui object. This allows me to retain access to the element or group of elements that are originally targeted via jQuery('<element>'); It also let me adjust the scope of the ‘this’ keyword to target my specific internal methods.

One of the nicest things about this approach is all the methods are private. But, it means you cannot call any additional methods, or maintain control over anything in the plugin once it’s been originally initialized. While they are definitely scenarios where having private methods is a huge plus, it’s not a one sized fits all solution.

Additionally, because I changed the scope of the this keyword, it’s difficult for other developers, familiar with jQuery, to quickly read and understand my pattern and code. One major downside is you junk up the code with tons of references to this.

This led me to begin thinking about alternatives to the above approach. I am currently trying out a new format with the FriendFeed plugin that I recently released. Here is the bare bones of that approach.

//<![CDATA[
 
/*
	name : friendfeed
	file : jquery.friendfeed.js
	author : gregory tomlinson
	site: http://gregorytomlinson.com/
	///////////////////////////
	///////////////////////////		
	dependencies : jQuery 1.3.2
	///////////////////////////
	///////////////////////////
 
*/
 
(function($) {
 
	$.fn.friendfeed = function( user, options ) {
 
		/* declare INSTANCE specific variables and settings */
		/* extend the defaults to include all user specified options */
		var defaults = $.extend( true, $.friendfeed.defaults, options );	
 
		/* do anything I want here, keep a cached version of the override options for this instance. */
 
		return this; /* jQuery default behavior, return container */
	};
 
	$.friendfeed = {
 
		log : function( str ) {
			if( !this.defaults.debug ) { return; }
			try {
				console.log( str );
			} catch(e){}
		}
	}
 
	/* define defaults for override */
	$.friendfeed.defaults = {
		/* this is publicly accessible */
	};
 
})(jQuery);

Again, this approach has several strengths. Because I have moved the specific method I might need, in this case ‘log’ outside of the $.fn.method, I can retain access to it, aka it’s public, not private. The biggest drawback to this approach is that collision could occur. Also, options that may be specific to this instance aren’t always easily accessible internally, which can lead to default values that were intended to be overriden at runtime containing incorrect values.

The final pattern I have playing with most recently has mostly private methods, but the pattern doesn’t alter the scope of this, and the code isn’t junked up with tons of references to this

Here is a sample skeleton of the pattern

//<![CDATA[
 
/*
	name : pluginName
	file : jquery.pluginName.js
	author : gregory tomlinson
	site: http://gregorytomlinson.com/
	///////////////////////////
	///////////////////////////		
	dependencies : jQuery 1.3.2
	///////////////////////////
	///////////////////////////
*/
(function($) {
 
	var defaults = {
		/* stuff I want to override  */
	}, el;
 
	function myMethod() {
		// do private method stuff
	}
 
	function eventMethod(e)  {
		/* listen to my element */
	}
 
	$.fn.pluginName = function( options ) {
		// do stuff with the method here
		el = this;
		$.extend( true, defaults, options );
		el.bind( 'click', eventMethod ); // attach an event for kicks
		myMethod();
		el.trigger('myPluginName');
 
		// standard jQuery - return the jQuery Object
		return this;
	}
 
})(jQuery);

It’s very simple to read and the code is fairly concise. It has some limitations, like the inability to directly alter the code once it’s been initialized, however, you can easily attach listeners that can handle that action for you.

I’m not particularly fond of any of these approaches, though I have found myself using the last pattern more often recently. There is definitely something to be said for the MooTools class pattern, though I do find it irritating that MooTools attempts to turn JavaScript into a classical language. jQuery doesn’t mask JavaScript’s prototypical nature and I find that more honest. I plan to keep exploring approaches and find a pattern that both fits my style and leverages the strengths of jQuery.

Quailty Products

I was relaxing at home this weekend, enjoying my favorite TV show, The Simpsons, when my cable suddenly displayed a message that my cable box wasn’t authorized for access. But, I was sure I had paid my bill on time. I tried to restart the box, but it didn’t resolve the issue.

I called my cable provider, which is Time Warner Cable. After about 10 minutes on hold, I finally spoke with a representative. She informed me that she was going to restart the box. I told her I had already tried that, but she was welcome to try again. After she restarted it, the picture returned. I asked what the issue was, and she said that after lengthy periods without a restart this issue tended to occur. That got me to thinking.

When we have to debug issues at work, one of the first things we try is restarting the browser and clearing the cache. If that fails, cookies are cleared and the page is refreshed. This often resolves the issue. However, it occurs to me that this isn’t really fixing the problem because it’s a complete system reset, which is akin to restarting the cable box.

Often, a problem arises because the engineer who designed the system never planned for a fringe case that is causing the bug or issue. Resetting the system doesn’t actually fix the problem. A complete reset makes the bug / issue a moot point. But, it never investigates the true issue with the software.

The team that developed my cable box should be happy that it can run for days or even weeks without issue, however, that doesn’t make it perfect. The problem isn’t that their software has a minor bug, it’s that software is such an integral part of daily life, bugs are inconvenient. Bugs, even the most minor, establish a level of frustration that detracts from the quality of the product. This is true from cable boxes to web applications. Consumers expect their products to be ready at a moments notice. While issues can be resolved with a system reset, they detract from the usefulness of the product.

As we move into a realm where software controls almost every aspect of our lives, stability becomes even more important. It’s not enough for products to pass bare bones unit tests. We must move products into the next level where quality meets stability and software rises past the point of available to extremely reliable.