Insert iTunes Data into Post

I used to use ecto to paste all of my entries on my blog, but with Blogsome’s XMLRPC issue, I have to use a browser. But it would be nice to automatically get the name and information about my currently playing iTunes track, just like ecto used to do. I wrote an AppleScript that does this, and, inserts the data in at the insertion point for you. Because it’s intended to be run from the Script Menu, and everything run from there runs as “System Events”, I had to hard code in the browser name. If you use another browser, just replace the second line with whatever your browser is called.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
property star : «data utxt2605» as Unicode text
property browser : "Camino"
on run {}
    
    tell application "System Events"
        try
            get process "iTunes"
        on error
            return "No Track"
        end try
    end tell
    
    tell application "iTunes"
        set theTrack to current track
        set theArtist to artist of theTrack
        set theAlbum to album of theTrack
        set theRating to rating of theTrack
        set theTrack to name of theTrack
    end tell
    
    set theString to "<p class=’itunes’> " & theTrack & " • <a href='http://www.google.com/search?q=%22" & theArtist & "%22>" & theArtist & "</a> • <a href=’http://www.google.com/search?q=%22" & theAlbum & "%22>" & theAlbum & "</a> " & myRating(theRating)
    set the clipboard to theString
    
    tell application browser
        activate
        tell application "System Events" to keystroke "v" using {command down}
    end tell
end run

on myRating(theRating)
    set theResult to ""
    set theTimes to (theRating - 9) / 20 as integer
    repeat theTimes times
        set theResult to theResult & star
    end repeat
    return theResult
end myRating

Automation of XHTML Cleanup

I use SubEthaEdit all of the time, and the feature I like just about most is the Copy As XHTML ⇧⌘C. This will create some nice marked up text that accurately represents what SubEthaEdit looks like - it takes your current syntax styling layout and creates is as XHTML. There are a couple of issues, at least with Blogsome. Firstly, for some reason Blogsome needs all style tags inside the block to use ‘, not “. I think it might be to do with the fact it is a <pre> block. I did notice it was screwing with some double-quotes on another script I was posting. My other hassle is that the syntax highlighting isn’t quite right for AppleScript: it doesn’t take into account terms used from applications, so sometimes the wrong colour appear. I will write an Automator action that grabs the XHTML from SubEthaEdit, replaces " with ‘, and pastes it into the current active text box, I think. I also started using Convert Script To Markup Code - don’t recall where I found this, but it does a much better job of marking up the text from Script Editor, and everything looks much nicer.

Reconnect all Adium Accounts.

Just a little quickie: sometimes Adium loses connections. This script will reconnect any disconnected accounts.

1
2
3
4
5
    tell application "Adium"
        repeat with acc in accounts
            connect acc
        end repeat
    end tell

Export Playlist(s)

I’m still kinda bummed out over how long it takes to scan through all of the playlists in iTunes and grab the details of each song, and write it all out to a file. I’m talking about Smart Playlists here, since it would be a trivial exercise to just grab the songs from the XML file that iTunes so nicely provides for normal playlists. Since I don’t use normal playlists (except when looking for missing album art - darn iTunes’s inability to search on missing artwork!), Bery Rinaldo’s Export Playlist to M3U didn’t necessarily do what I am doing any better.

But, I did pinch some ideas from him - the first was a snippet on how to get the name of the currently selected playlist:

1
2
3
4
5
tell application "iTunes"
    if (class of front window is browser window) or (class of front window is playlist window) then
        get name of view of window 1	
    end if
end tell

The second I haven’t implemented yet, is having settings, and a setup wizard.

Anyway, the updated version is Export Playlists.scpt, put it in ~/Library/iTunes/Scripts (User only) or /Library/iTunes/Scripts (System-wide).

Even better Current iTunes Track

It’s nice to show other users what you are listening to, and provide a handy link for them to see more about the artist and track. I noticed that some IM systems don’t like HTML, and I figured out a way to make the link only be sent to a user of an AIM compatible or Jabber server.

Basically, you test the result of serviceClass of contact of the active chat of the first interface controller, and if it is “AIM-compatible” or “Jabber”, then you use HTML, if not, just plain text. You can download it from Adium Xtras: Now Playing in iTunes.

Full Source:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
– Better itunes adium link script
– Includes rating (if present), and links.
property message_prefix : «data utxt266B0020» as Unicode text
property not_listening_message : "Quiet"
property star : «data utxt2605» as Unicode text
property google : "http://www.google.com/search?q="
property server : ""

property html_classes : {"AIM-compatible", "Jabber"}

on substitute()
    –set server to "http://" & my getIP() & ":8080" — Use betterGetIP if on broadband!
    
    tell application "System Events"
        try
            get process "iTunes"
        on error
            return message_prefix & not_listening_message
        end try
    end tell
    
    tell application "iTunes"
        if player state is not playing then
            return message_prefix & not_listening_message
        end if
        set theArtist to artist of current track
        if theArtist is "" then set theArtist to "Unknown Artist"
        set theTrack to name of current track
        set theRating to " " & my myRating(rating of current track)
        set theLocation to location of current track
        set pth to my encode_URL_string(characters 9 thru end of (POSIX path of theLocation) as string)
    end tell
    
    tell application "Adium" to set accountType to serviceClass of contact of the active chat of the first interface controller
    if first item of accountType is in html_classes then
        return html(message_prefix & my myLink(google, theArtist) & " • " & my myLink(server & pth, theTrack) & theRating)
    else
        return message_prefix & theArtist & " • " & theTrack & theRating
    end if
end substitute

on myRating(theRating)
    set theResult to ""
    set theTimes to (theRating - 9) / 20 as integer
    repeat theTimes times
        set theResult to theResult & star
    end repeat
    return theResult
end myRating

on myLink(URI, theText)
    if URI is google then
        set URI to URI & first word of theText
        repeat with wd in (rest of every word of theText)
            set URI to URI & "+" & wd
        end repeat
    else if server is "" then
        return theText
    end if
    return "<a href=\"" & URI & "\">" & theText & "</a>"
end myLink

on html(str)
    return ("<HTML>" as Unicode text) & str & "</HTML>"
end html

on getIP()
    return do shell script "ifconfig ppp0 | grep inet | awk ‘{print $2}’"
end getIP

on betterGetIP()
    return do shell script "curl -s http://www.showmyip.com/simple/ | grep GMT | awk ‘{print $1}’"
end betterGetIP

property allowed_URL_chars : (characters of "/$-_.+!*’(),1234567890abcdefghijklmnopqrstuvwxyz")
property hex_list : (characters of "0123456789ABCDEF")

on encode_URL_string(this_item)
    set character_list to (characters of this_item)
    repeat with i from 1 to number of items in character_list
        set this_char to item i of character_list
        if this_char is not in allowed_URL_chars then set item i of character_list to my encode_URL_char(this_char)
    end repeat
    return character_list as string
end encode_URL_string

on encode_URL_char(this_char)
    set ASCII_num to (ASCII number this_char)
    return ("%" & (item ((ASCII_num div 16) + 1) of hex_list) & (item ((ASCII_num mod 16) + 1) of hex_list)) as string
end encode_URL_char

on run
    tell application "Adium" to activate
    my substitute()
end run

Getting the Active Chat in Adium

Getting the active chat in Adium from AppleScript appears at first look to be a little dicey: Adium needs to actually be the active application before the code actually works! For instance, if you open up the Script Editor, and type in the following:

tell application “Adium”     get contact of the active chat of the first interface controller end tell

You will get an empty list: {} To get a result, all you need to include is:

    activate

just before you access something belonging to the active chat. If you are creating an AdiumScript, and are testing it in the Script Editor, chances are you have used the idiom:

on run     my substitute() end run

To get this to work if you are using the active chat, it just needs to be changed to:

on run     tell application “Adium” to activate     my substitute() end run

Happy AdiumScripting!

Camino AppleScript

Using Open As Dictionary… in Script Editor doesn’t work with Camino. Nor did the hint to remove a certain file from the Package. Never mind. It’s possible to look at the file Camino.scriptSuite (it’s just a plist file), and work out what commands can be sent, and classes can be read: Classes: only the one, URL, «class curl» (Obviously all of the standard NSApplication classes still exist: especially name of window.) Commands:

  • DoJavaScript
  • GetURL
  • OpenURL
  • RegisterEchoHandler
  • UnregisterEchoHandler

I haven’t figured out how to use them all yet, or any of them for that matter. But someone else might use this info to figure our how to actually script Camino to do something useful…

Sending Files under Adium

I wrote a small AppleScript that sends the currently playing iTunes track to the current chat user in Adium. The only tricky part was that the line:

send the active chat of the first interface controller file filename

requires Adium to be the frontmost application: you cannot test this with Script Editor, only install the code as a an AdiumScript and then run it from within Adium. Since it is usually illegal to copy music, all of the usual disclaimers apply: only use this to send music to which you own the copyright, or is in the public domain. Here’s the full code, if you want the whole thing, email or IM me.

on substitute()     tell application “System Events”         try             get process “iTunes”         on error             return         end try     end tell          tell application “iTunes”         set filename to location of current track     end tell          tell application “Adium”         send the active chat of the first interface controller file filename     end tell          return theChat end substitute

Adium iTunes Rater

I wrote a quick AdiumScript to rate the currently playing song in iTunes. Trivial. The only downside? Arguments to AdiumScripts need to be typed in using {} rather than (). I’m much faster at typing in () without looking at the keyboard than {}. I guess I’ll have to learn. There are also scripts for quick-rating a track as 0-5 stars: /rate3 will rate a track as ★★★. (That’s three stars if you don’t have Unicode!) /rate{44} will set a rating of two-and-a-bit stars. The AdiumScript bundle includes all of the scripts, and can be downloaded Adium Xtras: Rate Current iTunes Track.

Adium Plugin Scripts

Adium has great support for AppleScripts (or possibly other scripting languages), in that you define a string, and when this string is typed in as a message, the script is run, and the result is sent as the message instead. Thus, it’s possible to write scripts that allow you to type in: %_itunes And a nicely formatted string, with the current iTunes song is sent to the person you are chatting to. This string can even have hyperlinks embedded in it, so if you were serving your iTunes library up, the person could click on it and download/stream it. The same for %_safari/%_camino, this can be set up to send a hyperlink with the current page, including the title. What is not clear from the internet is how to create these. It’s really quite simple. The scripts must live inside a package: under MacOS X packages are just folders with particular extensions. For instance, Mail.app is a folder, and it appears to the system/user as an application, or a particular type of package. Double-clicking on it will not opent he folder, but (in this case) run the application. AdiumScripts packages (with the extension .AdiumScripts) will install into your Library when you double-click them. So, the format must be as follows:

PluginName.AdiumScripts/
    Contents/
        Info.plist
        Resources/
            Script1Name.scpt
            Script2Name.scpt

The ScriptxName.scpt files must be valid AppleScripts, of the format:

on substitute(arg) –do stuff here return value end substitute

Where value is the value you want printed. You should format it with starting and closing html tags, and any html markup you want. If you want the user to be able to send an argument (%command{argument}), then include it as shown. Inside the Info.plist file, you need to have some important information.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <key>CFBundleGetInfoString</key>
        <string>Matt's Adium Scripts</string>
        <key>CFBundleIdentifier</key>
        <string>net.schinckel.AppName.scripts</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>1.0</string>
        <key>CFBundleName</key>
        <string>bundleName</string>
        <key>CFBundlePackageType</key>
        <string>AdIM</string>
        <key>Scripts</key>
        <array>
            <dict>
                <key>File</key>
                <string>Script1Name</string>
                <key>Keyword</key>
                <string>/script1</string>
                <key>Title</key>
                <string>Menu Item 1</string>
            </dict>
            <dict>
                <key>File</key>
                <string>Script2Name</string>
                <key>Keyword</key>
                <string>%_script2</string>
                <key>Title</key>
                <string>Menu Item 2</string>
            </dict> </array>
        <key>Set</key>
        <string>Script Submenu</string>
    </dict>
    </plist>

There are some bits of data you’ll need to change: Matt's Adium Scripts should be a descriptive title for your Scripts. com.schinckel.AppName.scripts should be a unique identifier for your scripts. bundleName could be the name of your bundle. Realistically, these can be anything, although I suspect Adium will only allow one version of a script with a particular identifier, or bundle name. The next bits are the impart ones: Script1Name needs to be the name of a script, minus the .scpt extension. /script1 is the keyword that will trigger this script to be called. And Menu Item 1 is what will be written in the Scripts Sub Menu. It’s possible to have multiple calls to the same script, each one just requires a duplicate dictionary entry, with a different Keyword string. For instance, I use /camino and %_camino to mean the same function, without requiring seperate scripts to be called. Finally, the Script Submenu value needs to be replaced by which Script Sub Menu you want the item to be placed under. For instance, there is already one called System Statistics, and iTunes - Now Playing. Using a value that doesn’t appear already causes a new Sub Menu to be created. I’m not sure if there is a ‘rule’ against using /command, as most of the ones I’ve come across all use %_command. I find this too slow to type, and have adapted them accordingly. You will be able to do this also, now that you know how…