Lance Wicks
Kiwi,
Judoka,
Geek,
Husband
Daddy!

JudoGeek Blog

More tweaking of the Snarl Twitter script (including Identi.ca support). 

I have done a little refactoring of the script I use to pop-up messages when I get new messages from both Twitter and now Identi.ca too.

Comments on my bad scripting welcomed.

use strict;
use warnings;
use XML::Simple;
use Array::Diff;
use Data::Dumper;
use OfficeLaunch;
use IPC::Open3;
use LWP::UserAgent;

use English qw( -no_match_vars );
local $OUTPUT_AUTOFLUSH = 1;

use version; our $VERSION = qv('0.0.2');
# -----------------------------------------------------------
# parse_rss.pl
#
# Created by Lance Wicks ( www.lancewicks.com)
#
# This simple script polls Twitter and identica
# and lets you now if there are new posts via
# Snarl, using Snarl_CMD.
#
# -----------------------------------------------------------

print "Twitter & Identi.ca alerter Version:$VERSION\n\n";
my $twitter_url = 'http://twitter.com/statuses/friends_timeline/73963.rss';
my $twitter_user = 'USERNAME';
my $twitter_pass = 'PASS';
my $twitter_icon = 'c:\lwtemp\LH\twitter.png';
my $identica_url = 'http://identi.ca/lancew/all/rss';
my $identica_user = 'USER';
my $identica_pass = 'PASS';
my $identica_icon = 'c:\lwtemp\LH\speaker.png';


sub parse_feed{
my($feed,$id,$pass) = @_;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => $feed);
$req->authorization_basic($id, $pass);
my $rss_new = $ua->request($req)->as_string;
return $rss_new;
}

sub compare_feeds{
my($old,$new,$icon) = @_;
my @old_feed = split /<item/, $old;
my @new_feed = split /<item/, $new;
my $diff = Array::Diff->diff( \@old_feed, \@new_feed );
if ($diff->count > 0){
foreach (reverse(@{$diff->added})) {
$_ =~ /<title>(.+)<\/title>/;
if ($1 =~ /^(.*?): (.*)/) {
print "\n$1\n";
my $cmd = "\"C:\\Program Files\\Snarl_CMD_0.1\\Snarl_CMD.exe\" snShowMessage 8 \"$1\" \"$2\" \"$icon\"";
my $pid = open3(my $wtr, my $rdr, my $err, $cmd);
my @response = <$rdr>;
}

}
}

}

print "Obtaining initial feeds...\n";
my $twitter_orig = parse_feed($twitter_url, $twitter_user, $twitter_pass);
my $identica_orig = parse_feed($identica_url, $identica_user, $identica_pass);


# -----------------------------------------------------
# MAIN LOOP
# -----------------------------------------------------
while(1) {
print "Pausing";
for (my $count = 200; $count >= 1; $count--) {
print ".";
sleep(1);
}
my $twitter_new = parse_feed($twitter_url, $twitter_user, $twitter_pass);
my $identica_new = parse_feed($identica_url, $identica_user, $identica_pass);

compare_feeds($twitter_orig,$twitter_new,$twitter_icon);
compare_feeds($identica_orig,$identica_new,$identica_icon);

$twitter_orig = $twitter_new;
$identica_orig = $identica_new;
}


[ add comment ] permalink ( 3 / 2 )
How to add a new service to NoseRub... an eediot's Guide. ;-) 

How to add a new service to NoseRub... an eediot's Guide. ;-)



Below is a basic guide as to how to add a new service to NoseRub. By adding a new service to NoseRub you enable automatic discovery of RSS feeds and correct classification and handling of information from the new service.

This is an initial draft, so please give me your feedback. Some services will require more than this so your "mileage may vary" so to speak.

Enjoy...

To create a new service is a 4 step process.

STEP 1
Create a new file called myapp.php in /app/models/services.
You may decide to copy an existing similar service file to act as a template, for example if the service you are adding is a bookmarking service you might like to use the delicious.php file as a template for your service.
The contents of the delicious.php file are as follows:
<?php
class DeliciousService extends AbstractService {
public function detectService($url) {
return $this->extractUsername($url, array('#del.icio.us/(.+)#'));
}

public function getAccountUrl($username) {
return 'http://del.icio.us/'.$username;
}

public function getContacts($username) {
return ContactExtractor::getContactsFromSinglePage('http://del.icio.us/network/' . $username . '/', '/<a class="uname" href="\/(.*)">.*<\/a>/iU');
}

public function getContent($feeditem) {
return $feeditem->get_link();
}

public function getFeedUrl($username) {
return 'http://feeds.delicious.com/rss/'.$username;
}
}
?>

1a. You need to change the class name to MyappService
1b. Alter the detectService function so it refers to the url of your app, this is a REGEX. (This function is used to autodetect the username from an url)
1c. Alter the GetAccountUrl function so that it too knows where the username is. (This is used if you add the service and put your username, it creates an url)
1d. If the service has friends or contacts that you can connect to, alter getContacts to find contacts. If not you can remove this function.
1e. Alter getFeedUrl so that it has the correct path to the RSS feed for this new service.
Below is a example of how the myapp.php file might look:
<?php
class MyappService extends AbstractService {
public function detectService($url) {
return $this->extractUsername($url, array('#myapp.com/user/(.+)#'));
}

public function getAccountUrl($username) {
return 'http://myapp.com/user/'.$username;
}

public function getContacts($username) {
return ContactExtractor::getContactsFromSinglePage('http://myapp.com/users/' . $username . '/friends', '/<a class="Buddy" href="\/(.*)">.*<\/a>/iU');
}

public function getContent($feeditem) {
return $feeditem->get_link();
}

public function getFeedUrl($username) {
return 'http://rss.myapp.com/rss/'.$username;
}
}
?>


Step2.
Create a .GIF icon for this service and put it in the /app/webroot/images/icons/services directory. Please make it the right size etc.

Step 3.
Having created the php file you need to add an entry for this service in the NoseRub database. To ensure that everyone is able to benefit from your hard work database modifications are included in the SVN and are placed in individual files in /app/config/sql/migrations directory.
Create a SQL command similar to the one below (as a single line)
INSERT INTO `services` (`id` ,`internal_name` ,`name` ,`url` ,`service_type_id` ,`help` ,`icon` ,`has_feed` ,`is_contact` ,`minutes_between_updates` ,`created` ,`modified`)VALUES ('42' , 'Myapp', 'MyApp.com', 'http://www.myapp.com', '2', '', 'myapp.gif', '1', '0', '30', NOW( ) , NOW( ));
** The id field value (42 in this example). You need to select a unique ID, so check what services exist in the database already before choosing. You need to specify it so that the service ID will be consistent across installations.
** The internal_name field is case sensitive and is tied to the name of the class in step 1
** service_type_id. This is the type of service (bookmark, blog, picture, etc) the ID relates to the service_types table in the NoseRub database. In this example we have set the field to '2', which is a Bookmarking service.
** has_feed. Set to this is the service has a RSS feed. So in this case it does so it is set to '1'
** minutes_between_updates. This is the minimum time before noserub will check the RSS feed again. it will help prevent overloading of the service. In this example we have set it to thirty minutes.
You might want to cheat and add the record manually using something like phpmyadmin ( I know I do), you can then copy and paste the SQL command from the screen. If you do this however, be sure to edit the command so that it is one line and remove the name of your database. Also make sure you have added a ID field and it is not NULL.
Step 4.
Go to http://<server_name>/noserub/jobs ... tem/update to update the database with your new entry.

Hopefully everything is now working happily. So all there is left to do is send your changes to NoseRub.com (myapp.php and your migration SQL file).

Please also send an example username so that we can quickly test everything and get it into the code base.

*** Please note that you'll need to remove the service before you do an update from noserub.com as update will try and re add your new service and fail.




[ add comment ] ( 2 views ) permalink ( 2.2 / 5 )
TwitterSnarl Revised for Snarl_CMD 2 

So below is a minor revision of the TwitterSnarl code I wrote a while back.

Here is the code, I'd appreciate poeples comments:


use XML::Simple;
use Array::Diff;
#use LWP::Simple;
use Data::Dumper;

use OfficeLaunch;

#use FileHandle;

use IPC::Open3;
use English qw( -no_match_vars );
local $OUTPUT_AUTOFLUSH = 1;
#use XML::SemanticDiff;



my $rss_address = 'http://twitter.com/statuses/friends_timeline/73963.rss';
#my $rss_address = 'http://feeds.feedburner.com/PlanetJudo';

#getprint($rss_address);

use LWP::UserAgent;
$ua1 = LWP::UserAgent->new;
$req1 = HTTP::Request->new(GET => $rss_address);
$req1->authorization_basic('USERNAME', 'PASS');

#print $ua->request($req)->as_string;


print "Getting original data set...\n";
my $rss_old = $ua1->request($req1)->as_string;
#print "Old RSS:$rss_old\n";

while (1) {


OfficeLaunch::countdown();
print "Pausing";
for ($count = 200; $count >= 1; $count--) {
print ".";
sleep(1);
}
print "\nGetting new dataset...\n";

my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => $rss_address);
$req->authorization_basic('USER', 'PASS');
my $rss_new = $ua->request($req)->as_string;

#print "url:$rss_address\n";
#print "new rss:\n$rss_new \n";
@old = split /<item>/, $rss_old;
@new = split /<item>/, $rss_new;

my $diff = Array::Diff->diff( \@old, \@new );
print "\n".$diff->count."\n";

#print Dumper($diff->added);
#print Dumper($diff->deleted);

$rss_old = $rss_new;



if ($diff->count > 0){



#print @{$diff->added};

foreach (reverse(@{$diff->added})) {
$_ =~ /<title>(.+)<\/title>/;
if ( $1 ne "Twitter / lancew with friends" and $1 ne "Twitter"){
print $1.".\n";
my $tempuser;
my $temptext;
if ($1 =~ /^(.*?): (.*)/) {
$tempuser = $1;
$temptext = $2;
}
my $cmd = "\"C:\\Program Files\\Snarl_CMD_0.1\\Snarl_CMD.exe\" snShowMessage 8 \"$1\" \"$2\" \"c:\\lwtemp\\LH\\twitter.png\"";
my $pid = open3($wtr, $rdr, $err, $cmd);
my @response = <$rdr>;
#use Win32::Snarl; Win32::Snarl::ShowMessage('Twitter', $1);
}
sleep(1);
}

}




}





[ add comment ] permalink ( 3.5 / 2 )
Getting organised... 

So I am off to Germany next week for the NoseRub DevCamp, work has been busy and I have an increasing number of things I am trying to get done.

The result has been that things have been slipping and I have found myself feeling a bit dazed and disorganised.

So... I have had a bit or a refresh on the old getting things done (GTD) methodology.

First up, I have started using "Things" from Cultured Code both on my Mac and also on the iPhone. Things is a GTD tool and happily the iPhone client syncs with the Mac software, so I have one "InBox" (to use GTD terminology). So I feel happier putting my things to do in Things as I can do it on the phone and on the laptop.

As with every time you refresh your to do lists, you spend a lot of time creating a huge list of things and wondering if you'll ever get anything actually done. I have (almost) got past that point and am getting the satisfaction of watching things go into my "Logbook" in things.

Things is in Alpha/Beta technically but is pretty polished if you ask me. I decided on Things for two main reasons; first is the whole laptop<->iPhone sync feature. The other was basically that they have a part on the website which shows how you can export your data to XML, to quote the page itself:

Yours forever. We don't lock you in. Things uses an open XML file format to store your data. This gives third parties a transparent way to communicate with Things. Even better still, by using a modern web browser users will be able to view Things files fully formatted on any platform anytime


That swung it for me emotionally.

In other news, partly because I have a bit more of a sense of control I have put some effort into the podcast and www.08judo.com and other projects.

My big push at the moment is to learn a bit about iPhone development and Objective-C in advance of the DevCamp. I fancy creating an iPhone client for NoseRub so if you have thoughts on how to (quickly) get into Cocoa programming etc. let me know.



[ add comment ] ( 1 view ) permalink ( 2 / 3 )
NoseRub DevCamp - September 13th to 14th 2008 in Cologne Germany. 


This September I hope to get across to Germany for the NoseRub DevCamp that has just been announced on the NoseRub Blog.

I am not intimate with the codebase, but hopefully attending will help me get my head around it a bit more. Afterall I run it on this site ( http://www.lancewicks.com/noserub/lancew ).

I only use it really as a aggregator for the social networks I use, but would like to see the project expand. I have looked and experimented with integrating tools like identi.ca and SMOB and would like to see some of that functionality incorporated.

I also wrote a Python client for the location feature of NoseRub, which I used to run on my Nokia E90, it'd be good to contribute that back properly. Now I am an iPhone user, I am considering trying my hand at writing an iPhone app for NoseRub?

Perhaps, after attending the DevCamp and learning more about it I might be able to re-visit some of the ideas I have about "Context" and social networks. It is getting more coverage now that the iPhone has GPS and location is getting more and more trendy.

So... if you are free on the 13th and 14th of September, consider coming to Cologne or at attending the DevCamp virtually.
[ add comment ] ( 1 view ) permalink ( 3 / 10 )

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Next> Last>>