29 October 2006

How to check for UI scripting

How embarrassing. This blog gets a link from MacDevCenter and I have a (minor) bug in the script. I have had UI Scripting enabled for son long that I always forget to check for it in the script. Obviously if somebody else runs the script, nothing happens.

To enable UI scripting go to the Universal Access Preference Pane and enable the checkbox at the bottom of the screen. However good script should check for this and give you a dialog, prompting you to enable it. Here is the code:

(Works with Tiger and up.)

tell application "System Events"
if not UI elements enabled then
display dialog "GUI Scripting is not enabled. This script requires GUI scripting, click \"OK\" to enable."
set UI elements enabled to true
end if
end tell


Note to self: paste this in front of every script that uses UI scripting.

27 October 2006

Script Friday: Birthday Address Book Plug-ins

Two quick and fun Address Book Plug-ins, download the archive, put the scripts into ~/Library/Address Book Plug-Ins (create folder if necessary).

Both don't actually do anything but one will display the age and the other the zodiac when you click on the birthday label in Address Book.

25 October 2006

.Mac site feed

If you start a blog in iWeb then you will get an RSS feed, that part is simple. however some people don't want to open a blog, but just post individual pages. if you want to keep track of what they are doing there is a RSS feed for the entire site. Just enter:

http://rss.mac.com/username/iWeb/Sites.rss

into your favorite feedreader.

21 October 2006

Rock Star Developers

This movie on 37Signals on the Apple Page (why is it in the Higher Education section?) is just one more proof of the fact that the Mac community treats their developers like Rock Stars. Don't get me wrong. Jason and David and all of 37signals deserve all the attention. The stuff they make is awesome, not to mention Ruby on Rails.

Maybe it is not so much the fact that Mac users want to treat the developers differently, but that the Mac as a platform attracts a different breed of developers, who act like Rock Stars and then get treated the same way.

20 October 2006

Script Friday: SubEthaEdit Server

SubEthaEdit is a great tool to share and collaborate on text documents. However to share a document you need a machine that is available to the internet (not behind a NAT or firewall) and has to be on, not very friendly for laptop users.

Use this script to turn your home server into a SubEthaEdit Server. On how to setup your home server, dyndns and the router I will leave that as a exercise for the attentive reader. SubEthaEdit 2 uses a port range of 6942-6951.

This script will open all the documents in ~/Documents/SubEthaEdit Server Documents/ and turn the sharing on. Then it will periodically save all open documents. You can use SubEthaEdit from your client to connect. Try my SubEthaEdit Server!

You can actually get the code for the script there. I was tempted to have that be the only place but eventually I will turn that off again so I will also put it this article so it ends up in the archive. This however a wonderful chance to directly put feedback in to the code. Much more interactive than comments!

SubEthaEdit Server (click link to open script in Script Editor)

Save as application and check the "Stay open" option. Then set the script as a login item and set that user to automatically login. This is generally a bad idea on a server but SubEthaEdit has no background deamon to do the serving so we have to use the GUI app. Please give the Codingmonkeys lots of feedback that we want this feature!

17 October 2006

Set Boot Volume in the command line

I haven't found this anywhere, so I will throw it out to the Googlesphere here.

Say you want to restart a Mac and boot from CD. Say it doesn't have a display and keyboard attached and you don't have Remote Desktop around (you should though).

You can always ssh in and do the following: Insert the CD. Run diskutil list to see wether the CD mounted and note the partition number (something like /dev/disk1s2 though the numbers will vary. Then to actually set the next boot drive use:

sudo bless --device /dev/disk1s2 --setBoot

and do a sudo reboot to restart. There is also a --mount option which will take the mount point, e.g. "/Volumes/Mac OS X Server Install/". To do a Netboot do:

sudo bless --netboot --server bsdp://255.255.255.255

You can replace the 255's with the NetBoot server's IP address if you want to boot off a specific server.

The bless command has another option --nextonly which will only remember the setting for one boot. Read the bless man page for more details.

16 October 2006

Steve Jobs Interview on MSNBC.com

There is new Steve Jobs Interview on (ironically) MSNBC.com. My favorite quote:
Microsoft has announced its new iPod competitor, Zune. It says that this device is all about building communities. Are you worried?
In a word, no. I've seen the demonstrations on the Internet about how you can find another person using a Zune and give them a song they can play three times. It takes forever. By the time you've gone through all that, the girl's got up and left! You're much better off to take one of your earbuds out and put it in her ear. Then you're connected with about two feet of headphone cable.

Which just goes to prove that geeks aren't good product designers. They never think of the human interaction associated with a product.
(Via Gruber's Linked List)

13 October 2006

Daring Fireball: Processing Processes

Comparing Shell scripts to AppleScript seems fairly common these days. John Gruber over at Daring Fireball has a nice and (as usual) longish article on Processing Processes.

Script Friday: Build Similar Tracks Playlist in iTunes

Use this script on the currently playing track or selection in iTunes to build a list of similar tracks. It will generate a new playlist and start with the current track (iTunes will "hiccup" briefly while switching playlists, sorry).

Similar Artist information is gained by accessing the Audioscrobbler Web Service. I am in no way affiliated with last.fm/audioscrobbler but any company that opens their APIs for scripters does get bonus points from me.

This script is very sensitive to the naming of the artists in your library, if your naming does not match the naming in audioscrobbler then you are out of luck. Take a look at the event log to track down problems.

Use the following parameters to adjust to your preferences (you will find them in the first few lines of the script as properties):

includePlaylist : "Library" -- pick only songs from this playlist, use "Library" for all your songs, podcasts and songs which are marked 'Skip when shuffling' are ignored by default
numberOfTracks : 12 -- how many tracks should be added to the new playlist
minimumRating : 20 -- only choose tracks with a rating higher or equal to this, note: 1 star in iTunes equals a rating of 20 (5 stars = 100)
minimumMatch : 40 -- Audioscrobbler has a 'match' index for the artists from 100 downwards, describing how similar two artists are rated. ignore artists with a match rating lower than this.
namePrefix : "Similar Tracks starting with " -- the new playlist will start with this string followed by the name of the artist

So without much further ado:

Build Similar Tracks Playlist

12 October 2006

More on find...

Funny that I write about find yesterday and then I find this:

Harnessing The Über-Powerful find Command (+xargs)

Go there and read on the xargs thing I teased you with yesterday.

11 October 2006

Shell vs. AppleScript: 1-0

I added Google Analytics to his blog, just because I'm really curious and it really beats a boring hit counter (left handed and twice on any week-day). Aside from the fact that I am totally enslaving myself and my online publications to Google (and happily doing that, which is weird) it was really easy, you just have to insert a few lines of javascript into every page. Of course using a template based blogging system makes that really simple. But then I wondered about wether I could get Google to analyse my iWeb Blog?

Of course I could try to change the internal iWeb templates but that would be painful and I'd probably have to re-do that every time iWeb gets an update. It would be nicer to work on the published pages. If you go to your iDisk then you will see a "Sites" and a "Web" folder. The Sites folder was (is) used by the old web-based ".Mac HomePage" or can be used to publish self made pages. And if you look into the "Web" folder, then you see the code that iWeb generates. You can view and even modify the code there, and it will retain you modifications until you re-publish the site in iWeb.

So the problem is easy, open every html file, insert a code snippet before the </body> tag. Sounds like a job for a script. Fortunately AppleScript has this great support for filtering and you can do that recursively through folders , too. Should be as simple as

get every file of entire contents of iWebBaseFolder where name ends with ".html"

It should be. Try this with any decently sized iWeb page and you will get a timeout error. Of course you can increase the timeout, but it seems wrong that AppleScript chokes on this. Note: I have mounted my iDisk the standard way, so it is using WebDAV und you can tell by the delays this causes in Finder, if you have set your iDisk to synchronize with a local mirror, then this might actually work.

Of course finding the files is only the first part, then you have to open the text parse it for the </body> tag and insert the code and save the file again. All of this is very painful in AppleScript.

Wait, isn't this what Unix is supposed to be good at? Let's try. The find part is easy

find /Volumes/idiskname/Web/Sites -name '*.html'

You can still see the names appearing but it is much better than the AppleScript solution. So how do we go about the text manipulation? The answer is sed (stream editor) which takes a stream of characters and somehow manipulates this using the magic incantations of regular expressions and things that the sed man pages calls "functions" but which are basically single letters which are meaningful to the initiated and completely illegible to laypersons. Thankfully you can enter and nice search in Google (there it is again, I have no idea how I was able to learn programming entirely without Google) and find some examples:

# substitute "foo" with "bar" EXCEPT for lines which contain "baz"
sed '/baz/!s/foo/bar/g'

If the script already inserted the snippet then we won't need to insert it again. So some experimenting and much confusion lead to:

sed -i .bak -e "/$textToInsert/!s/$textToReplace/$textToInsert&/g" filename

Where the $ prefix denotes variables I defined earlier in the script to turn it into something close to legible. What this command does is: if a line does not (!) contain $textToInsert then substitute (s) $textToReplace with $textToInsert and append the text we orginally searched for ($textToReplace, &) globally across the document (g) filename and then write that into the file, keeping a copy with a .bak extension around in case all this gibberish happens out to pruduce... well gibberish.

Combine that with the find command form earlier and a nice -exec extension and you get the entire script:

#!/bin/bash

googleAnalyticsCode='enter your Google Analytics code number here'
textToInsert="<script src=\"http:\/\/www.google-analytics.com\/urchin.js\" type=\"text\/javascript\"><\/script><script type=\"text\/javascript\">_uacct = \"$googleAnalyticsCode\";urchinTracker();<\/script>"
textToReplace="<\/[Bb][Oo][Dd][Yy]>"
iWebBasePath='/Volumes/idiskname/Web/Sites'

# this is where the actual work happens
find $iWebBasePath -iname '*.html' -exec sed -i .bak -e "/$textToInsert/!s/$textToReplace/$textToInsert&/g" {} \; -print


Basically a one liner. I added the -print at the end of the command so I can see which files the script is working on. Otherwise you would get no feedback at all.

Admittedly very powerful. Armed with this new knowledge we can go ahead a write a script that removes the Google Analytic snippet again:

#!/bin/bash

googleAnalyticsCode='enter your Google Analytics code number here'
textToRemove="<script src=\"http:\/\/www.google-analytics.com\/urchin.js\" type=\"text\/javascript\"><\/script><script type=\"text\/javascript\">_uacct = \"$googleAnalyticsCode\";urchinTracker();<\/script>"
iWebBasePath='/Volumes/idiskname/Web/Sites'

# this is where the actual work happens
find $iWebBasePath -iname '*.html' -exec sed -i .bak -e "s/$textToRemove//g" {} \; -print

and (I bet you waited fro this) a one liner to remove all those pesky .bak files (after testing of course):

find /Volumes/arminb/Web/Sites -iname '*.bak' -exec rm {} \; -print

(again the print is for the sole purpose of having something to watch) And I know some smart guy will chime in here and say that xargs would be so much more efficient than -exec and that is true but I will leave that for another day.

I love AppleScript very much but in this case the command line tools are way more efficient (though painful to learn). I guess the resume here should be: "Know your tools!"

10 October 2006

Automator Actions

Shameless plug, but still. I wanted to point out, that I have a small site with a few useful Automator actions. They are up there including the code!

Armin's Automator Actions

Address Book Plug-In: Show Emails from or to

One of the recurring topics int he old blog were short AppleScripts to optimize the workflow. Here is a new one.

Show Emails From

Click on the link above and save the script that is opened in Script Editor in ~/Library/Address Book Plug-Ins/ as Show Email From. Create the folder if necessary. Then (re-)start Address Book and click and hold on the label next to an email address. You can now select the Show Emails from option, which will open a new message browser window in Mail and fill out the search field to show emails from this email address only.

Then go back in to Script Editor and change the lines
   return "Show emails from " & theName

to
   return "Show emails to " & theName

and
   click button "From" of window 1 

to
   click button "To" of window 1 

or click here for the entire script and save this as Show Email To in the same folder. Restart Address Book.

BTW: Opening new Mail viewer windows (File Menu > New Viewer Window) is one of the 'unsung' features in Mail which really increases my productivity. If you aren't using that yet, then start remembering the keyboard shortcut (command-option-N) to your repertoire.

Welcome (Back)!

It's been a while since I had a technical blog. While my personal life is nicely covered, I was still missing a venue for some of the technical stuff I've been doing recently.

As before, my plan is to blog mac-centric tips, tricks and scripts on how to use your Mac more efficiently. This time I took the chicken way out and registered with Blogger. I don't want the hassle of managing my own server, the service is free and there is the slight hope of getting some revenue through AdSense.

Welcome back! And don't forget to please reply!

Armin