Archive for the ‘hacks’ Category

SAC alert “application”

Tuesday, December 18th, 2007

During the recovery from my previously mentioned osteotomy, I’ve been spending lots of time chatting with my physical therapist Larry Meyer. He’s an interesting and personable guy (and is really handling my PT well). In my dozens of appointments, we’ve talked about lots of stuff, including Lijit, Christmas presents, and something near and very dear to me, bargain hunting.

Along the way, I mentioned Steep & Cheap, which is basically like the woot of outdoor gear. They have single deal after single deal, about every 20 minutes or so, all day long. It’s fine for me because I work at a computer all day long and can see each deal as soon as it is posted. But Larry is not at a computer, though he does have access to one.

What Larry does have, though, is a pager with an email address. It got me to thinking, so I hacked together a little PHP code, mixed it gently with cygwin cron, to poll the SAC deal feed. If the deal changes, the application will send him a page.

So far, he’s not tired of the constant buzzing on his hip.

Here it is. Standard disclaimer applies: this is quick n’ dirty(tm):

<?
// Requires PEAR::Mail
require_once( 'Mail.php' );

$sac_rss = "http://www.steepandcheap.com/steepcheap/rss.xml";
$item_element = "ITEM";
$have_item = FALSE;
$in_item = FALSE;
$current_element = "";
$message = "";
$statusFile = "sacdeal.txt";

$to_list = array( "pager_email_address" );

$from = 'SAC Alert <sacalert@my.hosting.company>';
$subject = 'SAC deal alert';

$host = 'smtp.server.name';
$username = 'smtp.userid';
$password = 'smtp.password';

$to = "";
foreach( $to_list as $emailaddy )
{
  $to .= "$emailaddy, ";
}
echo "$to\n";

function startElement( $parser, $name, $attrs )
{
  global $current_element, $have_item, $in_item, $item_element;
  $current_element = $name;
  if ( $name == $item_element )
    $in_item = TRUE;
}

function endElement( $parser, $name )
{
  global $current_element, $have_item, $in_item, $item_element;
  $current_element = "";
  if ( $name == $item_element )
  {
    $in_item = FALSE;
    $have_item = TRUE;
  }
}

function elementData( $parser, $text )
{
  global $current_element, $have_item, $in_item, $message;
  if ( $in_item && !$have_item )
  {
    // the message content is only the title or the price
    if ( $current_element == "TITLE" || $current_element == "SAC:PRICE" )
      $message .= "$text\n";
  }
}

$xml_parser = xml_parser_create();
xml_set_element_handler( $xml_parser, "startElement", "endElement" );
xml_set_character_data_handler( $xml_parser, "elementData" );

// fetch the feed content and parse it
$xml = file_get_contents( $sac_rss );
xml_parse( $xml_parser, $xml );
xml_parser_free($xml_parser);

// compare the current item in the feed to the last one we sent email about
$oldcontents = file_get_contents( $statusFile );
if ( $oldcontents != $message )
{
  $headers = array( 'From' => $from,
                    'To' => $to,
                    'Subject' => $subject );

  $smtpParams = array( 'host' => $host,
                       'auth' => true,
                       'username' => $username,
                       'password' => $password );

  $smtp = Mail::factory( 'smtp', $smtpParams );

  $mail = $smtp->send( $to, $headers, $message );

  echo $message;
  if (PEAR::isError($mail))
  {
    echo( $mail->getMessage() . "\n" );
  }
  else
  {
    echo( "Message successfully sent!\n" );
    file_put_contents( $statusFile, $message );
  }
}
else
{
  echo "same deal as last time\n";
}
?>

Blinklist -> del.icio.us

Friday, December 7th, 2007

Long ago I migrated from del.icio.us to Blinklist. Why? Blinklist would let me combine tags when trying to find a link, and del.icio.us wouldn’t. For example, with Blinklist I could find a link tagged with both “reference” AND “css”. On del.icio.us, only “reference” OR “css”.

Unfortunately, Blinklist dropped that feature a while back. I just noticed del.icio.us added it, and I’m tired of waiting for Blinklist to add it back in.

But I faced the problem of getting all my bookmarks from Blinklist back to del.icio.us. Probably such a tool exists already, but it was pretty easy to hack together in PHP.

Download your Blinklist bookmarks in XML from http://www.blinklist.com/?Action=User/Export/export.php and save them in blinklist.xml.

Blinklist allowed spaces in tags, del.icio.us does not. The code converts spaces in the tags to hyphens. PEAR HTTP_Request and openssl is required in your PHP install.

Run it from the command line: php blinklist-to-delicious.php blinklist.xml

Here’s the code. Standard disclaimer applies: this is quick n’ dirty(tm):

<?php
/* Take blinklist bookmarks xml
             and add them to del.icio.us via the API.

---------------------------------------------------
del.icio.us API:

https://api.del.icio.us/v1/posts/add?

&url (required) - the url of the item.
&description (required) - the description of the item.
&extended (optional) - notes for the item.
&tags (optional) - tags for the item (space delimited).
&dt (optional) - datestamp (format "CCYY-MM-DDThh:mm:ssZ").
&replace=no (optional) - don't replace bookmark if already posted.
&shared=no (optional) - make the item private

---------------------------------------------
Blinklist entry XML:
  <item>
   <title>MrBalky Heavy Industries</title>
   <description></description>
   <link>http://www.mrbalky.com</link>
   <guid></guid>
   <pubDate>1197042355</pubDate>
   <private></private>
   <favourite></favourite>
   <vote>0</vote>
   <category>awesome,cool,stupid</category>
  </item>
*/
require_once "HTTP/Request.php";

$delicious_id = 'mydeliciousid';
$delicious_pass = 'mypassword';

define( "ITEM", "ITEM" );
define( "TITLE", "TITLE" );
define( "LINK", "LINK" );
define( "PUBDATE", "PUBDATE" );
define( "CATEGORY", "CATEGORY" );

$item = array();
$have_item = FALSE;
$in_item = FALSE;

function startElement( $parser, $name, $attrs )
{
  global $current_element, $in_item, $item;

  $current_element = $name;
  if ( $name == ITEM )
  {
    $item = array();
    $in_item = TRUE;
  }
}

function endElement( $parser, $name )
{
  global $current_element, $in_item, $item;

  $current_element = "";
  if ( $name == ITEM )
  {
    $in_item = FALSE;
    addToDelIcioUs();
  }
}

function elementData( $parser, $text )
{
  global $current_element, $in_item, $item;

  if ( $in_item )
  {
    $item[ $current_element ] .= $text;
  }
}

function addToDelIcioUs()
{
  global $item, $delicious_id, $delicious_pass;

  $itemURL = urlencode( $item[LINK] );
  $itemTitle = urlencode( $item[TITLE] );
  $itemDate = strftime( '%Y-%m-%dT%H:%M:%SZ', $item[ PUBDATE ] ); 

  $apiURL = "https://api.del.icio.us/v1/posts/add?url=$itemURL";
  $apiURL .= "&description=$itemTitle";
  $apiURL .= "&dt=$itemDate";
  $apiURL .= '&tags=';
  $sep = "";

  $itemTags = split( ',', $item[ CATEGORY ] );
  foreach( $itemTags as $tag )
  {
    $tag = str_replace( ' ', '-', $tag );
    $apiURL .= "$sep$tag";
    $sep = '+';
  }
  echo "$apiURL\n";

  $req =& new HTTP_Request( $apiURL );
  $req->setBasicAuth( $delicious_id, $delicious_pass );

  $response = $req->sendRequest();

  if ( PEAR::isError($response) )
  {
    echo 'Error: '.$response->getMessage()."\n";
  }
  else
  {
    echo 'Response: '.$req->getResponseBody()."\n";
  }

  echo "\n";

  sleep( 5 );  // be polite to del.icio.us
}

$inputFile = $argv[1];
echo "input: $inputFile\n";
$xml = file_get_contents( $inputFile );
$xml_parser = xml_parser_create();
xml_set_element_handler( $xml_parser, "startElement", "endElement" );
xml_set_character_data_handler( $xml_parser, "elementData" );
xml_parse( $xml_parser, $xml );
xml_parser_free($xml_parser);
?>

A TiVo post

Wednesday, April 4th, 2007

This is a post about TiVo. “TiVo” is a favorite search term at Lijit, so I’m writing a post about it so TiVo will come up in my search results.

You can see what’s currently recorded on my TiVo in the sidebar on the right.

tivo logo