#!/usr/bin/perl # # MyRSSMerger - read multiple RSS feeds, post new entries to Movable Type. # http://disobey.com/d/code/ or contact morbus@disobey.com. # # This code is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # 1.1 (2004-11-19) # * Moved date routines to Date::Manip. # * Quickie hack to support 2.0's . # # 1.0 (2003-05-27) # * Initial release. # use warnings; use strict; $|++; my $VERSION = "1.1"; use Date::Manip; use Getopt::Long; my %opts; # make sure we've got the modules we need, else die peacefully. eval("use LWP::Simple;"); die "[err] LWP::Simple is not installed.\n" if $@; eval("use Net::Blogger;"); die "[err] Net::Blogger is not installed.\n" if $@; eval("use XML::RSS;"); die "[err] XML::RSS is not installed.\n" if $@; # define our command line flags (long and short versions). GetOptions(\%opts, 'server|s=s', # the POP3 server to use. 'username|u=s', # the POP3 username to use. 'password|p=s', # the POP3 password to use. 'blogid|b=i', # unique ID of your blog. 'catid|c=i', # unique ID for posting category. 'showcategories', # list categories for blog. 'filter|f=s', # per item filter for posting? ); # at the very least, we need our login information. die "[err] XML-RPC URL missing, use --server or -s.\n" unless $opts{server}; die "[err] Username missing, use --username or -u.\n" unless $opts{username}; die "[err] Password missing, use --password or -p.\n" unless $opts{password}; die "[err] BlogID missing, use --blogid or -b.\n" unless $opts{blogid}; # every request past this point requires # a connection, so we'll go and do so. print "-" x 76, "\n"; # visual separator. my $mt = Net::Blogger->new(engine=>"movabletype"); $mt->Proxy($opts{server}); # the servername. $mt->Username($opts{username}); # the username. $mt->Password($opts{password}); # the... ok. self- $mt->BlogId($opts{blogid}); # explanatory! # show existing categories. if ($opts{showcategories}) { # get the list of categories from the server. my $cats = $mt->mt()->getCategoryList() or die "[err] ", $mt->LastError(), "\n"; # and print 'em. if (scalar(@$cats) > 0) { print "The following blog categories are available:\n\n"; foreach (sort { $a->{categoryId} <=> $b->{categoryId} } @$cats) { print " $_->{categoryId}: $_->{categoryName}\n"; } } else { print "There are no selectable categories available.\n"; } # done this request, so exit. print "\nCategory ID's can be used for --catid or -c.\n"; print "-" x 76, "\n"; exit; # call me again, again! } # now, check for passed URLs for new-item-examination. die "[err] No RSS URLs were passed for processing.\n" unless @ARGV; # loop through each RSS URL. foreach my $rss_url (@ARGV) { # download whatever we've got coming. print "Downloading RSS feed at ", substr($rss_url, 0, 40), "...\n"; my $data = get($rss_url) or print " [err] Data could not be downloaded!\n"; next unless $data; # move onto the next URL in our list, if any. # parse it and then # count the number of items. # move on if nothing parsed. my $rss = new XML::RSS; $rss->parse($data); my $item_count = scalar(@{$rss->{items}}); unless ($item_count) { print " [err] No parsable items.\n"; next; } # sandwich our post between a preface/anteface. my $clink = $rss->{channel}->{"link"}; # shorter variable. my $ctitle = $rss->{channel}->{title}; # shorter variable. my $preface = "From $ctitle:\n\n
"; my $anteface = "
\n\n"; # new items as quotes. # and look for items dated today. foreach my $item (@{$rss->{items}}) { # no description or date for our item? move on. unless ($item->{description} or $item->{dc}->{date}) { print " Skipping (no description/date): '$item->{title}'.\n"; next; } # compare the item's date with today's date. my $date = $item->{dc}->{date} || $item->{pubDate}; my $rss_date = UnixDate($date, '%s'); my $right_now = UnixDate('today', '%s'); my $timeframe = $right_now - $rss_date; # and post if it's within an hour. if ($timeframe <= 86400) { # shorter variable. we're lazy. my $creator = $item->{dc}->{creator}; # if there's a filter, check for goodness. if ($opts{filter} and $item->{description} !~ /$opts{filter}/i) { print " Skipping (failed filter): '$item->{title}'.\n"; next; } # we found an item to post, so make a # final description from various parts. my $description = "$preface$item->{description} "; $description .= "($creator) " if $creator; $description .= "{link}\">Read " . "more from this post.$anteface"; # now, post to the passed blog info. print " Publishing item: '$item->{title}'.\n"; my $id = $mt->metaWeblog()->newPost( title => $item->{title}, description => $description, publish => 1) or die "[err] ", $mt->LastError(), "\n"; # set the category? if ($opts{catid}) { $mt->mt()->setPostCategories( postid => $id, categories => [ {categoryId => $opts{catid}}]) or die " [err] ", $mt->LastError(), "\n"; # "edit" the post with no changes so # that our category change activates. $mt->metaWeblog()->editPost( title => $item->{title}, description => $description, postid => $id, publish => 1) or die " [err] ", $mt->LastError(), "\n"; } } else { print " Skipping (failed date check): '$item->{title}'.\n"; } } print "-" x 76, "\n"; # visual separator. } exit;