{ =head1 NAME Net::Blogger::API::Extended - provides helper methods not defined in the Blogger API. =head1 SYNOPSIS It's very dark in here because this is a black box. =head1 DESCRIPTION This package is inherited by I and provides helper methods not defined in the Blogger API. =cut package Net::Blogger::API::Extended; use strict; $Net::Blogger::API::Extended::VERSION = '1.0'; @Net::Blogger::API::Extended::ISA = qw ( Exporter ); @Net::Blogger::API::Extended::EXPORT = qw (); @Net::Blogger::API::Extended::EXPORT_OK = qw (); use Exporter; use FileHandle; =head1 OBJECT METHODS =head2 $pkg->MaxPostLength Abstract method for returning the max post length =cut sub MaxPostLength { return undef; } =head2 $pkg->GetBlogId(\%args) Return the unique blogid for I<$args{'blogname'}>. Valid arguments are =over =item * B => string. =back Releases prior to Net::Blogger 0.85 accepted a list of arguments rather than a reference. Version 0.85+ are backwards compatible. Returns a string. If no blogname is specified, the current blogid for the object is returned. =cut sub GetBlogId { my $self = shift; my $args = (ref($_[0]) eq "HASH") ? shift : { @_ }; my $blogid = undef; if (! $args->{'blogname'}) { return $self->{'_blogid'}; } my $blogs = $self->getUsersBlogs() || return undef; foreach my $b (@$blogs) { if ($b->{'blogName'} eq $args->{'blogname'}) { $blogid = $b->{'blogid'}; last; } } return $blogid; } =head2 $pkg->DeleteAllPosts(\%args) Delete all the posts on a weblog. Valid arguments are : =over 4 =item * B Boolean. =back Releases prior to Net::Blogger 0.85 accepted a list of arguments rather than a reference. Version 0.85+ are backwards compatible. Returns true or false. =cut sub DeleteAllPosts { my $self = shift; my $args = { @_ }; my ($ok,@pids) = $self->getRecentPosts(numposts=>20); while (@pids) { foreach my $p (@pids) { $self->deletePost(postid=>$p->{'postid'},publish=>$args->{'publish'}); } ($ok,@pids) = $self->getRecentPosts(numposts=>20); } return $ok; } =head2 $pkg->PostFromFile(\%args) Open a filehandle, and while true, post to Blogger. If the length of the amount read from the file exceeds the per-post limit assigned by the Blogger servers -- currently 65,536 characters -- the contents of the file will be posted in multiple "chunks". Valid arguments are =over =item * B /path/to/file I =item * B String. =item * B Boolean. =item * B Boolean. If true, the method will not attempt to post data whose length exceeds the limit set by the Blogger server in the order that the data is read. Translation : last in becomes last post becomes the first thing you see on your weblog. =back If a I argument is present, the method will call the Blogger API I method with postid. Otherwise the method will call the Blogger API I method. Releases prior to Net::Blogger 0.85 accepted a list of arguments rather than a reference. Version 0.85+ are backwards compatible. Returns true or false, followed by an array of zero, or more, postids. =cut sub PostFromFile { my $self = shift; my $args = (ref($_[0]) eq "HASH") ? shift : { @_ }; if (! -f $args->{'file'}) { $self->LastError("Not a file."); return 0; } my $fh = FileHandle->new(); my $ok = $fh->open("<$args->{'file'}"); if (! $ok) { $self->LastError("Failed to open file : $!"); return 0; } my $method = ($args->{'postid'}) ? "editPost" : "newPost"; if (! $args->{'tail'}) { local $/; undef $/; my $postbody = <$fh>; $fh->close(); return $self->$method(postbody=>\$postbody,%$args); } my $post = ""; my @postids = (); while (<$fh>) { my $line = $_; chomp $line; $post .= $line; my $len = length($post); if (($self->MaxPostLength()) && ($len > $self->MaxPostLegth())) { my $postbody = substr($post,0,$self->MaxPostLength()); my $remainder = $self->_TrimPostBody(\$postbody); my ($pid) = $self->$method( postbody => \$postbody, postid => $args->{'postid'}, publish => $args->{'publish'}, ); if (! $pid) { $fh->close(); $self->LastError("Encountered an error posting. Exiting prematurely."); return (0,@postids); } push(@postids,$pid); $post = $remainder.substr($post,$self->MaxPostLength(),$len); } } $fh->close(); if (! $post) { $self->LastError("Failed to read any data from file."); return 0; } my ($pid) = $self->$method( postbody => \$post, postid => $args->{'postid'}, publish => $args->{'publish'}, ); if (! $pid) { $self->LastError("Encountered an error posting last chunk : ".Error->prior()); return (0, @postids); } push (@postids,$pid); return (1,@postids); } =head2 $pkg->PostFromOutline(\%args) Like I, only this time the file is an outliner document. This method uses Simon Kittle's Text::Outline::asRenderedHTML method for posting. As of this writing, the Text::Outline package has not been uploaded to the CPAN. See below for a link to the homepage/source. Valid outline formats are OPML, tabbed text outline, Emacs' outline-mode format, and the GNOME Think format. Valid arguments are =over =item * B /path/to/file I =item * B String. =item * B Boolean. =back If a I argument is present, the method will call the Blogger API I method with postid. Otherwise the method will call the Blogger API I method. Releases prior to Net::Blogger 0.85 accepted a list of arguments rather than a reference. Version 0.85+ are backwards compatible. Returns true or false, followed by an array of zero, or more, postids. =cut sub PostFromOutline { my $self = shift; my $args = (ref($_[0]) eq "HASH") ? shift : { @_ }; my $class = "Text::Outline"; # We'll get rid of this when, and if, a proper # Makefile is ever written... eval "require $class" || &{ $self->LastError($@); return 0; }; my $outline = $class->new(load=>$args->{'file'}) || &{ $self->LastError($!); return 0; }; my $postbody = $outline->asRenderedHTML(); my $method = ($args->{'postid'}) ? "editPost" : "newPost"; return $self->$method(postbody=>\$postbody,%$args); } sub _PostInChunks { my $self = shift; my $args = (ref($_[0]) eq "HASH") ? shift : { @_ }; my $caller = (caller(1))[3]; my @chunks = (); my @postids = (); unless ($caller =~ /^(Net::Blogger::Base::API::)(editPost|newPost)$/) { $self->LastError("$caller is not a valid caller for this method."); return 0; } my $text = $args->{"postbody"}; while ( $$text ) { my $chunk = substr($$text,0,$self->MaxPostLength()); my $remainder = $self->_TrimPostBody(\$chunk); $$text = $remainder.substr($$text,length($chunk),length($$text)); # Since Blogger posts are chronological, we add chunks # to the top of the stack. That way, the 'end' pieces get # added first and, in the end, the text will be displayed # in the order it was written. # 20010813 (asc) unshift (@chunks, \$chunk); } map { $args->{"postbody"} = $_; push(@postids, $self->$caller(%$args)); } @chunks; return @postids; } sub _TrimPostBody { my $self = shift; my $body = shift; if (ref($body) ne "SCALAR") { $self->LastError("Input must be a scalar ref."); return undef; } } =head1 VERSION 1.0 =head1 DATE $Date: 2005/03/26 19:29:08 $ =head1 AUTHOR Aaron Straup Cope =head1 SEE ALSO L L =head1 LICENSE Copyright (c) 2001-2005 Aaron Straup Cope. This is free software, you may use it and distribute it under the same terms as Perl itself. =cut return 1; }