AppleScript calling LiveJournal XML-RPC

Here’s a simple script I wrote that you can use to post directly to LiveJournal from AppleScript. This is only a small example of how you can interact with LiveJournal using AppleScript. For more information on their XML-RPC implementation and syntax, look here. Remember that AppleScript treats structs as {{|records|:within, |single|:parameters}}, and don’t forget to |pipe| all your labels (which should match LJ’s xml fields) to prevent scripting addition conflicts.

update: added support for moods, user pictures, current music, & tags. Also added an edit/preview system. The script backdates entries by default for testing purposes. (see notes)

-- the name of your livejournal account
set my_name to "YOUR_USERNAME"

-- password dialog (sent in the clear, see LJ docs for safer methods)
set my_pass to text returned of (display dialog "Enter password for " & quoted form of my_name with title ¬
	"LiveJournal Post Event" with icon stop default answer "" buttons {"Continue."} default button 1 with hidden answer)

-- login and request a list of user pictures
try
	tell application "http://www.livejournal.com/interface/xmlrpc" to call xmlrpc {method name:"LJ.XMLRPC.login", parameters:¬
		{{username:my_name ¬
			, |password|:my_pass ¬
			, getpickws:"1"}}}
	set my_userpics to pickws of result
on error the error_message number the error_number
	display dialog "Error: " & the error_number & ". " & the error_message buttons {"Cancel"} default button 1
end try

-- line ending type (mac/unix/pc)
set my_lines to "mac"

-- set this to true if you don't want your experimental post showing up on Friend Lists
set is_backdated to true

-- get iTunes track for blank entry
tell application "iTunes" to set my_music to (name of current track & " - " & ¬
	artist of current track & " - " & album of current track) as string

set text_area to ""
-- how many lines should the composition window have? (I dunno if this works right pre-tiger)
repeat 10 times -- # lines
	set text_area to text_area & return
end repeat

-- set up default values for the blank entry
copy {"", text_area, my_music, "", "false", ""} to {my_topic, my_post, my_music, my_mood, my_userpic, my_tags}

repeat
	-- the subject line for your entry: (optional)
	set my_topic to text returned of (display dialog "Entry Subject:" with title "LiveJournal Post Event" default answer ¬
		my_topic buttons {"Continue."} default button 1)
	
	-- the body of your entry: (required)
	repeat
		set my_post to text returned of (display dialog "" with title "Compose Entry" default answer ¬
			my_post buttons {"Continue."} default button 1)
		if my_post is not "" and my_post is not text_area then exit repeat
		set my_post to text_area
		display dialog "You must blog about something!" with icon stop
	end repeat
	
	-- some tags for the entry (optional)
	set my_tags to text returned of (display dialog "Comma-separated tag(s) for your entry:" with title ¬
		"LiveJournal Post Event" default answer my_tags buttons {"Continue."} default button 1)
	
	repeat
		-- the currently playing iTunes track (optional)
		copy {text returned, button returned} of (display dialog "Current iTunes Music: " with icon note with title ¬
			"LiveJournal Post Event" default answer my_music buttons {"Get Music", "Continue."} default button 2) to ¬
			{my_music, my_select}
		if my_select is "Continue." then exit repeat
		tell application "iTunes" to set my_music to (name of current track & " - " & ¬
			artist of current track & " - " & album of current track) as string
	end repeat
	
	-- ask what mood to use (optional)
	set my_mood to text returned of (display dialog "How you feelin' today?" with icon note with title ¬
		"LiveJournal Post Event" default answer my_mood buttons {"Continue."} default button 1)
	
	-- if the user has more than one picture, ask which to use for this entry (optional)
	if (count my_userpics) > 1 then set my_userpic to (choose from list my_userpics with title ¬
		"User Pictures for " & quoted form of my_name with prompt ¬
		"Select a picture for this entry:" default items my_userpic OK button name "Use Selected" cancel button name ¬
		"Use Default" without empty selection allowed and multiple selections allowed) as string
	
	
	-- confirm the entry, and allow the user to make infinite changes to the stored data
	if my_userpic = "false" then set my_userpic to "(default)" as string
	if my_music = "" then set my_music to "(none)"
	if my_mood = "" then set my_mood to "(none)"
	
	-- confirm the complete entry
	if button returned of (display dialog "Journal: " & my_name & "
Subject: " & my_topic & "

Body: " & my_post & "

Tags: " & my_tags & "

Mood: " & my_mood & "
Music: " & my_music & "
Picture: " & my_userpic with title "Entry Preview" buttons ¬
		{"Cancel", "Edit Entry", "Post Entry"}) is "Post Entry" then exit repeat
end repeat

if my_userpic = "(default)" then set my_userpic to 0
if my_mood = "(none)" then set my_mood to 0
if my_music = "(none)" then set my_music to 0

-- figure out the time and date of your post based on local system time
current date
copy {year of result, month of result as integer, day of result, time of result} to {my_year, my_month, my_day, post_time}
if post_time ≥ hours then
	copy {post_time div hours, post_time mod hours} to {my_hour, minute_x}
	copy {minute_x div minutes, minute_x mod minutes} to {my_minute, my_second}
else if post_time ≥ minutes then
	copy {0, post_time div minutes, post_time mod minutes} to {my_hour, my_minute, my_second}
else
	copy {0, 0, post_time} to {my_hour, my_minute, my_second}
end if

-- post the actual entry
tell application "http://www.livejournal.com/interface/xmlrpc" to call xmlrpc {method name:"LJ.XMLRPC.postevent", parameters:¬
	{{username:my_name ¬
		, |password|:my_pass ¬
		, |event|:my_post ¬
		, lineendings:my_lines ¬
		, subject:my_topic ¬
		, |year|:my_year ¬
		, mon:my_month ¬
		, |day|:my_day ¬
		, hour:my_hour ¬
		, min:my_minute ¬
		, props:{current_mood:my_mood ¬
		, current_music:my_music ¬
		, picture_keyword:my_userpic ¬
		, opt_backdated:is_backdated ¬
		, taglist:my_tags}}}}

--open the entry in your default browser
open location (|url| of result)

While I’m at it, here’s another (perhaps more useful) script that lets you edit just the body of the last entry you posted, while keeping all other settings (timestamp, mood, etc.) of the entry intact:

-- the name of your livejournal account
set my_name to "YOUR_USERNAME"

-- password dialog (sent in the clear, see LJ docs for safer methods)
set my_pass to text returned of (display dialog "Enter password for " & quoted form of my_name with title ¬
	"LiveJournal Post Event" with icon stop default answer "" buttons {"Continue."} default button 1 with hidden answer)

-- get information about the last entry
tell application "http://www.livejournal.com/interface/xmlrpc" to call xmlrpc {method name:"LJ.XMLRPC.getevents", parameters:¬
	{{username:my_name, |password|:my_pass, selecttype:"one", itemid:-1, lineendings:"unix"}}}

-- scrape out just the things we're interested in
item 1 of |events| of result
copy {|event| of result, itemid of result, subject of result} to {my_post, my_item, my_topic}

-- present a dialog to edit the body of the entry
set my_post to text returned of (display dialog "" with title "Edit Entry" default answer my_post buttons {"Cancel", "Update Journal"})

-- post the changes. this preserves the post's other original settings, timestamp included.
tell application "http://www.livejournal.com/interface/xmlrpc" to call xmlrpc {method name:"LJ.XMLRPC.editevent", parameters:¬
	{{username:my_name ¬
		, |password|:my_pass ¬
		, subject:my_topic ¬
		, |event|:my_post ¬
		, itemid:my_item ¬
		, lineendings:"unix"}}}

--open the entry in your default browser
open location (|url| of result)	

x-posted