home > notes > Lazy Mac OS X: Weblog links sidebar
v1.0 2003-01-13: First public version; pre editing
By Matt Webb.
One of the joys of Mac OS X is that it's possible to tinker and make useful things without being an expert. By finding out just enough about some concepts in any task, you're usually able to make something that's Good Enough with very little code and very little trouble.
So that's what I'm writing about: Each article we'll make something vaguely useful, and take in some of the sights of OS X along the way. If you know a little, but not a lot, and you like getting your hands dirty, this is for you.
And to begin with, it's going to be about turning your Mac into a weblogging machine. As easy as the links-and-commentary genre is with all the blogging apps out there, I'm too lazy for the commentary bit, and so I tend to drag-and-drop links to my desktop for later posting -- and then promptly forget about them. Consequently my desktop is a mess, and my blog is stagnating. Bad.
Fortunately, a list of naked links is a popular form for a blog sidebar (see Anil Dash's Daily Links, LinkMachineGo's sidebar, Kottke's weekly remainders). I'd like one of those, so I could update my blog links sidebar completely automatically. That's today's task. (And you can see the result - the Mini Links on Interconnected.)
and it's probably best to be up-to-date with Mac OS X 10.2.3.
First things first, what are those files that appear if you drag a link to a folder or the desktop?
If you drag from an application such as Chimera (excellent web browser of choice), Apple's Safari, NetNewsWire (reading weblogs the lazy way) or BBEdit then it's an Internet Location File.
If you drag from Internet Explorer, then the file you get isn't an Internet Location File. It's a document type specific to Internet Explorer, and not so easy to play around with. So if you're a user of this browser, we'll have to leave you for the moment, and pick up support of IE again another time.
Internet Location Files can store any one of seven types of location, including web, FTP, and email addresses. If you double-click on one, it'll open in whichever application you've listed as default for that type in System Preferences.
Handily, this means they're an Apple standard file type and simple to deal with.
Internet Location Files are a generic class of file for a bunch of different file types: Web Internet Location, FTP Internet Location, and so on.
The class has been around since Mac OS 8.5, when there were eight different types.
You can see the icons for the various types in your System folder. Have a look in:
/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources/
and open the seven files that begin with "InternetLocation" in Preview. It's probably safest not to play around with these however.
AppleScript is a built-in, easy to learn language for automating tasks on your Mac. What I don't like about it is that its power comes from how much applications let you do, so the documentation isn't centralised. But what I do like about it is that once you know where to look, it becomes very easy.
As I said, I'm not an expert. But AppleScript is the kind of language where you can't (accidentally!) do much damage, so it's fun to play.
First we open the Script Editor, at
/Applications/AppleScript/Script Editor
and type in the following code:
tell application "Finder"
set these_items to the selection
end tell
repeat with i from 1 to the count of these_items
set this_item to (item i of these_items)
set this_class to class of this_item
display dialog this_class as string
end repeat
Then select one or more file in the Finder, and hit Run. The class of the file (or files) is displayed in dialog boxes. We'll be able to make use of this later.
I'm not going to explain too much about the syntax of AppleScript because it's fairly readable, and reasonably easy to find out how to do things by experimenting and reading the examples.
Example scripts are in
/Applications/AppleScript/Example Scripts/
O'Reilly's book Applescript in a Nutshell has a good, short chapter on the syntax of the language, and covers the basics nicely.
To find out particulars about the language, you'll have to look in the Dictionaries offered by various applications. For example, although there are some file functions built in, the Finder offers a lot more.
In the Script Editor, choose Open Dictionary from the File menu and open the Finder dictionary.
I find these two are the ones I consult most frequently.
In the Finder Dictionary, we can see the different file classes that the Finder offers: alias files, document files, internet location files and so on. In the above script, when we asked for the class of the item in the section, this is what came back.
Different classes have different properties we can access. location is listed in the properties for Internet Location Files in the Finder dictionary, so change the script to
tell application "Finder"
set these_items to the selection
repeat with i from 1 to the count of these_items
set this_item to (item i of these_items)
set this_class to class of this_item
display dialog this_class as string
if this_class is internet location file then
set this_location to location of this_item
display dialog this_location
end if
end repeat
end tell
This script will pop the location held within an Internet Location File in a dialog box if the file is of the correct type.
(The tell has been expanded around all of the script because the class internet location file belongs to the Finder only, and so the processing has to be done in that application.)
We'll make use of this property later.
Along with the Finder Dictionary, the Standard Additions and System Events Dictionaries are where what most of what we need is hidden.
Incidentally, AppleScript isn't the only way to get access to the location of this type of file. I'm more comfortable with Unix, so the first method I tried was the strings command-line tool that comes with Mac OS X. In the Terminal (in /Applications/Utilities/), type this:
strings mi.webloc/rsrc | grep ':' | sed 's/^.//' | tail -n1
Where:
So there's more than one way to do it, even if I can't think of a situation where this would be useful.
Okay, so we know how to get the URL out of an Internet Location File. How to post it to a weblog?
(The idea being, of course, that the list of links is a weblog that generates an HTML fragment that can be included in our main page, either by server-side includes, PHP, or some other means.)
XMLRPC is a way of doing procedure calls over the internet. Sites can offer functionality as web services, and applications can do things on the web automatically without us having to go near a web browser. Kind of like AppleScript on the web.
Blogger allow new posts, the editing of posts and a little more functionality by XMLRPC, and the Blogger API has been adopted by a number of different blogger servers, including Blogger itself, Movable Type, and many others:
That first link is the Blogger API specification itself.
AppleScript has the ability to talk XMLRPC itself, so it's a simple matter to post direct from the script. An ideal fit.
To use the blogger.newPost method, you'll need a bunch of information. We'll start with Blogger, then you can move on to your preferred application later.
Start a new blog at Blogger. Remember your username and password (of course!), and get the blog ID. It's the number in the URL when you go to edit posts.
The URL to send the XMLRPC to for Blogger is
http://plant.blogger.com/api/RPC2
And we'll also need an application key to be allowed to post (not all servers require this, but Blogger does for their implementation). Register for an appkey here, and make a note of it.
Here's a simple script that'll post from AppleScript:
property username : "xxxx"
property userPassword : "xxxxxxxxxx"
property blogId : "4076297"
property bloggerApiKey : "3F58FC0D9439CD7A76A731C89C9540F2919xxxxxx"
property publish : true
set content to "Hello World!"
try
tell application "http://plant.blogger.com/api/RPC2"
set postId to call xmlrpc {method name:"blogger.newPost", parameters:{bloggerApiKey, blogId, username, userPassword, content as Unicode text, publish}}
display dialog postId
end tell
on error error_message
display dialog error_message
end try
The property
lines at the top set the information collected earlier.
Using XMLRPC from Applescript is just the tell application "http://plant.blogger.com/api/RPC2"
line to say where the request should go, and the call xmlrpc
to set the method and parameters.
A few things to note:
Unicode string
. This is because the call will silently fail if it's a plain text string.try
, on error...
, end try
. This catches any errors that occur in the first half, and does something with the message in the second half. It means we don't have to handle the XMLRPC failing in any one of the ways it could product a fault (the server might be down, or there might be disallowed characters in the content), we just display the error message at the end.There's a way of dragging a URL to the Desktop, a way of reading this file, and a way of posting that to a blogging system: Folders Actions lets us automate it.
Folder Actions are events that run in AppleScript when a folder changes. They start with on
, just like AppleScript subroutines.
There are different types of Folder Actions, for adding to or changing the contents of folders, and other events. They're contained in scripts which run automatically when this event occurs. The documentation is in the Standard Additions Dictionary.
A simple Folder Event script looks like this:
on adding folder items to theFolder after receiving theAliases
[AppleScript to operate on theAliases]
end adding folder items to
The code inside will run whenever one or more items are added to the folder this script is attached to.
What's that variable theAliases? AppleScript has two ways of referring to files: items, and aliases (also called file references). The item is the file itself, whereas the alias is just all the information about the file -- although this isn't an important distinction in most circumstances. It's just important to be aware of what any particular function is giving you to deal with. (Earlier, when we saw what class the files were, we were dealing with items.)
Folder Events don't work by default. To enable them:
This menu also has the option to attach a script to a folder. We'll need this later.
Here's the final script.
property username : "xxxxx"
property userPassword : "xxxxxxxxxx"
property blogId : "4076297"
property bloggerApiKey : "3F58FC0D9439CD7A76A731C89C9540F291xxxxxxxx"
property publish : true
property debug : false
on adding folder items to theFolder after receiving theAliases
try
tell application "Finder"
repeat with thisAlias in theAliases
if (class of item (thisAlias)) is internet location file then
set theLocation to the location of thisAlias
set theName to the displayed name of thisAlias
if theLocation contains theName then
-- hitting cancel here will automatically stop the script
set nameResult to display dialog "Choose some text for this link:" default answer theName
if button returned of nameResult is "OK" then
set theName to text returned of nameResult as string
end if
end if
set postContent to "<a href=\"" & theLocation & "\">" & theName & "</a>"
set postId to my postToWeblog(postContent)
end if
end repeat
end tell
on error error_message
if debug is true then display dialog error_message
end try
end adding folder items to
on postToWeblog(content)
set content to my xml_encode(content as string)
try
tell application "http://plant.blogger.com/api/RPC2"
return call xmlrpc {method name:"blogger.newPost", parameters:{bloggerApiKey, blogId, username, userPassword, content as Unicode text, publish}}
end tell
on error error_message
display dialog error_message
end try
end postToWeblog
-- takes a string, encodes xml unfriendly things
on xml_encode(myString)
set myString to searchReplace(myString, "&", "&")
set myString to searchReplace(myString, ">", ">")
set myString to searchReplace(myString, "<", "<")
set myString to searchReplace(myString, "\"", """)
set myString to searchReplace(myString, "'", "'")
return myString as string
end xml_encode
-- taken from http://maccentral.macworld.com/news/0003/16.briggs.shtml
on searchReplace(theText, SearchString, ReplaceString)
set OldDelims to AppleScript's text item delimiters
set AppleScript's text item delimiters to SearchString
set newText to text items of theText
set AppleScript's text item delimiters to ReplaceString
set newText to newText as text
set AppleScript's text item delimiters to OldDelims
return newText
end searchReplace
The block that starts on adding folder items to
and ends end adding folder items to
is the code that runs when a new item is added to the folder.
There are a few additions from the script fragments earlier. You'll see that the alias is converted to an item to check it's an Internet Location File.
The post itself is just a hyperlink with the name of the file as the link text, and the URL as the href.
There's also a small amount of code that checks whether the name of the file is a portion of the location, and if it is presents a dialog box to give some better link text. This is because some applications don't give the Internet Location Files sensible names, and just use part of the URL.
The code which does the XMLRPC call has been moving into on postToWeblog
.
As promised, this includes some code to encode XML-unfriendly characters. It just runs the text through a search-and-replace routine found in an online AppleScript column.
Any errors are trapped by the try
loop around the XMLRPC call, and the error message displayed, so we know if anything went wrong.
And that's it!
Change the properties at the top of the script to match the information you noted down earlier.
Save the script in the Folder Action Scripts folder. This is in the Scripts folder in Library, in your own home directory. Call it something like "Post to weblog".
Now it's time to automate it.
Choose "Attach script to Folder" from Folder Actions in the Script menu.
Choose the new script, "Post to weblog", and then choose a folder to attach it to. I chose my Desktop folder (in my home directory). This means that whenever I drag a URL to it from Chimera or NewNewsWire, it'll automatically be posted to my weblog.
Job done!
Right, so this is helping me be lazy. But I want more.
These links sometimes need a small amount of explanation, or a typo corrected, or I want to promote it to my main weblog.
So one task for the future will be to build an ultra simple management system to deal with these quick links, keeping it fast, local, and part of Mac OS X.