As I continue my attempts to increase my daily efficiency, I wanted to be able to post tweets through LaunchBar. There are numerous scripts that accomplish this. I found one that was almost what I was looking for.1 The only thing missing was the ability to automatically shorten URLs. You can find the resulting script here.

The previous authors worked their magic so that the script has the features:

  • Warns if the tweet message is over 140 characters
  • Escapes the message so it’s safe to send
  • Outputs Growl notification on success and on error
  • Pulls authentication information from the macOS keychain

The authentication is taken from the last user id and password provided when accessing

A caveat: this script won’t work for you if you use multiple Twitter accounts.

--   This script was put together with the help of the following sources:
-- by Coda Hale
-- by Graham English
-- by @drdrang (fix for &ampersand issues)
--   put together and adapted by @ptujec to work with LaunchBar
--   minor changes to convert urls to tiny versions by @ctwise (

-- take string from LaunchBar
on handle_string(tweet)
     -- shorten urls
     set tweet to replace_http(tweet)

     -- do wordcount
     set wordcount to do shell script "echo " & quoted form of tweet & " | wc -c"
     set wordcount to do shell script "echo " & quoted form of wordcount & " | sed 's/^[     ]*//'"

     if wordcount as integer > 140 then
         -- notify when tweet contains more than 140 characters
         my growlRegister()
         growlNotify("Tweet too long", "(" & wordcount & ") characters")
         return nothing
     end if

     --do tweetescape
     set tweet_new to tweetescape(tweet)

     -- take logininformation from keychain
     tell application "Keychain Scripting"
         set twitter_key to first Internet key of current keychain whose server is ""
         set twitter_login to quoted form of (account of twitter_key & ":" & password of twitter_key)
     end tell

     -- update twitter
     set twitter_status to quoted form of ("source=launchbarat&status=" & tweet_new)
     set results to do shell script "curl --user " & twitter_login & " --data-binary " & twitter_status & ""

     -- display dialog results
     my growlRegister()
     -- you can change "Tweet" into a diffent text e.g. "Zwitscher"
     growlNotify("Tweet", tweet)
end handle_string

-- fix for &ampersand issues (by @drdrang)
on tweetescape(tweet)
     set cmd to "
from urllib import quote
print quote(\"\"\"" & tweet & "\"\"\", \"/:\")
     return (do shell script "python -c " & (quoted form of cmd))
end tweetescape

-- additional scripting for Growlnotification
using terms from application "GrowlHelperApp"
     on growlRegister()
         tell application "GrowlHelperApp"
             register as application "Tweet" all notifications {"Alert"} default notifications {"Alert"} icon of application ""
         end tell
     end growlRegister
     on growlNotify(grrTitle, grrDescription)
         tell application "GrowlHelperApp"
             notify with name "Alert" title grrTitle description grrDescription application name "Tweet"
         end tell
     end growlNotify
end using terms from

-- This uses the built in splitting in AppleScript.
-- Most of the code just restores the delimiters.
on split(theText, splitText)
     set tid to AppleScript's text item delimiters
     set AppleScript's text item delimiters to splitText
     set theTextItems to text items of theText
     set AppleScript's text item delimiters to tid
     return theTextItems
end split

-- I tried the opposite of the split implementation but for some
-- reason it doesn't work reliably
on join(theList, joinText)
     set result to ""
     repeat with theToken in theList
         if length of result = 0 then
             set result to theToken
             set result to result & joinText & theToken
         end if
     end repeat
     return result
end join

-- Send the url to tiny url for shortening
on shorten_url(theURL)
     set theURL to tweetescape(theURL)
     set results to do shell script "curl" & theURL
     return results
end shorten_url

-- Find everything that looks like a URL and shorten it
-- The number 25 is the length of a tiny url, no point in
-- shortening a url if it's already below that.
on replace_http(theText)
     set tokens to split(theText, " ")
     set output to {}
     repeat with theToken in tokens
         if (theToken starts with "http://") and length of theToken > 25 then
             set the end of output to shorten_url(theToken)
             set the end of output to theToken
         end if
     end repeat
     return join(output, " ")
end replace_http

[1] The script came from but was built from previous scripts at and and