Back in December, I commented that I could, with a judicious bit of additional code in the open source GraffitiCMS codebase, accept posts from Posterous and publish them on this blog. Well, it turned out that it wasn't that brilliant a code change: it broke the validation for XHTML. So, this evening, I fixed up the current HTML and took another look at my code.
First of all, let me describe how I envisioned how all this was going to be used. If I'm sitting at my laptop or my main machine, I would continue to use WLW (Windows Live Writer) as my main post editor for this blog, just as I am right now. It makes sense: it's just as quick as writing an email and sending it to Posterous, but with WLW I have more control over things. If I'm away from my main PCs, and I want to post, I can use Gmail on my iPhone or someone else's PC to send an email to Posterous and this would replicate across my social sites, including this blog. Of course, if I also wanted to make sure that a mini blog post hit my Facebook, Twitter, LinkedIn as well as my Posterous blog, I would have to use the email route no matter where I was.
OK, that's the basic scenario: If I want to use Posterous' services, I use Gmail. Otherwise it's WLW all the way, baby.
Rather than use my main user id for GraffitiCMS on this site for my blogs from Posterous, I decided to create a new user and a new category both called "posterous". I would rather not have had to set up a separate category, but I had to, as we'll see in a minute. I also created a role called "posterous" and made sure that this role could only have permissions to the "posterous" category. Overkill, perhaps, but I wanted to limit any damage an external user had on my site. I set up the Posterous configuration for the Autopost to my blog to use this new user.
The first code change, then, was to listen in for blog posts from Posterous and do some fiddling with the data. This is from the newPost()
method in MetaWeblog.cs
:
if (post.categories != null && post.categories.Length > 0) { postToAdd.CategoryId = AddOrFetchCategory(post.categories[0], user).Id; } else if (String.Compare(username, "posterous", true) == 0) { postToAdd.CategoryId = AddOrFetchCategory("posterous", user).Id; postToAdd.PostBody = FixUpPosterousText(postToAdd.PostBody); } else { postToAdd.CategoryId = CategoryController.UnCategorizedId; }
Here you can infer the first problem: no matter what I did I could not get Posterous to send the MetaWeblog interface any category information (ditto tags as well). It seems there's something that might work: Posterous helpfully say that if you put some specially formatted text in your email subject like this, ((tag: tag1, tag2))
, it will use those values as tags. However, my testing shows that this only works for the posts that appears on the Posterous blog, they're not transmitted anywhere else.
In GraffitiCMS 1.2, the post would be automatically rejected as having no category, but as you can see in the open source 1.3 Alpha it gets the uncategorized id by default (I disagree with this change but am riding with it for now). I added my code to check for the posterous user, and set the category to "posterous" automatically if so. Note also that I also fiddle (sorry, "fix up") the post body by calling another method. Why this fix up?
Here's some raw text the MetaWeblog interface gets from Posterous for a simple test post (I added some line breaks to format it better):
<div class='posterous_autopost'> <b>Line 1</b><br /> <b>Line 2</b>, no intervening blank line <p /> <b>Line 3</b>, with intervening blank line <p /> <b>Line 4</b>, with break<br /> continues
</p> <p style="font-size: 10px;"> <a href="http://posterous.com">Posted via email</a>
from <a href="http://jmbucknall.posterous.com/test-post-from-posterous-38">Julian's posterous</a> </p> </div>
It's horrible. Apart from the ending footer (which you can see defined in the Posterous autopost config image above) it's a bunch of naff-looking HTML encased in a <div>
element. And there are those nasty empty <p />
elements as well. No paragraph elements per se, but HTML encodings for links and text formats were coming through fine from Gmail. I have no idea which service is adding those funky empty paragraph elements, but I'm guessing Gmail at this stage.
I decided to do the minimum fixing up possible that would work, so at this point you may validly throw up your hands in horror at the code: yes, it'll break at the merest change from Gmail or Posterous.
public string FixUpPosterousText(string postBody) { // Posterous posts have embedded <p /> for blank lines // They also are embedded in a div with class posterous_autopost var fixedText = postBody.Replace("<p />", "</p><p>"); fixedText = fixedText.Replace("<div class=", "<p class="); fixedText = fixedText.Replace("</div>", ""); return fixedText; }
In essence, replace all those nasty <p />
elements, change the <div>
to a <p>
instead. I left the class name present for future use, although I can't imagine what for at the moment (it's only applied to the first paragraph of course). Another possibility for this method is to extract tag information from the main body of the post from some specially formatted text, but that's a job for another free evening.
Those small changes were enough to produce valid HTML that displayed well with the look and feel on my blog from a (fairly simple) email sent using Gmail to Posterous.
Now playing:
dZihan & Kamien - E.P.A.
(from Music Matters)
2 Responses
#1 suvarna said...
13-Oct-10 2:22 AMNice Blog!!!
Thanks For Great Information .
#2 julian m bucknall said...
15-Feb-13 4:40 PMUPDATE: This particular post is one of the more popular on my blog. However, I will note that it is all for nothing now, as Posterous is being closed down (or will have been closed down) on April 30, 2013. So, all this information is somewhat moot and no longer valid.
Cheers, Julian
Leave a response
Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.
_emphasis_
**strong**
[text](url)
`IEnumerable`
* an item
1. an item
> Now is the time...
Preview of response