Archive for Code monkey

Twitmon update: read and post to Twitter on the command line

I've posted a new version of Twitmon, my Python command-line Twitter client.  The new version includes a fix to work with the latest version of Twyt, but more importantly, it can now be used to post status updates to Twitter as well!

Download: twitmon, and don't forget to set your username and password in the script!

Twitmon will fetch new Twitter updates from your followees every couple of minutes, just as before.  But now you can update your status as well, just by typing the new status and hitting enter.

You can also edit the update as you're typing it, and use the arrow keys to navigate back and forth through updates you've previously typed.

Occasionally, the Twitter posts will be refreshed while you're typing, and mess up the display.  You can use the arrow keys to go back, then forward, to clean things up.  It's ugly when this happens, but it still works.


Tags: , ,
Comments (2)

Twitmon: command-line Twitter reader

I've been feeling dissatisfied while trying to read the Twitter statuses of people I'm following. What I usually want to do is read everything that has come in since the last time I posted something. Unfortunately, this is hard to do on Twitter's website. I have to go back through the pages, one by one, to find my last tweet, then start reading upwards and backwards until I get to the beginning again. It's a lot of work and the page load times could be better, so it leaves a lot to be decided.

Twitmon screenshotI decided to use the Twitter API to write a command-line client that would check Twitter every so often and spit out new updates. Turns out I didn't need to do much work: Twyt is an existing Python implementation of the API. I was going to write it in Python anyway, so I downloaded Twyt (on Ubuntu: sudo apt-get install python-twyt) and started poking around.

It wasn't immediately clear how to get started, but I read through Twyt's files until I figured out how to authenticate, fetch status data, and turn it into usable objects. I added some extra stuff to print out color text and to periodically check Twitter, and I've got something I can really use. The code is here: twitmon.

I haven't tested it on Windows; it should work in general, but the text colors may not. The colors can be turned off in the script. Normally, it will use the colors to highlight links and usernames. It will also highlight the current user's username separately from other names; I like this because I can quickly tell if anyone mentions me, and I can find my last tweet quickly.

Update: I've fixed the script to work with Twyt 0.7 (which is the version in Ubuntu 8.04) and 0.8 (which is currently the latest version). You can also now send updates to Twitter with it - just type them and hit enter, and they'll show up on the next refresh.


Tags: , , , ,
Comments (4)

Roll your own remote RickRoll

Last week I posted about a program I wrote to RickRoll someone at will by controlling their computer over the network. Basically, you tell their computer to play "Never Gonna Give You Up" whenever you want. I call it Remote RickRoll, and I'm making it available to download today, including prebuilt binaries and source code.

Remote RickRoll UI

In the victim's list of Windows services:

Remote RickRoll service

In the victim's application log:

Remote RickRoll in the application log

The README file contains complete instructions for preparing your victim's computer without physical access to it.

Remote RickRoll runs as a Windows service, so you will need administrative rights on the victim's machine to make it work. The victim's machine needs to be running Windows and have the .NET Framework 2.0 installed (although that can also be installed remotely without their knowledge). You'll find that Sysinternals PsExec comes in handy.

The source code is C# and it's a Visual Studio 2005 solution. But the zip file includes binaries, so you don't need to compile anything to use it. It's GPL, so if you want to modify it, knock yourself out.

I've used this on two people so far, to great effect. That said, messing with people's computers without their knowledge can turn ugly, so be smart.

I'd like to hear about your questions/comments/success stories/failures/modifications, so please comment below if you're inclined.

Thanks and enjoy!


Tags: , , , , ,
Comments (2)

Greasemonkey script: Pitchfork links

Last.fm links on Pitchfork I read a lot of record reviews over at Pitchfork, and when something sounds good, I usually jump over to Last.fm to listen to it, or to remind myself to check it out again later. For a long time, I've been meaning to write up a Greasemonkey script for Firefox to generate the Last.fm link for me, so I don't have to type it in every time. You know, because that's so hard.

Anyway, I'm working on an, ahem, not tremendously exciting project at work, so I finally got around to it. I went ahead and made it extensible for other links besides Last.fm, so it can do links to iLike and Wikipedia, too; others are easy to add if you're reasonably familiar with Javascript. The script adds the links right next to the album artwork, right below the links to Emusic, digg, del.icio.us, and so on.

I posted it on userscripts.org. I currently have a hundred or so back reviews to read, so hopefully I'll have saved net keystrokes by the time I catch up.

Update: added links to IsoHunt, Mininova, and the Pirate Bay, by request.  I can't test right now because I'm on Firefox 3 RC2 and Greasemonkey doesn't work there yet.  But you can get the new version right here for now.  I will update it on userscripts.org as soon as I get it tested.


Tags: , , , , , , , , , , ,
Comments (2)

Im in ur printrz

When I read about INSERT COIN, the Perl script that changes the ready messages on HP network printers, I was overjoyed. It seems to be a perfect way to wreak mild havoc without really harming anything. I showed it to my buddy John this morning; it's right up his alley, too (for an idea of what John's alley is like, check this out).

Of course, he's a Windows guy (although not a Windows 95 guy). And INSERT COIN is a Perl script, and he doesn't have ActivePerl installed, because when you have cmd, you have everything you need!

So I decided to get him a standalone version of INSERT COIN that will run on his box. I decided to try to port the thing to D. Mainly because I have a short attention span, and I recently read an article about D.

I'm a scripting guy, only recently having delved into statically-typed-but-still-use-a-runtime languages like Java and C#, and hardly at all into lower levels of programming. C and C++ scare me a bit, frankly, but D seems a little more accessible. And by accessible, I mean that it seems like it would be harder to make a total ass of yourself as a newbie. Image is everything.

So I ported INSERT COIN to D. And I have to say it was a very enjoyable experience. Here's the source and the Windows binary (compiled with MinGW). Now John can happily tweak the printers anytime he likes.


Tags: , , , , ,
Comments

Update your status on Twitter and Facebook with Perl

Here's twitface, a Perl script I wrote to set my Twitter and/or Facebook status from the command line.

Get twitface Apparently this violates Facebook's TOS. Oh well.

I run it as twitter to update Twitter, fbstatus to update Facebook, and twitface to update both. To accomplish this, I keep it in my ~/bin directory, with symlinks to it called twitter and fbstatus. So:

cd ~/bin
ln -s twitface twitter
ln -s twitface fbstatus

You'll have to edit the script once to set your Twitter and Facebook login info, but after that, it's as easy as:

twitface wasting time on social networking websites.

Remember that Facebook prepends '[Name] is' to the status you set.

You can also use this to send direct messages via Twitter as you normally would; so this type of thing works as you'd expect:

twitter d rtm Remember the milk...

I found Christian Flickinger's PHP+cURL code quite useful while writing this, since it meant I didn't have to dissect Facebook.

I'm new to Twitter right now, but it seems pretty fun. We'll see how it goes.


Tags: , , , , ,
Comments (3)

I'm not a math geek, but…

I'm not a math geek, but occasionally something piques my interest. Today I was trying to work out a good way to do something randomly about once every nine or ten times. I decided to check the last digit of the return value of Javascript's Math.random() function, which returns a number between 0 and 1. Like this:

0.1809368982206232

I knew it would never be zero, since the trailing zero would be removed; so I figured I could pick any other digit and I'd be right about once every nine times.

Turns out it doesn't work like that. The frequency distribution of the last digit is uneven.

<script type="text/javascript">
for (var num=1; num<=9; num++) {
var match = 0;
var re = new RegExp(num+'$');
for (var i=0; i<10000; i++) {
if (re.test(Math.random())) { match++; }
}
document.write("<p>" + num + ": " +
(match/i*100+'').substring(0,5) + "%</p>");
}
</script>

This script calls Math.random() 10,000 times for each digit from 1 to 9. It prints the last digit match rate as a percentage. Its output looks like this:

1: 8.790%
2: 10.4%
3: 12.19%
4: 13.17%
5: 13%
6: 12.95%
7: 11.51%
8: 9.35%
9: 8.58%

You'd expect something around 11.11% (one of nine) for each digit; but you can see that the frequency increases until 4, and then decreases again. In fact, this looks a heck of a lot like a bell curve, ergo, a Gaussian distribution.

I found that if I check the first digit after the decimal point, I get what I'm expecting: a list of roughly equal values somewhere around 11.11% for each digit. So although the output of Math.random() is uniformly distributed, the last digits are normally distributed.

I can't grok this much further than that; perhaps it's got something to do with the way the numbers are generated, or maybe that's just The Way Things AreTM. If anyone can explain to me why this happens, leave a note. Maybe I'll go poke around in the Gecko source code or something.


Tags: , , ,
Comments (6)

Wordpress plugin: Batch image uploader 0.2

I've gotten a great response from my initial release of the Batch image uploader. So let me first say thanks to everyone who left their comments and suggestions.

Today I'm releasing the next version of the plugin - Batch image uploader 0.2. The killer feature this time around is the ability to use different "backends" to resize the images. (This was initially suggested by Alexander Radsby.) There are three supported backends right now: GD, mogrify, and imagick.

GD is PHP's default image processing library. It's fast, but the quality of the images is not so good. This is what version 0.1 of the plugin used, and it's still an option in version 0.2.

mogrify has nothing to do with me, other than being the program from which I chose my Internet identity many years ago. It's actually one of the programs in the ImageMagick distribution of command-line image processing tools. This backend offers far better image quality, but is most likely slower, than GD. To use this, you have to have ImageMagick installed, and you have to tell my plugin where to find the mogrify binary. On UNIX systems, this is nearly always /usr/bin/mogrify, so that's the default.

Finally, imagick is the imagick PECL extension for PHP. It has the same image quality as the mogrify program, but is likely to be a great deal faster. This is because it uses ImageMagick libraries instead of invoking a program, so there is none of the overhead involved with starting another shell process.

You can force the plugin to use any one of these backends, but I recommend using the 'Auto' option. This will automatically select the best available backend, in this order: imagick, mogrify, GD. You can figure out which one it's using if you enable the debugging info.

With ImageMagick support comes support for dozens of image formats. The GD backend still only supports PNG, JPG, or GIF images.

The download and other current information is at the Batch image uploader page.


Tags: , , , , , , ,
Comments

Audio tagging, Web 2.0-style.

I decided I want to be able to tag my audio files. Not just tagging, like with ID3 tags, but you know, tagging, like you tag a flickr photo or a del.icio.us bookmark. Web 2.0 tagging.

I have a digital music collection of close to 800 albums. There are nearly 300 different artists represented across almost 9,000 individual Ogg and MP3 files. I typically listen to this collection over the network, using DAAP (see a previous post), or occasionally through a Samba share from my Windows machine.

It's getting a little hard to find things with so much music to look through. So I've built some playlists with mt-daapd that divide things up in various ways. It goes a long way - you can specify playlists based on any combination of metadata fields, date added, filename, bitrate, etc.

There are a few problems with this approach. First, they're hard to maintain; even if your files are scrupulously tagged (I use MusicBrainz, which handles everything except, inexplicably, genre), you usually have to remember to add new things to your playlists.

Second, it's not very flexible; if you want to group music by anything other than genre (say, region of origin, or "driving songs"), you're out of luck. This issue is complicated by the perverse decision to limit genres in ID3v1 to a predetermined list of 126 (often dubious) choices.

Third, it's not portable. Your carefully constructed playlists are only available to DAAP clients accessing your share. This defeats the main reason for building audio metadata right into the files themselves.

After struggling with this for a while, it seems clear that what I really want to do is to associate small bits of arbitrary metadata with each file, so that I can create playlists based on whether those bits are present or not. And it should be up to me to determine what the groupings are. I should be able to create playlists of my wife's favorite songs, songs written by Lennon/McCartney, songs that came out while I was in high school, songs by artists from other countries, songs that I've seen performed live… anything I can think of should be possible. In other words, I want to be able to tag — and I mean Web 2.0-style, baby — my music.

So I began to commandeer the "comment" metadata field for this purpose. It works beautifully - I fill in the comment field with a space-separated list of tags for a file. In mt-daapd, and in library-based clients like Winamp, I can create a playlist based on whether a particular string occurs in the comment field. And the tags stay with the file, where they belong.

Still, it's a little daunting to tag 9,000 audio files. So — and here's the fun part — I wrote a couple of tools in Perl to help me out.

The first one doesn't actually tag anything. I use it to help me figure out what tags I might want to add to a particular artist. Given a list of artists, it will go over to last.fm and get a list of the top tags for an artist using their excellent XML services. If you don't give it any artists, it will use the name of the current directory (a convenience for me, since I'm doing all this from the command line). It's called lastfmtags, it uses LWP, and if you love the GPL, you can download it right here.

lastfmtags:
$ lastfmtags C*
Fetching tags for CAKE...
alternative
rock
indie
alternative rock
indie rock
seen live
Cake
pop
favorites
fun
Fetching tags for Cage...
Hip-Hop
hip hop
rap
Def Jux
heavy metal
underground hip hop
underground hip-hop
hiphop
Power metal
metal
...

'Nuff said. Okay, the other one is called commentify, and it's the tool I use to bend the audio comment field to my will. At its core is Audio::TagLib, which is a Perl wrapper around the nifty taglib library. It's a format-independent audio metadata library, which means that it goes and figures out what kind of audio file it's dealing with and handles each type in its own special way, so you don't have to. And it means that this script should work, not only for MP3 and Ogg, but also, apparently, APE, FLAC, and Musepack.

commentify can do five different tagging operations: set, append, delete, clear, and list. And it can act on multiple files or directories. If you give it a directory, it'll perform that operation on all files it finds underneath that directory (including all subdirectories). So it's easy to tag a whole lot of files, especially in a well-organized library. It's GPL, too, and you can get it right here.

Note that it will not attempt to preserve tag order. If it does, it's by accident. And it will not tag a file with duplicate tags.

commentify:
# set tags for all files within multiple directories
# (replaces all comment fields)
commentify -s "rock indie canadian" Arcade\ Fire/ Metric/

# add a new tag to some files
# (leaves existing tags intact)
commentify -a "favorite" dir1 dir2 file1 file2

# delete a couple of tags from some files
# (leaves others intact)
commentify -d "blah yadda" dir1 file1

# clear all comment fields
commentify -D dir1 dir2

# list comment fields for all files found
commentify -l dir1 dir2

Ah, that's good stuff. Now I think I'll go create a playlist from albums with green on the cover, bands that are side projects, and songs about cheese.


Tags: , , , , , , ,
Comments (9)

HenricoCrime.org

I recently put together a new website, HenricoCrime.org. It's a crime data/Google Maps mashup in the style of ChicagoCrime.org and RichmondCrime.org.

The crime data comes from the Henrico County, VA police department website… the heavy lifting is handled by a set of PHP classes that search the site and scrape the HTML for event data. I use Yahoo's geocoding service to find the latitude and longitude of each event. I first tried Google's but I found that it guessed wrongly too often… Henrico County has several different localities, and I have no way of knowing which one I'm looking for. Google will return hits on similar street names in the wrong places, where Yahoo is more strict. I then store the whole mess in a MySQL database on my server.

All that happens on the backend - the website itself just queries the database and assembles a Google Map with info markers for each event. I also generate some basic statistics from the database for each day.

The other interesting bit is The Cloud. I was trying to think of interesting ways to display trends over a long period of time… The Cloud loads hundreds of crime events at once and marks each one with a tiny, nearly transparent dot on the map. As events stack up in the same place, the marks become darker. So if you pull in a few thousand events, you can see where much of the police activity is happening. Generally, it seems like many of the events cluster along the main roads in suburban Richmond. The best places to be, crime-wise, appear to be Glen Allen (the area in the North right around 295), and eastern Henrico (which is mostly rural).

I'd like to keep coming up with different ways of looking at the data; for instance, weekly, monthly, and annual statistics, breakdowns by crime type, RSS feeds, etc. Most events have more data than I'm actually displaying here, so there should be some other possibilities.

Oh, and I also recently completed a site for my aunt, who runs Connections Speech-Language Therapy in Boerne, TX. So, shameless plug there.


Tags: , , , , , , , , , , ,
Comments (1)

Bad Behavior has blocked 53 access attempts in the last 7 days.