Blog

A Tale of Two Bots

Pew pew pew

RedditBots Source: [ Download ]

One day, somewhere between Christmas and New Years, a coworker of mine was musing out loud about a vanity reddit account he had created. He was describing exactly what it would do and I was like "dude. We can automate that." So, in a fury of coding and some poring over reddit documentation, I pulled together a very simple bot that did exactly what he had described. Slapped it on an every ten minutes cron job and called it a day. The code was ugly and I vowed to make a nicer version.

That I did and, while I was at it, decided that I should make it a simple framework with which I could bots in a simple manner and have a central script that managed them all. The above source is what I settled on (complete with a working, if not banned, version of a binky79 clone).

My own bot idea, as it was Christmas, was for a bot named Ebeneezer_McUpvote (a portmanteau of Ebenezer Scrooge, Scrooge McDuck and everyone's favorite reddit term, upvote) to randomly upvote a new link and add the comment "Merry Christmas! Have an upvote ^ _ Q". Scripted, running, would execute every five minutes.

People hate it.

As of this writing, that bot has -310 comment karma. Now here's where the fickleness of reddit shows through.

Yesterday, as I was browsing, I came upon this post. So, Oprah giving random upvotes is considered cool, eh?

Enter, OprahGivesAnUpvote. She does pretty much EXACTLY the same thing as Ebeneezer_McUpvote, only she says "Look under your chair... you got an UPVOOOOOOOOTE!!". People love her. OprahGivesAnUpvote has, at this writing, 233 comment karma and she's only been running since yesterday morning.

Why the hatred? I dunno. Maybe people don't get the joke of Ebeneezer_McUpvote. Maybe the joke just sucks. Maybe it's not Christmas anymore. Either way, Oprah is loved, McUpvote is not. I'll be interested to see if Ebeneezer's fortune turns around when we get closer to Christmas again...

With the addition of search, the circle is complete

Sometime in late 2002, I was welcomed on to the partyfish dev team. My first task: create the site wide search. Now, bear in mind that this was my first time really doing anything in PHP and search is quite a big thing. Ask Google. I'm pretty sure they'd back me up.

Today, some eight years later, I have implemented site search into my website. Of course, it's running circles around my original code in terms of complexity, speed and even the amount of lines it's implemented in (340 v 70).

Here are some of the fun things the new search can do:

- Searches through all content types and each type can display differently in search results

- All searches are weighted against where the terms were matched. The algorithm is such: (matches in title * 10) + (matched tags * 5) + matches in body

- As with all aspects of my site, the search has a RESTful interface so I could make an ajaxy instant search if I so desired

Here are some good queries to show off what it can do:

Rock Band - Example where weighting really helps

Photoshop - Example of different document types

btw, if you wanted to see the old partyfish search code, here you go. The new search stuff will be added to the repository shortly and I'll be making that public very soon.

Another Code Battle Royale

My brother and I are programmers. This must be discreetly understood or no good will come of the story I am about to regale. Every once and again, we'll embark on a coding competition. Last time was a game, this time a chat client. My weapon of choice was various web languages (PHP and JS for the programatic stuff) and his was C++. Arguably, I had an advantage.

Even though I was able to bypass the whole sockets layer, I did set a rule for myself: I could not resort to using a transactional database (i.e. MySQL). Granted, I didn't foresee any issues as I had the power of APC caching on my side. It turned out that this would be what I fought with most and, eventually, just give up on.

For whatever reason, despite the fact that apc_store was returning success on caching an object, it would not persist. A quick call to apc_exists immediately after the store command with the same cache key confirmed this. I went round and round with this issue. Sometimes the object would persist for one or two sessions but ultimately would up be dropped. I read somewhere that storing an array of objects could cause issues (which I was doing), so I serialized the bitch before caching. No dice.

In the end I said "screw it" and just created my own disk-based caching model. I decided to take the whole thing a little further and account for cache collisions (two instances accessing the cache at the same time) which may or may not work. The only reason I even bothered was because I have an ID variable that needs to iterate for every single chat posted and sought to avoid two scripts running simultaneously and writing an erroneous value (a point that was raised in some fashion during my Digg interview.

So, two hours after the initial one we'd allotted for the competition, I wound up victorious. While not glamorous, my chat client does indeed work: Live Demo - Source

What of my brother's program? Well, let's just say the computers weren't talking too nice and the program kept crashing.

Victory is mine!

PHP ID3Lib 1.0 Release

Brand spanking new release of the PHP branch of ID3Lib!

[ Download ]

[ Documentation ]

What's new:

- Added support for ID3v1, older ID3v2

- Genre now returned on all tag versions

- Calculates song duration and average bit rate for constant (CBR) and variable (VBR) bit rate files

- Single object instantiation can read more than one file

- Much improved inline documentation (phpDoc style)

- General code clean-up, bug fixes and improved compatibility

Example

Code: php
  1. include('id3lib.php');
  2. $songs = array('song1.mp3', 'song2.mp3', 'song3.mp3');
  3. $id3 = new ID3Lib();
  4. for ($i = 0, $count = count($songs); i < $count; i++) {
  5. $id3->readFile;
  6. $min = floor($id3->length / 60);
  7. $sec = $id3->length - ($min * 60);
  8. $sec = strlen($sec) == 1 ? '0' . $sec : $sec;
  9. echo 'Title: ', $id3->title, '<br />';
  10. echo 'Artist: ', $id3->artist, '<br />';
  11. echo 'Album: ', $id3->album, '<br />';
  12. echo 'Track Number: ', $id3->track, '<br />';
  13. echo 'Disc: ', $id3->disc, '<br />';
  14. echo 'Year: ', $id3->year, '<br />';
  15. echo 'Genre: ', $id3->genre, '<br />';
  16. echo 'Length: ', $min, ':', $sec, '<br />';
  17. echo 'Avg. Bit Rate: ', $id3->bitrate, '<br />';
  18. $id3->savePicture($i.'_pic.jpg');
  19. }
  20. ?>

If you have any comments/issues, let me know!