Getting all Podcast Names

Here’s a nice little AppleScript I knocked up to grab all of the details of my podcasts, for the previous post:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    tell application "iTunes"
    	set podcastList to {}
    	repeat with trk in selection
    		set thisPodcast to album of trk & " • " & artist of trk
    		if thisPodcast is not in podcastList then
    			set podcastList to podcastList & thisPodcast
    		end if
    	end repeat
    end tell
    
    set HTML to "<ul>"
    repeat with trk in podcastList
    	set HTML to HTML & "<li>" & trk & "</li>"
    end repeat
    set the clipboard to HTML & "</ul>"

Hot Toddy • Mindtrip • [Chillout Sessions 8][2] ★★

[2]: http://www.google.com/search?q=%22Chillout Sessions 8%22

Scripting Quicktime

I’m trying to create reference movies (as Quicktime .MOV documents) for all of the movies on my Media server, and the most obvious method is to use AppleScript and Quicktime Player. Why am I doing this? Because iTunes requires Quicktime Movies, I’ve mainly got AVIs, and I don’t want to (a) convert all of them, and (b) have iTunes manage them. I’d rather have the files in the right spot, and allow iTunes to manage the reference movies. Quicktime will often open files of varying types, even though iTunes will not. It’s then possible to save the file, and choose not to create a stand-alone movie. This will create a reference movie, which is much smaller than the original, but requires that the original remains in the same place in order to work. However, using AppleScript, the following will not work if AVIs are set to play in another player, like VLC:

1
2
3
4
5
6
7
8
9
    tell application "Finder"
    	set theMovies to selection
    end tell
    
    repeat with theMovie in theMovies
    	tell application "QuickTime Player"
    		open theMovie
    	end tell
    end repeat

That is, the movie opens in it’s default application. To get it to work requires simply the following:

1
2
3
4
5
6
7
8
9
    tell application "Finder"
    	set theMovies to selection
    end tell
    
    repeat with theMovie in theMovies
    	tell application "QuickTime Player"
    		open theMovie as alias
    	end tell
    end repeat

That little as alias causes Quicktime to open it, instead of VLC. How bizarre! The next problem is that by default, it puts the document(s) into a list. I often make the mistake of operating on a list, rather than each item individually. Especially when there’s only one item in the list. It’s like my eyes don’t see the curly brackets. So, we can save the movie, and by default it will save it as a reference movie. Next problem, how do we tell it where to save the movie? It will default to the root directory of the boot disk. Not really where I want to save this file, as I want to do multiple copies. But, what I can do is save the file, import it into iTunes, (ensuring that iTunes creates a copy of this file in it’s library) and then delete the file, or create the next one over the top. What I’m up to so far (and this doesn’t deal with names or anything yet):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    tell application "Finder"
    	set theMovies to selection
    end tell
    
    repeat with theMovie in theMovies
    
    	tell application "QuickTime Player"
    		set mov to first item of (open theMovie as alias)
    		save mov in (file "movie.mov")
    		close mov
    	end tell
        
    	tell application "iTunes"
    		add alias "Macintosh HD:movie.mov"
    	end tell
        
    end repeat

More later. Sleep time now.

Rounding Ratings

I like that iTunes displays half-star ratings, but I want my tracks rated 51-59 to display this way too. That doesn’t work, but if you use the following script, it will round the ratings of selected tracks to the nearest half-star:

1
2
3
4
5
    tell application "iTunes"
    	repeat with trk in selection
    		set rating of trk to ((rating of trk) / 10 as integer) * 10
    	end repeat
    end tell

I hope Apple don’t include the functionality of odd-rated tracks to play different amounts, otherwise I’ll need to re-rate all of my music. Again.

Bypassing iTunes Downloader

My biggest hate about iTunes is that if the download of a Podcast fails, it needs to restart the whole download, rather than just resume. This really sucks if you are 21Mb into a 22.5Mb download. Using the technique illustrated in Adding a Podcast to a Pre-Existing Subscription, it’s possible to download the files in another program, such as wget, which can handle resumes. It also tends not to drop out as much as iTunes does when the network is congested. Which it is automatically when three downloads are concurrently occurring. There are some changes that need to be made to the process, but these are really just simplifications. You need to know the URL of the file you want to get, which can be obtained using the following AppleScript:

1
2
3
    tell application "iTunes"
        set the clipboard to address of item 1 of selection
    end tell

Then, set up your http server, and create the same directory structure from your server root. Go to the relevant directory, and download the files you want to grab. Finally, go offline, and point the domain(s) at your own computer. Go back into iTunes, and use the GET button to grab the files from your own ‘server’. Don’t use the Update Podcasts button, or an error may occur. This removes the need to recreate the XML file, which is the most labour intensive part of the process illustrated in the previous post. It works a treat.

iTunes Ratings

From OmniNerd: Playing Favourites, I decided to run my own version of the experiment that compares how often songs with different ratings get played by iTunes. The difference with my experiment is that it has 101 tracks, each with a different rating (0, 1, …, 99, 100). To start with, I created a new user, so I wouldn’t have to muck around with my own iTunes library. I recorded a short empty track with Sound Studio. That is, I started the application, pressed Record, then Stop, and saved this. Then, I imported this track into iTunes, and made it so it was only 0.01 seconds in length (use Info, Options, Stop Time). This will make the experiment much faster than the previous one, which had 1 second tracks. I’m not that concerned it’s an AIFF, as I made this script to create the 101 empty tracks, as AAC or MP3:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    tell application "iTunes"
    	set i to 0
    	set base to first item of selection
    	repeat 101 times
    		set trk to first item of (convert base)
    		set name of trk to i
    		set rating of trk to i
    		set i to i + 1
    	end repeat
    end tell

This will duplicate the selected track (or the first track of the selection, if you have more than one) 101 times. It will then give a name to each of these, 0-100, and assign the same rating as the name. Since doing this also seemed to play the tracks once, I used the following script to reset the play count. The bonus is that it can be used to reset the play counts and run the experiment again, with different parameters.

1
2
3
4
5
    tell application "iTunes"
    	repeat with trk in selection
    		set played count of trk to 0
    	end repeat
    end tell

It’s now time to run the experiment. I set the Party Shuffle to use the Library, and to play higher rated songs more often. Then I clicked play, and went away for about 12 hours. • When I came back, I could see what the data was starting to look like, but I grabbed the data using this script anyway:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    tell application "iTunes"
    	set theData to {}
    	repeat with trk in selection
    		set theRating to name of trk
    		set theCount to played count of trk
    		set thisData to {theRating, theCount}
    		copy thisData to the end of theData
    	end repeat
    end tell
    
    get theData
    
    tell application "TextEdit"
    	set theDoc to make new document
    	repeat with thisData in theData
    		set text of theDoc to text of theDoc & (first item of thisData) & "," & (second item of thisData) & return
    	end repeat
    end tell

Then, I saved this file as a CSV file, and imported it into Excel, which when plotted, gives the following graph: To me, the results look pretty clear. iTunes does not take into account the actual rating, only the star value. Even the new half-stars aren’t notably different. I’ll continue to run the experiment, and put up another post later. I may change some things, and rerun the original experiment, just to confirm it, although my results seem to do this already.

Address Book Scripting

I’m trying to save time by creating some simple scripts to add values to Address Book entries. For instance, I have a whole lot of people in a group who are living in the same state, and I want to add this to all addresses. However, it doesn’t seem to be possible to get or set the state of an address:

1
2
3
4
5
    tell application "Address Book"
    	tell my card
    		set the_state to state of address 1
    	end tell
    end tell

This fails. With the very helpful:

Address Book got an error: Can’t make state of address 1 of my card into type reference.

Which means absolutely nothing, as far as I can tell. Googling this string brings no joy. Now the weird thing is that if I switch over to another user, it works fine. Update: I quit all running Apps (with the intention of restarting, but System Update stopped me) and retried it. It worked. Something I was running was interfering with it, but I have no idea what.

Profiling AppleScript code

This looks promising. Shark is a tool that can be used to profile code. I haven’t done any serious profiling since some python script I was working on years ago on BeOS. Daniel Jalkut has a nice post, Shark Bites Script up on his blog, on how to use Shark to profile AppleScript code. Since I’ve been doing a bit of AppleScripting lately, and I have some code that is in serious need of optimisation, this might be worth a second look.

Script to XHTML

I wrote my own script to convert the selection (or whole front document) in Script Editor to XHTML. It uses the same CSS tags as Jonathon’s program, but does not add the style data in, unless a property is set. I’ve also got the Source Code for his program, so it will be interesting to see similarities.

  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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
    (*
    Script to XHTML v1.0
    ©2005 Matthew Schinckel
    http://schinckel.net/
    
    Converts selection (or whole document) into XHTML code.
    
    Insert the StyleSheet into your CSS if you want.  Else set externalCSS to false.
    
    Put it in your Scripts Menu, and it will work a treat for you.  
    Even copies the data to the clipboard.
    
    Bugs/Issues:
    
    • Script Editor reports the start of comments [--] as being black, not grey.
    • Doesn't handle references.
    • Operators and values are treated all as values.
    
    *)
    
    property StyleSheet : "
    .AppleScript { background-color:#ffffff; border: solid black 1px; padding:0.5em 1em 1em 1em; text-align:left; font-family: Verdana,Sans-Serif; overflow:auto; font-size:0.9em; white-space:pre; line-height:1.2em; margin-bottom:9px;}
    .as_new_text  { font-family:Courier; color: purple; }
    .as_operators  { color: black; }
    .as_language  { font-weight: bold; color: blue; }
    .as_application  { color: blue; }
    .as_comments, .as_comment  { font-style:italic; color: gray; }
    .as_values  { color: black; }
    .as_variables ,.as_variable { color: green; }
    .as_references  { color: purple; }
    "
    property externalCSS : true
    
    -- The HTML code either side of the block.
    property htmlStart : "<pre class='AppleScript'>" & return
    property htmlEnd : return & "</pre>" & return
    
    property tagStart : "<span class='"
    property tagMiddle : "'>"
    property tagEnd : "</span>"
    
    -- Apparently, this one is different to 'return'
    property enter : "
    "
    -- For testing, set this to 2, for use via Script Menu, set to 1.
    property win : 1
    
    if externalCSS is not true then set htmlStart to htmlStart & "<style>" & return & StyleSheet & return & "</style>" & return
    
    tell application "Script Editor"
    	set theData to contents of selection of document of window win
    	if (theData is "") then
    		-- No selection, let's do the whole document.
    		set textList to attribute run of contents of document of window win
    		set fontList to font of attribute run of contents of document of window win
    		set colorList to color of attribute run of contents of document of window win
    	else
    		set textList to attribute run of contents of selection of document of window win
    		set fontList to font of attribute run of contents of selection of document of window win
    		set colorList to color of attribute run of contents of selection of document of window win
    	end if
    end tell
    
    set html to ""
    
    repeat with i from 1 to the count of textList
    	set theClass to whichClass(item i of fontList, item i of colorList)
    	set theText to my HTMLify(item i of textList)
    	set html to html & tagStart & theClass & tagMiddle & theText & tagEnd
    end repeat
    
    set the clipboard to htmlStart & html & htmlEnd
    beep
    
    -- Utility Functions
    
    on whichClass(theFont, theColor)
    	-- Set the class according to the font or colour.
    	if theFont is "Verdana-Bold" then return "as_language"
    	if theColor is {16384, 32768, 0} then return "as_variables"
    	if theColor is {19660, 19960, 19960} then return "as_comments"
    	if theColor is {0, 0, 65535} then return "as_application"
    	if theColor is {32768, 0, 32768} then return "as_new_text"
    	return "as_values"
    end whichClass
    
    on replace(theText, find, replace)
    	-- Nice replace function
    	set OldDelims to AppleScript's text item delimiters
    	set AppleScript's text item delimiters to find
    	set newText to text items of theText
    	set AppleScript's text item delimiters to replace
    	set theResult to newText as text
    	set AppleScript's text item delimiters to OldDelims
    	return theResult
    end replace
    
    on HTMLify(someText)
    	-- This might need some more entries.
    	-- Perhaps a better way of doing it...?
    	set someText to replace(someText, "&", "&amp;")
    	set someText to replace(someText, "\"", "&quot;")
    	set someText to replace(someText, "<", "&lt;")
    	set someText to replace(someText, ">", "&gt;")
    	--set someText to replace(someText, tab, "&nbsp;&nbsp;&nbsp;&nbsp;")
    	--set someText to replace(someText, enter, "<br />" & enter)
    	--set someText to replace(someText, return, "<br />" & return)
    	return someText
    end HTMLify

'Fixed' XHTML Export

Since I need to replace all " in the generated XHTML with ‘, I use the replace function from the previous post.

 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
    (* 
    Bugs:
    
    Does not like no selection: no real way to get the selection from SEE anyway.
    Sometimes does not execute if called from Script Menu.  Intermittant.
    *)
    
    -- If called from Script Menu, need to do this.
    
    tell application "SubEthaEdit"
    	activate
    	tell application "System Events" to keystroke "C" using {command down}
    end tell
    
    set theStart to (the clipboard)
    
    set the clipboard to (my replace(theStart, "\"", "'"))
    
    beep
    
    -- Another way of the Replace Function being called:
    
    -- set the clipboard to (replaceText from theStart to "'" instead of "\"")
    
    on replace(theText, find, replace)
    	set OldDelims to AppleScript's text item delimiters
    	set AppleScript's text item delimiters to find
    	set newText to text items of theText
    	set AppleScript's text item delimiters to replace
    	set theResult to newText as text
    	set AppleScript's text item delimiters to OldDelims
    	return theResult
    end replace
    
    -- Alternate version of replace()
    
    to replaceText from theText to replace instead of find
    	set OldDelims to AppleScript's text item delimiters
    	set AppleScript's text item delimiters to find
    	set theText to text items of theText
    	set AppleScript's text item delimiters to replace
    	set theText to theText as text
    	set AppleScript's text item delimiters to OldDelims
    	theText
    end replaceText

Code Markup

I like to present styled code for my readers, but I’m not totally happy with my methods of getting it: SubEthaEdit’s Export as XHTML is very cool, but I still have to tweak it so it looks nice. And I’ve got a great program for getting the XHTML version of the code Script Editor (AppleScript) is currently displaying. But, I’d like more flexibility. I want the code to be tagged with classes, like it’s possible to do with the Script Editor add-on, rather than using inline styles. I’ve already done this for the Script Editor code, but I just need to remember to remove the inline stylesheet from the start of the generated code. Unfortunately the Script has been saved as a Run Only. I’d love to know a way to decompile one of these Scripts…apparently there isn’t. I’ll have to write my own. Or see if Jon is nice enough to give the Source Code. As for the SubEthaEdit part: I should be able to do it. I’ve learned a couple of tricks that will help.