All pastes #780567 Raw Edit

iTunes.scpt

public text v1 · immutable
·published 2007-11-18 16:50 UTC
rendered paste body
property prefs : missing value
property prefsPath : missing value

on get_tracklength(numBars, isUTF)
	my loadPrefs()
	if numBars is 0 then
		-- just use regular time
		tell application "iTunes"
			set thePosition to my convertTime(player position)
			if duration of current track is missing value then
				set theDuration to "∞"
			else
				set theDuration to my convertTime(duration of current track)
			end if
		end tell
		return "(" & thePosition & " / " & theDuration & ")"
	else
		tell application "iTunes"
			if duration of current track is not missing value then
				set n to round (player position / (duration of current track) * numBars)
			else
				set n to -1
			end if
		end tell
		if isUTF then
			set leftedge to "╞"
			set bar to "═"
			set marker to "╪"
			set rightedge to "╡"
		else
			set leftedge to "["
			set bar to "="
			set marker to "<b>|</b>"
			set rightedge to "]"
		end if
		set str to "<span style=\"color:" & my rgbStringOf(prefs's getKey("--Left Progress Bar Color")) & "\">" & leftedge
		repeat with b from 0 to numBars
			if b < n then
				set str to str & bar
			else if b = n then
				set str to str & "</span><span style=\"color:" & my rgbStringOf(prefs's getKey("--Progress Bar Marker Color")) & "\">" & marker & "</span><span style=\"color:" & my rgbStringOf(prefs's getKey("--Right Progress Bar Color")) & "\">"
			else
				set str to str & bar
			end if
		end repeat
		set str to str & rightedge & "</span>"
		return str
	end if
end get_tracklength

on convertTime(theTime)
	set theMinutes to (theTime div 60) as string
	set theSeconds to ((theTime mod 60 as integer) as string)
	if length of theSeconds is 1 then
		set theSeconds to "0" & theSeconds
	end if
	return theMinutes & ":" & theSeconds
end convertTime

on rgbStringOf(theColor)
	repeat with i from 1 to 3
		if item i of theColor < 256 then set item i of theColor to 256
		if item i of theColor > 65270 then set item i of theColor to 65270
	end repeat
	set rtn to "rgb(" & (round ((item 1 of theColor) / 256 - 0.5)) & "," & (round ((item 2 of theColor) / 256 - 0.5)) & "," & (round ((item 3 of theColor) / 256 - 0.5)) & ")"
	return rtn
end rgbStringOf

on encodeEntities(htmlText)
	set oldDelims to AppleScript's text item delimiters
	
	set AppleScript's text item delimiters to the "&"
	set the itemList to every text item of htmlText
	set AppleScript's text item delimiters to the "&amp;"
	set htmlText to the itemList as string
	
	set AppleScript's text item delimiters to the "<"
	set the itemList to every text item of htmlText
	set AppleScript's text item delimiters to the "&lt;"
	set htmlText to the itemList as string
	
	set AppleScript's text item delimiters to the ">"
	set the itemList to every text item of htmlText
	set AppleScript's text item delimiters to the "&gt;"
	set htmlText to the itemList as string
	
	set AppleScript's text item delimiters to the "\""
	set the itemList to every text item of htmlText
	set AppleScript's text item delimiters to the "&quot;"
	set htmlText to the itemList as string
	
	set AppleScript's text item delimiters to the "'"
	set the itemList to every text item of htmlText
	set AppleScript's text item delimiters to the "&apos;"
	set htmlText to the itemList as string
	
	set AppleScript's text item delimiters to oldDelims
	return htmlText
end encodeEntities

on urlEncodeText(thisText, encodeGroupA, encodeGroupB)
	set the acceptableCharacters to "abcdefghijklmnopqrstuvwxyz0123456789"
	set the aCharacters to "$+!'/?;&@=#%><{}[]\"~`^\\|*"
	set the bCharacters to ".-_:"
	
	if encodeGroupA is false then ¬
		set the acceptableCharacters to the acceptableCharacters & the aCharacters
	if encodeGroupB is false then ¬
		set the acceptableCharacters to the acceptableCharacters & the bCharacters
	
	set the encodedText to ""
	repeat with thisChar in thisText
		if thisChar is in the acceptableCharacters then
			set the encodedText to (the encodedText & thisChar)
		else if thisChar is in " " then
			set the encodedText to (the encodedText & "+")
		else
			set the encodedText to (the encodedText & urlEncodeCharacter(thisChar)) as string
		end if
	end repeat
	
	return the encodedText
end urlEncodeText

on urlEncodeCharacter(thisChar)
	set the asciiNumber to (the ASCII number thisChar)
	set the hexList to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
	
	set x to item ((asciiNumber div 16) + 1) of the hexList
	set y to item ((asciiNumber mod 16) + 1) of the hexList
	return ("%" & x & y) as string
end urlEncodeCharacter

on get_rating(the_track, EncodingIsUTF)
	tell application "iTunes"
		set the_rating to the rating of the_track
	end tell
	if the_rating is not missing value and the_rating is not equal to 0 then
		tell application "iTunes"
			if not (exists the rating of the_track) or the_rating is missing value then
				return ""
			else
				set stars to (the_rating div 20) as integer
				if the_rating is greater than 0 and stars is equal to 0 then
					set stars to 1
				end if
			end if
		end tell
		if not EncodingIsUTF then return "(" & stars & " stars)"
		
		set starString to "("
		
		set fullstar to "&#x272E;"
		set emptystar to "&#x2729;"
		
		if stars is equal to 0 then
			set starString to "<font color=\"grey\">"
			repeat with i from 1 to 5
				set starString to starString & emptystar
			end repeat
			set starString to starString & "</font>"
		else
			repeat with i from 1 to stars
				set starString to starString & fullstar
			end repeat
			repeat with i from stars to 4
				set starString to starString & emptystar
			end repeat
		end if
		set starString to starString & ")"
		return starString
	else
		return ""
	end if
end get_rating

using terms from application "Colloquy"
	on process user command c with arguments for view
		if c is in {"itunes", "music"} then
			try
				tell application "System Events"
					set itunesRunning to ((application processes whose name is equal to "iTunes") count) is greater than 0
				end tell
				if (arguments is "" or arguments is missing value) then
					set theitunes to my getitunes(encoding of view is UTF8)
					if theitunes is "not running" then
						set msg to "isn't running iTunes currently."
					else if theitunes is "paused" then
						set msg to "has iTunes paused."
					else if theitunes is "unknown track type" then
						set msg to "is listening to an unknown type of track."
					else
						set msg to "is listening to " & theitunes
					end if
					tell view to send message msg with action tense
				else if first word of arguments is "open" then
					ignoring application responses
						tell application "iTunes" to activate
					end ignoring
				else if first word of arguments is "quit" and itunesRunning then
					ignoring application responses
						tell application "iTunes" to quit
					end ignoring
				else if first word of arguments is "play" then
					ignoring application responses
						tell application "iTunes" to play
					end ignoring
				else if first word of arguments is "pause" and itunesRunning then
					ignoring application responses
						tell application "iTunes" to pause
					end ignoring
				else if first word of arguments is "stop" and itunesRunning then
					ignoring application responses
						tell application "iTunes" to stop
					end ignoring
				else if first word of arguments is "next" and itunesRunning then
					ignoring application responses
						tell application "iTunes" to next track
					end ignoring
				else if first word of arguments is "previous" and itunesRunning then
					ignoring application responses
						tell application "iTunes" to previous track
					end ignoring
				else if first word of arguments is "rating" and itunesRunning then
					set EncodingIsUTF to (encoding of view is UTF8)
					--if the command is just "/itunes rating", this try block will cause an error in the first line, skip the rest of the block, and no one will be the wiser. Otherwise, it will set the rating then continue the script.
					
					try
						set theRating to (word 2 of arguments) as number
						tell application "iTunes"
							if player state is playing then
								set rating of current track to theRating * 20
							end if
						end tell
						
					end try
					
					tell application "iTunes"
						if player state is playing then
							set starString to my get_rating(current track, EncodingIsUTF)
							set msg to "iTunes song rating: " & starString
							set actionTense to false
						else
							set msg to "has iTunes paused"
							set actionTense to true
						end if
					end tell
					if actionTense then
						tell view to send message msg with action tense
					else
						tell view to send message msg
					end if
					
				else if first word of arguments is "stats" and itunesRunning then
					try
						set args to words 2 through -1 of arguments
					on error
						set args to ""
					end try
					tell view to send message "'s " & my getStats(args) with action tense
				else if first word of arguments is "prefs" then
					tell view to add event message "<a href=\"listening\">Control-click (or right-click) here for iTunes Prefs</a>" with name "itunes"
					return true
				end if
				
				return true
			on error err
				display dialog err
			end try
		else if c is "reload" then
			if arguments is "prefs" then
				my reloadprefs()
			end if
			return false
		end if
		
		return false
	end process user command
	
	(*	on process incoming chat message m
		my loadPrefs()
		if prefs's getKey("Link Songs") is in {missing value, false} then
			return m
		end if
		if body of m starts with "is listening to " and action tense of m is true and prefs's getKey("Link Songs") is true then
			set segments to attribute run of m
			if (count of segments) ≥ 3 and item 1 of segments is "is listening to " then
				try
					set theSong to item 2 of segments
					
					set theArtist to missing value
					if (count of segments) is greater than or equal to 4 and item 3 of segments is equal to " by " then set theArtist to item 4 of segments
					
					set theAlbum to missing value
					if (count of segments) is greater than or equal to 6 and item 5 of segments is equal to " from " then set theAlbum to item 6 of segments
					if (count of segments) is greater than or equal to 4 and item 3 of segments is equal to " from " then set theAlbum to item 4 of segments
					
					set initialSearch to "itms://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?"
					set artistSearch to initialSearch
					set albumSearch to initialSearch
					set delim to ""
					
					if theArtist is not missing value then
						set artistSearch to artistSearch & "artistTerm=" & my urlEncodeText(theArtist, true, true)
						set albumSearch to artistSearch
						set delim to "&"
						set link of attribute run 4 of m to artistSearch
						set style classes of attribute run 4 of m to {"itunes"}
					end if
					
					if theAlbum is not missing value then
						set albumSearch to albumSearch & delim & "albumTerm=" & my urlEncodeText(theAlbum, true, true)
						set delim to "&"
						if theArtist is missing value then
							set albumIndex to 4 --which attribute is the album string
						else
							set albumIndex to 6
						end if
						set link of attribute run albumIndex of m to albumSearch
						set style classes of attribute run albumIndex of m to {"itunes"}
					end if
					
					set songSearch to albumSearch & delim & "songTerm=" & my urlEncodeText(theSong, true, true)
					set link of attribute run 2 of m to songSearch
					set style classes of attribute run 2 of m to {"itunes"}
				on error err
					display dialog err
				end try
			end if
		end if
	end process incoming chat message *)
	
	on build contextual menu for item theItem
		try
			if theItem contains "listening" then
				my loadPrefs()
				tell prefs to set sm to getContextMenu()
				return {title:"iTunes Script Settings", submenu:sm}
			end if
		on error err
			--			return {title:"iTunes script got an error!!", submenu:{{title:err, enabled:false}, {title:build of prefs as string}}}
		end try
	end build contextual menu for item
	
	on handle clicked contextual menu item theItem within theParents
		if theParents is {"iTunes Script Settings"} then
			try
				prefs's changekey(theItem)
				my savePrefs()
			on error err
				display dialog err
			end try
		end if
	end handle clicked contextual menu item
end using terms from

script prefsTemplate
	property defaultKeys : {¬
		{label:"Show Rating", value:true}, ¬
		{label:"Show Colors", value:true}, ¬
		{label:"Link Songs", value:true}, ¬
		{label:"Show Time", value:false}, ¬
		{label:"Show Progress Bar", value:false}, ¬
		{label:"--Left Progress Bar Color", value:{40000, 40000, 40000}}, ¬
		{label:"--Progress Bar Marker Color", value:{40000, 40000, 40000}}, ¬
		{label:"--Right Progress Bar Color", value:{40000, 40000, 40000}}, ¬
		{label:"Show Bit Rate", value:false} ¬
			}
	property theKeys : defaultKeys
	property build : 10 --increment each time you change something where prefs needs to change
	
	--returns true if the value was found, false if the value had to be created
	on setKey(thisLabel, newValue)
		repeat with k in theKeys
			if label of k is thisLabel then
				set value of k to newValue
				return true
			end if
		end repeat
		set theKeys to theKeys & {{label:thisLabel, value:newValue}}
		return false
	end setKey
	
	--like setKey, except it handles the interface: if it's boolean it toggles it, if it's a string it will ask for a new value, etc
	on changekey(thisLabel)
		set asd to AppleScript's text item delimiters
		set AppleScript's text item delimiters to " ("
		set thisLabel to text item 1 of thisLabel
		set oldvalue to getKey(thisLabel)
		set AppleScript's text item delimiters to asd
		if oldvalue is missing value then
			display dialog "That item (" & thisLabel & ") does not exist"
			return
		else if class of oldvalue is boolean then
			setKey(thisLabel, not oldvalue)
		else if class of oldvalue is string then
			set ans to (text returned of (display dialog "New value?" default answer oldvalue) as string)
			setKey(thisLabel, ans)
		else if class of oldvalue is integer then
			set ans to text returned of (display dialog "New value?" default answer oldvalue)
			setKey(thisLabel, ans as integer)
		else if class of oldvalue is list then
			if number of items in oldvalue is 3 then ---must be a color
				set ans to choose color default color oldvalue
				setKey(thisLabel, ans)
			else
				display dialog "Cannot edit lists of items."
			end if
		end if
	end changekey
	
	on getKey(thisLabel)
		repeat with k in theKeys
			if label of k is thisLabel then
				return value of k
			end if
		end repeat
		return missing value
	end getKey
	
	on listKeys()
		set final to ""
		repeat with k in theKeys
			set final to final & label of k & ": " & (value of k as string) & return
		end repeat
		return final
	end listKeys
	
	on getContextMenu()
		set final to {}
		try
			repeat with k in theKeys
				if class of value of k is boolean then
					set final to final & {{title:label of k, checked:value of k}}
				else if class of value of k is integer or class of value of k is string then
					set final to final & {{title:label of k & " (" & value of k & ")"}}
				else if class of value of k is list then
					set asd to AppleScript's text item delimiters
					set AppleScript's text item delimiters to ", "
					if number of items in value of k < 3 then
						set final to final & {{title:label of k & " (" & (every item of value of k as string) & ")"}}
					else if number of items in value of k is 3 then
						set final to final & {{title:label of k, icon:value of k}}
					else
						set final to final & {{title:label of k & " (" & (items 1 through 3 of value of k as string) & ", ...)"}}
					end if
					set AppleScript's text item delimiters to asd
				end if
			end repeat
			return final
		on error err
			return {{title:"iTunes script got an error: " & err, enabled:false}}
		end try
	end getContextMenu
end script

on loadPrefs()
	if prefs is missing value then
		set prefsPath to (path to preferences folder from user domain as Unicode text) & "Colloquy Prefs - iTunes"
		try
			set prefs to load script alias prefsPath
			try
				set oldbuild to build of prefs
			on error
				set oldbuild to -1
			end try
			if oldbuild < build of prefsTemplate then
				set newPrefs to prefsTemplate
				set newPrefs to my mergeKeys(prefs, prefsTemplate)
				set prefs to newPrefs
				my savePrefs()
			end if
		on error
			set prefs to prefsTemplate
		end try
	end if
end loadPrefs

on savePrefs()
	if prefs is not missing value then store script prefs in file prefsPath replacing yes
end savePrefs

--This function is used to merge keys of the old list with the values of the new one.
--Note that the first parameter is the old version of the prefs (from which the values need to be kept), and the second contains the new list (with default values to be overwritten by values gotten from oldPrefs
--returns the list to set theKeys to
on mergeKeys(oldPrefs, newDefaultPrefs)
	try
		repeat with k in theKeys of newDefaultPrefs
			set oldvalue to oldPrefs's getKey(label of k)
			if oldvalue is not missing value then
				set value of k to oldvalue
			end if
		end repeat
	end try
	return newDefaultPrefs
end mergeKeys
on getitunes(EncodingIsUTF)
	tell application "System Events"
		set itunesRunning to ((application processes whose name is equal to "iTunes") count) is greater than 0
	end tell
	if itunesRunning then
		tell application "iTunes"
			if player state is playing then
				return item 1 of my getitunesFor(EncodingIsUTF, current track)
			else
				return "paused"
			end if
		end tell
	else
		return "not running"
	end if
end getitunes

on getitunesFor(EncodingIsUTF, trackID)
	tell application "System Events"
		set itunesRunning to ((application processes whose name is equal to "iTunes") count) is greater than 0
	end tell
	set fullmsg to {}
	if itunesRunning then
		my loadPrefs()
		tell application "iTunes"
			if class of trackID is not list then set trackID to {trackID}
			repeat with thisTrackID in trackID
				if class of thisTrackID is integer then
					set thisTrack to (first track of library playlist 1 whose database ID is thisTrackID)
				else if class of thisTrackID is in {track, file track, URL track, device track, shared track, audio CD track} then
					set thisTrack to thisTrackID
				else
					error "Unknown class" number 3245
				end if
				if class of thisTrack is in {track, file track, URL track, device track, shared track, audio CD track} then
					if class of thisTrack is URL track then
						set theSong to current stream title
						if theSong is missing value then
							set theSong to name of thisTrack
							set theAlbum to missing value
						else
							set theAlbum to name of thisTrack
						end if
						set theArtist to missing value
					else
						set theArtist to artist of thisTrack
						set theAlbum to album of thisTrack
						set theSong to name of thisTrack
					end if
					
					set showColors to prefs's getKey("Show Colors")
					if showColors then
						set msg to "<font color=\"maroon\">" & my encodeEntities(theSong) & "</font>"
					else
						set msg to my encodeEntities(theSong)
					end if
					if theArtist is not "" and theArtist is not missing value then
						if showColors then
							set msg to msg & " by <font color=\"green\">" & my encodeEntities(theArtist) & "</font>"
						else
							set msg to msg & " by " & my encodeEntities(theArtist)
						end if
					end if
					if theAlbum is not "" and theAlbum is not missing value then
						if showColors then
							set msg to msg & " from <font color=\"teal\">" & my encodeEntities(theAlbum) & "</font>"
						else
							set msg to msg & " from " & my encodeEntities(theAlbum)
						end if
					end if
					if prefs's getKey("Show Rating") then
						set msg to msg & " " & my get_rating(thisTrack, EncodingIsUTF)
					end if
					if prefs's getKey("Show Time") then
						set msg to msg & " " & my get_tracklength(0, EncodingIsUTF)
					end if
					if prefs's getKey("Show Progress Bar") then
						set msg to msg & " " & my get_tracklength(10, EncodingIsUTF)
					end if
					if prefs's getKey("Show Bit Rate") then
						set theKind to kind of thisTrack
						if theKind contains "MPEG" then set theKind to "MP3"
						if theKind contains "AAC" then set theKind to "AAC"
						if theKind contains "WAV" then set theKind to "WAV"
						if theKind contains "Apple Lossless" then set theKind to "Apple Lossless"
						set msg to msg & " (" & bit rate of thisTrack & " kbps " & theKind & ")"
					end if
				else
					set msg to "unknown track type"
				end if
				set fullmsg to fullmsg & {msg}
				
			end repeat
		end tell
	end if
	return fullmsg
end getitunesFor

on getStats(args)
	tell application "iTunes"
		if args is "" then
			set lib to library playlist 1
			set libName to name of library playlist 1
		else
			try
				set lib to some playlist whose name contains args
				set libName to "Playlist \"" & name of (some playlist whose name contains args) & "\""
			on error
				set lib to ""
			end try
		end if
		if lib ≠ "" then
			if size of lib < 1.0E+9 then
				set mysize to (round (size of lib) / 1024 / 1024 * 100 as string) / 100 & " MB"
			else
				set mysize to ((round (size of lib) / 1024 / 1024 / 1024 * 100) / 100 as string) & " GB"
			end if
			set res to "iTunes " & libName & " is " & time of lib & " long, with " & (count tracks in lib) & " songs totalling " & mysize & "."
		else
			set res to ""
		end if
	end tell
	if res ≠ "" then
		return res
	end if
end getStats