#!/usr/bin/perl -w # Tasty Post - Post a daily collection of links on your blog # Copyright (C) 2005 Nikolas Coukouma # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. my %config = ( 'delicious_username' => 'atrus', 'delicious_password' => 'password1', 'delicious_tags', => '', 'blog_username' => 'atrustheotaku', 'blog_password' => 'password2', # atom, blogger, meta, or lj # atom = Atom API 0.3 # blogger = Blogger # meta = MetaWeblog # lj = LiveJournal 'interface_type' => 'lj', #'interface_url' => 'http://www.livejournal.com/interface/atomapi/atrustheotaku/post', #'interface_url' => 'http://www.livejournal.com/interface/blogger', 'interface_url' => 'http://www.livejournal.com/interface/xmlrpc', # backend-specific options 'blogger_appkey' => '0123456789ABCDEF', 'blogger_blogid' => 'atrustheotaku', 'blogger_publish' => 'true', 'meta_blogid' => 'atrustheotaku', 'meta_publish' => 'true', 'lj_security' => 'friends', 'lj_tags' => 'links', # see http://search.cpan.org/~sbeck/DateManip-5.44/Manip.pod#UnixDate 'dt_format' => '%m/%d/%Y', 'time_format' => '%i:%M %p', 'http_proxy' => '', # xsltproc or libxslt 'xslt_backend' => 'xsltproc', 'style_file' => 'style.xsl', # temp files are only used with xsltproc 'temp1_file' => 'temp1.xml', 'temp2_file' => 'temp2.xml'); use Time::localtime; use Date::Manip; require URI::URL; require XML::LibXML; if($config{'interface_type'} eq 'atom') { require XML::Atom::Client; require XML::Atom::Entry; } elsif(($config{'interface_type'} eq 'blogger') || ($config{'interface_type'} eq 'lj') || ($config{'interface_type'} eq 'meta')) { require RPC::XML; require RPC::XML::Client; } else { die "Unknown interface type '$config{interface_type}'\n"; } if($config{'xslt_backend'} eq 'xsltproc') { # nothing to do } elsif($config{'xslt_backend'} eq 'xsltproc') { require XML::LibXSLT; } else { die "Unknown xslt backend '$config{xslt_backend}'\n"; } my $yyyy = 1900 + localtime->year(); my $mm = sprintf('%02d', localtime->mon()+1); my $dd = sprintf('%02d', localtime->mday()); my $robot = new DeliciousAgent($config{'delicious_username'}, $config{'delicious_password'}); $robot->proxy('http', $config{'proxy'}) if $config{'proxy'}; my $get_url = new URI::URL 'http://del.icio.us/api/posts/get'; $get_url->query("ht=$yyyy-$mm-$dd&tag=" . $config{'delicious_tags'}); my $res = $robot->request(new HTTP::Request 'GET', $get_url); unless($res->is_success) { die "Error while fetching posts:\n ".$res->status_line."\n"; } my $parser = XML::LibXML->new(); my $del_doc = $parser->parse_string($res->content); #my $del_doc = $parser->parse_file('test.xml'); # apply date formatting and create tag nodes if($config{'dt_format'}) { my $format = $config{'dt_format'}; my @nodelist = $del_doc->getElementsByTagName("posts"); for my $postsElm (@nodelist) { my $dt = $postsElm->getAttribute('dt'); $postsElm->setAttribute('dt', trim(UnixDate($dt, $format))); $postsElm->setAttribute('orig_dt', $dt); } } my $format = $config{'time_format'}; my @nodelist = $del_doc->getElementsByTagName('post'); die "Nothing to post today" unless @nodelist; for my $postElm (@nodelist) { if($config{'time_format'}) { my $tim = $postElm->getAttribute('time'); $postElm->setAttribute('orig_time', $tim); chop($tim); $tim = trim(UnixDate($tim, $format)); $postElm->setAttribute('time', $tim); } my $taglist = $postElm->getAttribute('tag'); @taglist = split(/\s+/, "$taglist "); for my $tag (@taglist) { my $newTag = $del_doc->createElement('tag'); $newTag->appendText($tag); $postElm->appendChild($newTag); } } my $post_doc = undef; if($config{'xslt_backend'} eq 'xsltproc') { $del_doc->toFile($config{'temp1_file'}, 0); $retval = system "xsltproc -o \"$config{temp2_file}\" \"$config{style_file}\" \"$config{temp1_file}\""; if($retval) { $retval /= 256; die "xsltproc exited with status $retval"; } $post_doc = $parser->parse_file($config{temp2_file}); } elsif($config{'xslt_backend'} eq 'libxslt') { my $xslt = XML::LibXSLT->new(); my $style = eval "$xslt->parse_stylesheet_file('$config{style_file}')"; die $xslt->get_last_error() unless $style; $post_doc = $style->transform($del_doc); } my @title = $post_doc->getElementsByTagName('title'); my $str = ''; for my $node ($title[0]->childNodes) { $str .= $node->serialize; } $title = $str; my @body = $post_doc->getElementsByTagName('body'); $str = ''; for my $node ($body[0]->childNodes) { $str .= $node->serialize; } $body = $str; #print "$body\n"; if($config{'interface_type'} eq 'atom') { # construct entry my $entry = XML::Atom::Entry->new; $entry->title($title); $entry->content($body); # make post $api = XML::Atom::Client->new; $api->username($config{'blog_username'}); $api->password($config{'blog_password'}); my $ret = $api->createEntry($config{'interface_url'}, $entry); die "Error while posting:\n ".$api->errstr."\n" unless $ret; } elsif($config{'interface_type'} eq 'blogger') { $cli = RPC::XML::Client->new($config{'interface_url'}); $cli->combined_handler(\&xmlrpc_error); $cli->send_request('blogger.newPost', $config{'blogger_appkey'}, $config{'blog_blogid'}, $config{'blog_username'}, $config{'blog_password'}, $body, $config{'blogger_publish'}); } elsif($config{'interface_type'} eq 'meta') { $cli = RPC::XML::Client->new($config{'interface_url'}); $cli->combined_handler(\&xmlrpc_error); $cli->send_request('metaWeblog.newPost', $config{'_blogid'}, $config{'blog_username'}, $config{'blog_password'}, $body, $config{'blogger_publish'}); } elsif($config{'interface_type'} eq 'lj') { $cli = RPC::XML::Client->new($config{'interface_url'}); $cli->combined_handler(\&xmlrpc_error); $args = { 'subject' => $title, 'event' => $body, 'ver' => 1, 'lineendings' =>'unix', 'username' =>'atrus', 'password' =>'something', 'year' => localtime->year()+1900, 'mon' => localtime->mon()+1, 'day' => localtime->mday(), 'hour' => localtime->hour(), 'min' => localtime->min(), 'username' => $config{'blog_username'}, 'password' => $config{'blog_password'}, 'security' => $config{'lj_security'}, 'props' => {}}; $args->{'security'} = 'public' unless $args->{'security'}; if(($args->{'security'} eq 'friends') || ($args->{'security'} eq 'friendsonly') || ($args->{'security'} eq 'allowmask') || ($args->{'security'} eq 'usemask')) { $args->{'security'} = 'usemask'; if($config{'lj_allowmask'}) { $args->{'allowmask'} = $config{'lj_allowmask'}+0; } else { $args->{'allowmask'} = 0; } } $args->{'props'}->{'opt_preformatted'} = 1; $args->{'props'}->{'opt_screening'} = 1 if $config{'lj_screening'}; my $propmap = { 'tags' => 'taglist', 'tag' => 'taglist', 'taglist' => 'taglist', 'mood' => 'mood', 'moodid' => 'moodid', 'pic' => 'picture_keyword', 'userpic' => 'picture_keyword', 'picture' => 'picture_keyword', 'picture_keyword' => 'picture_keyword', 'backdate' => 'opt_backdated', 'backdated' => 'opt_backdated', 'opt_backdated' => 'opt_backdated', 'noemail' => 'noemail', 'noemail' => 'opt_noemail', 'screen' => 'opt_screening', 'screening' => 'opt_screening', 'opt_screening' => 'opt_screening' }; for my $key (keys %$propmap) { if($config{"lj_$key"}) { $args->{'props'}->{$propmap->{$key}} = $config{"lj_$key"}; } } $cli->simple_request('LJ.XMLRPC.postevent', $args); } else { die "Unknown interface type '$config{interface_type}'\n"; } sub trim { my $str = shift @_; $str =~ s/^\s+|\s+$//g; return $str; } sub xmlrpc_error { my $error = shift @_; $error = $error->code . ": " . $error->string; die "Error while posting:\n $error\n"; } package DeliciousAgent; BEGIN{@ISA = qw ( LWP::UserAgent );} sub new { my ($type, $user, $pwd) = @_; my $self = {}; $self->{'username'} = $user; $self->{'password'} = $pwd; bless($self, $type); return $self; } sub get_basic_credentials { $self = shift; return ($self->{'username'},$self->{'password'}); }