Flickrtweeter: automatically tweet your flickr pics

A few weeks ago I decided to roll my own script to automatically twitter an update if I posted a photo onto my flickr pages with a certain tag.  I know that there are third party services out there that can do this for you (e.g. Snaptweet, Twittergram) but I thought it’d be an interesting project to do it myself.  As well as (obviously) requiring flickr and twitter accounts, it also requires a bit.ly account and API key as it uses this service to produce a shortened URL for the photo to include in the tweet.

The script is written in Perl and is fairly straitforward.  It pulls the Atom feed of my flickr account and checks any photos tagged “twitme” against a list of photos it has already seen and tweeted.  It then passes the photo’s URL through bit.ly to get a shortened version and builds a tweet using a standard prefix, the photo’s title from flickr, and the bit.ly’ified URL.  It then attempts to post the tweet.

The script uses LWP::Simple for HTTP GETs to flickr and bit.ly, XML::Simple to parse the responses, Storable to maintain a cache file of seen photos, Net::Twitter to talk to twitter itself and URI::Escape to escape the photo’s URL before passing it to bit.ly.  It also uses the sysopen call from Fcntl to manage a lockfile – I run it as a cron job so this seemed a sensible precaution.

It can be configured by setting variables at the start of the script.  All are commented (I hope) reasonably clearly.  It can be downloaded and used under the terms of the GNU Public License.  I originally called it flickr2twitter but as this appears to be the name of a Firefox Addon I have renamed it flickrtweeter.

Basic version control with wikieditish

At the St Werburghs Community Centre, we use Blosxom to power our website. As the other staff needed to be able to update and add content quickly and with the minimum of fuss, I combined the wikieditish plugin with TinyMCE and a couple of other scripts to create a simple rich-text web interface to the site.

During testing and the initial setup period, it became apparent that having the ability to roll an entry back to its original state after a dodgy edit would be a useful feature, so I added a few lines of code to wikieditish that supports a very simple kind of version control: every time a change is made, the plugin saves a copy of the current state of the post into a backup file. This file is over-written each time so you can only revert to the last saved version, but this allowed staff some scope for experimentation with the knowledge that they could undo any serious mistakes quickly.

I thought that I’d make this version of the plugin available here in case any other blosxom users might find it useful, so download wikieditishvc.zip, which contains the plugin and some basic flavour templates. I have not renamed the plugin itself, it is still simply named wikieditish, but I’ve added a bit of extra documentation and updated the version number to differentiate it. The version control behaviour is all optional and is off by default.

Atom 1.0 Support for Blosxom

Here is an updated atomfeed plugin that supports Atom 1.0: download atomfeed.

Changes since the last beta version:

  • Moved variable configuration to head sub
  • Added simple entity-unescaping in generation of the element
  • Adjusted the xml:base attribute to reflect $id_domain rather than $blosxom::url, and added the attribute at feed-level as well as for each entry

This plugin offers basic support for most of the specification, which should be enough for the vast majority of users. Not currently supported are the and elements. has been excluded as it seems an element more aimed at those publishing feeds aggregated from other feeds. probably could be supported, but would have been a bit of a kludge without the use of metadata – so anyone who needs this element could use the meta plugin and a custom template.

Of course, Atom is designed to be flexible and extensible and there are already people out there imagining losts of uses for the format – see this article at IBM Developer Works for some ideas (via Tim Bray). This plugin can never hope to cater for all possible uses, but it should be enough to provide the bare bones that others can build upon to meet their own needs.

The plugin comes with flavour templates and extensive documentation, including a list of all the variables it makes available for use in templates, notes on compatibility issues with other plugins and suchlike. I’ve extracted some of the major points below, but see the plugin itself for more complete notes.

  • The plugin has a large number of configurable variables and generates an even larger number of template variables. However, it is designed to be usable with only minimal configuration: set the variables $default_author and $feed_yr, drop the plugin into your $plugins_dir and off you go.
  • The plugin is intended to work with nothing but blosxom.cgi and a standard perl installation, but it will perform better if the XML::Parser and LWP modules are installed, and if you are using a plugin like entries_cache that stores the creation times of your posts.
  • If you are modifying the content of your entries using other plugins, particularly any that escape characters or add markup (like some of these), you should have them run before the atomfeed plugin. You want atomfeed to get each post in the state that it would be sent to a normal web browser.
  • Similarly, if you intend to use the config or prefs plugins to modify any of the variables generated by the plugin, they will need to run before it.
  • Podcasters: enclosures are supported. You need to link to your enclosure in the body of your weblog post, and provide the anchor tag with a rel attrubute of “enclosure”. For example: <a rel="enclosure" href="http://example.com/podcasts/august-05.mp3">Podcast for 5th August</a>. If you have the LWP module and you change the $use_full_enclosures configurable variable to “1”, the plugin will also include data on the length and content type of the enclosure (this is recommended as good practice).
  • You can include “related” and “via” links using a similar method – just ensure the anchor tags have an appropriate rel attribute for these links to be included in your feed as corresponding s.

Please post any feedback you have to the blosxom mailing list, maybe as a follow-up to this post.

Beta support for Atom 1.0 in blosxom

atomfeed released!

It’s finished! See this post for more information, docs and download.

atomfeed-beta-6

Download: atomfeed-beta-6

This is now pretty much ready for release: just a last check for suggestions and bugs. It now supports the whole spec apart from , which seems aimed at aggregators rather than bloggers, and , which could easily be implemented if desired using the meta plugin.

Changes:

  • Moved from using class to rel attributes in HTML anchors to identify enclosure/via/related links to include in the feed. Just use the appropriate rel value – there’s no need to include the “atom-” prefix any longer.
  • Support for
    . This uses a technique similar to that used by the foreshortened plugin. It is excluded from the default templates in favour of a full-text element. I’ve temporarily placed the

    inside a comment in my feed if you’re interested in how it looks.
  • and are now available as user-configurable variables.
  • Documentation is now included in the plugin – use perldoc or read directly.
  • Includes support for a stylesheet, like in the original 0.3 version. Excluded by default. You can also specify the MIME tpye of the stylesheet.

As before, comments to the mailing list please.

atomfeed-beta-5

Download atomfeed-beta-5

Changes in this version: support for rel attributes in elements, including enclosures (based on Dave Slusher‘s and Keith Irwin‘s enclosures plugin for RSS 2).

  • enlcosure: In the body of your post, link to a file you would like to appear in your atom feed as an enclosure. Make sure this link has a class attribute of “atom-enclosure”. For extra points: if you have access to the LWP perl module, set the configurable variable $use_full_enclosures to “1” and atomfeed will attempt to find the content-type and length of your enclosure. (Test: This little audio file should appear in my post as an enclosure. The code for this link looks like this: This little audio file)
  • via: To include a link from your post in your atom feed as , give it a class attribute of “atom-via”
  • related: similar to via, simply give a link a class attribute of “atom-related” for it to appear in your atom feed as an appropriate element.

Note: using the class attribute to identify these links may change in future versions.

atomfeed-beta-4

Download atomfeed-beta-4

Changes in this version (also posted to mailing list) based on suggestions from Stu MacKenzie:

  • typo corrected
  • XML::Parser is now a require rather than a use – those who don’t have this module can now use the plugin with the consequence that their entries will never be labelled as xhtml, only text or html, regardless of validity/well-formedness.
  • Regular expression for guessing text vs. mark-up is now: m!! This should hopefully catch pretty much anything that resembles mark-up.
  • The check in the start() sub for preloaded templates is now or‘d with the call to _load_templates. I’m not even sure if this check is necessary, as it doesn’t appear possible for any user-defined templates to have been loaded by this stage anyway, unless someone else knows better?

Major Revision: atomfeed-beta-3

Since posting this entry, I have made a number of changes to the plugin. It now contains support for the following additional elements:

  • and for

Also, it checks $blog_title, $blog_description and each post’s $title for markup by looking for left-side angle brackets anything matching the regular expression /<[a-zA-Z0-9]+>/. If it finds a match, it assumes that the variable contains markup and parses it as such, labelling it either html or xhtml depending on well-formedness.

You can download the new version here. The link below continues to point to the original version. Documentation is still not finished, but the code is commented. I’m particularly interested in feedback on the _parse_markup subroutine.

Original post

I’ve updated the atomfeed plugin for Blosxom to emit a basic Atom 1.0 feed. It’s in beta; you can download it here. I’m running the plugin, so if you like you can see it in action by checking my Atom feed; the feed’s been checked with feedvalidator.org‘s new Atom 1.0 support. Here are the notes I posted to the blosxom mailing list:

The feed is very basic: only the required elements along with a feed-level pointing at the feed, a based on $blog_description, a element (updated 2005-07-21, but it was always in there), and each has a as well as an element.

I have not yet updated documentation in the plugin. I’m making it available so that anyone interested can take a look and make suggestions before I start looking at adding more support for optional elements and doing some other bugfixes. When I’m happy with it I’ll re-write the docs, remove the BETA flag and post some instructions on my site. Until then, use these notes as guidance if you want to use or test the plugin:

  • $feed_yr is now a configurable variable that MUST to be set to the year you want to see in your feed level element. This should be set once and then never changed.
  • is derived from the timestamp in %blosxom::files, and (entry level) is derived from a stat()->mtime on the actual file. For these two elements to work as intended, you really should be running entries_cache or similar, otherwise they will be the same.
  • entry level ‘s are derived from %blosxom::files. Again, for maximum conformance – to guarantee the tags never change – is currently to use entries_cache or similar.
  • I decided not to worry about sniffing for plaintext entries as it seems to me that most blosxom users will have markup in their entries, so the mechanism for determining the type of has remained bascially the same (UPDATED – see below).
  • I am still assuming that $blog_title and $blog_description contain only plaintext and no mark-up whatsoever.
  • the feed-level element must appear before the s, so I’ve taken the method used in the rss10 plugin to insert it in $blosxom::output in the foot subroutine using a placeholder.

Update 2005-07-21 (1)

I’ve removed the code that conditionally placed some HTML content into a CDATA section. ALL content identfied as HTML will now be escaped.

Feedback

Please direct comments to the blosxom mailing list.

Hide plugin and date-based URLs

The hide plugin allows you to conceal certain posts and/or categories from the standard blosxom index pages – this works for either path or date based URLs. A side effect of this is that if you are using date-based links like me – http://example.com/YYYY/MM/DD/filename – then the posts won’t show up when you visit their permalinks – they’ll only display when referenced with a URL like http://example.com/path/to/filename.flavour.

A solution is to add quick test to the start subroutine in the hide plugin that checks to see whether blosxom knows about any date-based path information:

sub start {
  $blosxom::path_info_yr and return 0;
  ...

As I don’t want posts in about/ to display in the monthly archives, I used the $path_info_da variable, but you could just as easily use $path_info_yr or $path_info_mo instead to allow the posts to display on less specific date-based index pages.

Stripping out <script> tags from RSS feeds

It’s good practice not to include <script> tags inside your RSS feeds, and feedvalidator.org will react if you include them, so here’s a plugin that will do this for you.

By default, the plugin will attempt to strip <script> tags from the $body of your posts when $blosxom::flavour equals “rss”. This is configurable, of course.

Note that the plugin is not designed as a security precaution and so the regular expression used to try and find the tags isn’t particularly sophisticated. It is case-insensitive but expects to find the actual tags themselves to be unbroken by white space or line breaks, however the contents of the tags can be arranged in any way you please.

Auto escaping HTML in RSS with blosxom

Out of the box, blosxom comes with simple HTML and RSS formats built in. In order to get the RSS 0.91 feed set-up correctly, blosxom escapes HTML tags during the story generation phase where is finds an XML content-type (specifically: $content_type =~ m{\Wxml$}).

This feature is fine until you start experimenting with your RSS feeds when it can become a bug. For example, if you decide to provide the full text for each story in a feed enclosed in a CDATA section, you don’t want this escaping to take place. So I recommend that you move the escaping section from blosxom itself and place it into a plugin where you can then call it if you need it.

The escaping code is lines 378-384 in the standard blosxom 2.0 script. Just for fun I’ve made a patch, but it’s probably simpler to just open a text editor and do it by hand. Here’s a simple plugin that allows you to control whether or not the code is called during the story generation phase.

Untainting blosxom

If you want to run Blosxom in taint mode (using the -T switch), you’ll hit some problems with 2.0 as it comes out of the box. Joe Landman posted a patch dealing with one issue on the mailing list over the weekend, but if you’re using any plugins then you’ll immediately encounter another problem when blosxom does a readdir() on your $plugins_dir. Here’s a patch that solves both these issues.

blosxom plugin: altlinks

This is a trivial plugin I wrote to scratch a bit of an itch. It had always slightly annoyed me that while blosxom itself was designed to use the filesystem hierarchy as its structure and allowed you to view pages based on their position in the hierarchy, there was no simple method to include alternate <link>s to syndication feeds or alternative flavours that mirrored a visitor’s position. Hence altlinks.

Currently, the plugin works for path-based views right the way down to individual story pages, but date-based paths are ignored completely – the href attribute will be formed from whatever path information is available in the requesed URL. That is, if you request http://yourblog.net/path/2003/10, the alternate will have an href attribute pointing to http://yourblog.net/path/index.flavour. I originally thought this wouldn’t matter, but I suppose for the sake of completeness I should I add this at some time. When I get around to it, I will post an updated version here.

I wasn’t going to post this code at all, particularly since it’s not quite finished, but then I thought it might be useful to someone somewhere sometime, so here it is. The plugin provides three variables for use in templates, allows the user to specify which flavours these variables point to, and contains full documentation.

Transforming <foaf:mbox> to <foaf:mbox_sha1sum>

Recently I added a number of people into my FOAF file. At first I included their email addresses in plaintext using the property, but I decided that this wasn’t really acceptable for several reasons so decided to switch to using the obscured property instead.

Instead of calculating the SHA 1 digests of all the email addresses separately and pasting them into the file, I wrote a simple Perl script to go through it and do it all automatically. It occurred to me that this might be useful to someone else one day, so here it is. The script includes some documentation in POD format.

There are snippets of code from various programming languages for creating SHA 1 digests available from Sam Ruby’s website, which helped by pointing me towards the module I needed for the program. For more about FOAF, visit the FOAF Project website.