# NOTICE: If you see "Can't locate Encode/ConfigLocal.pm in @INC" # then you need to run (as root user on unix): "enc2xs -C" # TODO: feed autodiscovery # TODO: enclosures (MediaRSS?) use strict; my $XML_RSS = album::attempt_require('XML::RSS'); my $XML_RSS = 1; # This plugin generates one feed per album. Thus,someone can subscribe to sub-albums in an album # i.e. if you have a multi-person album or something. my_end_album is where we do our work. # This function gets called as the recursive do_album function is unwinding, so we're working # from leaf nodes back up the tree. What we do is collect up items left to us by our child nodes, # add our items, write it out to the feed, and leave this collection for our (potential) parent # node. # Definitions: # Item: A single entry in an RSS feed. Could be a whole album or could be a single image, # depending on configuration. my ($SINCE, $ITEMS); sub start_plugin { my ($opt, $plugin, $path) = @_; my $ret = { author => 'Jason Dufair', href => 'http://www.dufair.org/', version => '0.1', description => "Generates an rss feed for recently added/updated albums and images", }; unless ($XML_RSS) { my $err = "XML::RSS is required and not installed!\n"; print STDERR "\n[Plugin: $plugin] $err\n"; $ret->{description} .= "\n$err"; return $ret; } ################################################## # OPTIONS ################################################## album::add_option(1, 'numberOfDays', album::OPTION_NUM, default=>30, usage=>"Include images up to this many days old"); album::add_option(1, 'title', album::OPTION_STR, usage=>"The album's RSS feed title"); album::add_option(1, 'language', album::OPTION_STR, default=>'en-us', usage=>"The album's RSS feed language"); album::add_option(1, 'description', album::OPTION_STR, usage=>"A short description of the album's RSS feed"); album::add_option(1, 'creator', album::OPTION_STR, usage=>"The creator of the album's RSS feed"); album::add_option(1, 'publisher', album::OPTION_STR, usage=>"The publisher for the album's RSS feed"); album::add_option(1, 'feedImage', album::OPTION_STR, usage=>"The URL to an image associated with the whole album"); album::add_option(1, 'feedFilename', album::OPTION_STR, default=>'index.rdf', usage=>"The name of the file containing the XML for the feed"); album::add_option(1, 'feedBase', album::OPTION_STR, usage=>"The URL that points to your album's top folder (no trailing slash)"); album::hook($opt,'end_album', \&my_end_album); $ret; } sub create_feed { my ($opt, $rss, $dir) = @_; my $feedBase = album::option($opt, 'feedBase'); $rss->channel(title => album::option($opt, 'title') | "No title", link => "$feedBase$dir/index.html", description => album::option($opt, 'description') || "No description given", dc => {creator => album::option($opt, 'creator'), publisher => album::option($opt, 'publisher'), language => album::option($opt, 'language')}); $rss->image(title => album::option($opt, 'title'), url => album::option($opt, 'feedImage'), link => "$feedBase$dir/index.html") if album::option($opt, 'feedImage'); } sub get_items_left_by_children { my ($data) = @_; return $ITEMS->{$data->{paths}{album_path}} || []; } sub add_local_images { my ($opt, $data, $dir, $albumItems, $itemCount) = @_; my $description = ""; my $album_url = album::option($opt, 'feedBase') . "/" . $data->{paths}{album_path} . "/"; my $imageCount = 0; for(my $i=0; $i<=$#{$data->{pics}}; $i++) { my $pic = $data->{pics}[$i]; my $picModTime = (stat("$dir/$pic"))[9]; next if $picModTime < $SINCE; my $obj = $data->{obj}{$pic}; my $name = $obj->{name}; $description .= "{URL}{album_page}{image}) . "'" . ">{URL}{album_page}{thumb}) . "'" . " />
$name


\n"; $imageCount++; } $description .= "]]>"; my $itemModTime = (stat($dir))[9]; if ($imageCount) { push(@$albumItems, ({title => $data->{paths}{album_path}, #TODO: make this more friendly link => $album_url, description => $description, modTime => $itemModTime})); $$itemCount++; } } sub write_items_to_feed { my ($rss, $albumItems) = @_; foreach my $item (sort { $a->{modTime} cmp $b->{modTime} } @$albumItems) { $rss->add_item(title => $item->{title}, link => $item->{link}, description => $item->{description}); } } sub save_items_for_parent { my ($data, $albumItems) = @_; my $parent = join('/', @{$data->{paths}{parent_albums}}[0..@{$data->{paths}{parent_albums}} - 2]); $ITEMS->{$parent} = [] if (!$ITEMS->{$parent}); foreach my $item (@$albumItems) { push(@{$ITEMS->{$parent}}, ($item)); } delete $ITEMS->{$data->{paths}{album_path}}; } sub save_feed { my ($opt, $rss, $dir) = @_; my $feedFilename = album::option($opt, 'feedFilename'); $rss->save("$dir/$feedFilename"); } sub my_end_album { my ($opt, $data, $hookname, $dir, $album) = @_; my $numberOfDays = album::option($opt, 'numberOfDays'); $SINCE = time() - ($numberOfDays * 24 * 60 * 60); my $rss = new XML::RSS (version => '1.0'); create_feed($opt, $rss, $dir); my $albumItems = get_items_left_by_children($data); my $itemCount = @$albumItems; add_local_images($opt, $data, $dir, $albumItems, \$itemCount); write_items_to_feed($rss, $albumItems); save_items_for_parent($data, $albumItems); save_feed($opt, $rss, $dir); my $w = $opt->{hash_width} - $opt->{num_hashes} - 3 - 8; my $album = $data->{paths}{album_path}; my $p = (length($album) >= $w) ? '..'.substr($album,-$w+3) : $album; album::start_hashes($opt, "RSS : $p"); print "$itemCount new or updated album"; print "s" if ($itemCount != 1); print "\n"; } 1;