I'm trying to make an AppleScript which can play top songs of some artist. I've seen an iTunes script library via ScriptEditor but did't find anything useful for me. Hope someone can forward me in the right direction, if this case is possible to do. Thanks.
The basic way of getting tracks from iTunes is using get every track. For example:
tell application "iTunes" to set topTracks to every track of playlist "Library" whose artist is "Golden Earring" and rating is 100
Ratings are 1 to 5 stars (or no stars) in the iTunes GUI, but are 0 to 100 in the backend. Multiply the rating by 20 for the backend rating (or divide the backend rating by 20 for the GUI star count), with zero stars equalling 0.
There is a quirk in iTunes; adding and rating is 100 makes the query much slower, as if it’s doing a search on both queries and putting them together, rather than doing the easy one (artist) and then the hard one (rating). Because of that, this will probably be much, much faster at getting all of the five-rated tracks of a particular artist:
tell application "iTunes"
set artistTracks to every track of playlist "Library" whose artist is "Golden Earring"
set topTracks to {}
repeat with possibleTrack in artistTracks
if the rating of possibleTrack is 100 then copy possibleTrack to end of topTracks
end repeat
end tell
Now, if by “top songs", you mean the top x songs, then there is no guarantee that there will be enough rating five tracks to reach x. So if you want a specific number of tracks, you would have to grab the rating 5 tracks, see if you have enough, and if not, grab the rating 4 tracks, and so on. Here is one example of how to do that; there are many more. How, exactly, you do it will depend partly on how you define “top songs”.
tell application "iTunes"
set desiredArtist to "chi coltrane"
--get topCount tracks
set topCount to 5
set fiveStars to {}
set fourStars to {}
set threeStars to {}
set twoStars to {}
set oneStar to {}
set noStars to {}
set allTracks to every track of playlist "Library" whose artist is desiredArtist
--collect tracks into bins according to star rating
--this is much faster than doing five searches with "and rating is"
repeat with possibleTrack in allTracks
copy (rating of possibleTrack) / 20 as integer to starRating
if starRating is 5 then
copy possibleTrack to end of fiveStars
else if starRating is 4 then
copy possibleTrack to end of fourStars
else if starRating is 3 then
copy possibleTrack to end of threeStars
else if starRating is 2 then
copy possibleTrack to end of twoStars
else if starRating is 1 then
copy possibleTrack to end of oneStars
else
copy possibleTrack to end of noStars
end if
end repeat
end tell
--collect the top tracks
set topTracks to {}
getTracks(fiveStars)
getTracks(fourStars)
getTracks(threeStars)
getTracks(twoStars)
getTracks(oneStar)
getTracks(noStars)
--play the tracks, if any
if (count of topTracks) > 0 then
tell application "iTunes"
repeat with topTrack in topTracks
set topTrackID to the persistent ID of topTrack
play topTrack
--wait until this song is no longer playing, then go to the next
repeat while the persistent ID of current track is topTrackID
--delay a tenth of a second to avoid too much of the next random track
delay 0.1
end repeat
end repeat
end tell
end if
--add more tracks from the given trackList, until topCount is reached
--within a list, the choice of which tracks to use to reach topCount is somewhat arbitrary
on getTracks(trackList)
global topTracks, topCount
if (count of topTracks) ≥ topCount then return
repeat with possibleTrack in trackList
if (count of topTracks) ≥ topCount then
return
end if
copy possibleTrack to end of topTracks
end repeat
end getTracks
Other options for choosing when to advance to the next track in the topTracks list might include delaying for the duration of topTrack as number, if you are reasonably certain that no one will pause or advance the tracks in the GUI; it is also possible to set a handler that receives notification when a track changes.
Related
Basically I have a script that im running on my mac using script editor to prevent my character from be kicked due to AFK. Here is what I have right now.
delay 5
repeat 10000 times
tell application "System Events"
key down "w"
delay (random number from 0.5 to 1)
key up "w"
key down "s"
delay (random number from 0.5 to 1)
key up "s"
delay (random number from 20 to 30)
end tell
end repeat
Basically I just want to add a counter so I can see how long it has been running. Ideally it would show the total time elapsed and not the amount of times the script has been repeated, but either would work.
I want my script to be listening/detecting any keystroke(any key pressed) via keyboard. If no key is pressed for about 5seconds, then continue to do something. Otherwise, keep on recording the keys pressed in a text edit.
Any help would be greatly appreciated.
Since you specified TextEdit in your question, I wrote a script for you that checks for changes in a TextEdit document within the specified number of seconds. Do note that this only detects keys that input something into the document, so it's not exactly what you wanted. However, there's no way to detect any and every key being pressed in raw AppleScript, so this is the closest you can get (unless someone wrote a Scripting Addition or agent application to do that).
Here's the script, hope it is of use:
global lastText, lastTime, startTime
on run
set lastText to application "TextEdit"'s (text of the document of the front window)
set lastTime to current date
set startTime to current date
repeat
if (checkForRecentTextUpdate given seconds:5) is true then
-- Do something while the user is typing
else
-- Do something after the user has stopped typing
exit repeat -- This is only an example
end if
end repeat
end run
to checkForRecentTextUpdate given seconds:secsRequired
tell application "TextEdit"
-- If midnight just passed, reset the last time
if (the day of (the current date)) > (the day of the lastTime) ¬
then set lastTime to current date
-- If we just started, we can't judge; give a positive
if ((the time of (the current date)) - (the time of the startTime)) < secsRequired ¬
then return true
-- If there have been changes since the last run, update info
if (the text of the document of the front window) ≠ the lastText then
set lastTime to the current date
set lastText to the text of the document of the front window
end if
-- If the specifiied number of seconds has passed without any text updates, give a negative
if ((the time of (the current date)) - (the time of the lastTime)) ≥ secsRequired ¬
then return false
-- If we got this far, there were changes in the seconds specified; give a positive
return true
end tell
end checkForRecentTextUpdate
I have the following script that successfully retrieves the current track and updates my Messages (iChat) status, but for this to work autonomously I guess I need to run it on a loop? Recommendations for that?
tell application "Rdio"
set theTrack to current track
set theArtist to artist of theTrack
set theName to name of theTrack
end tell
tell application "Messages"
if status is available then
set status message to ("♫ Playing in Rdio: " & (theArtist as string) & " - " & (theName as string))
end if
end tell
Unless Rdio has the ability to trigger scripts on certain condition (which you would have to check for yourself, as I am not a Rdio user myself – the rather sparse Rdio AppleScript docs on site do not indicate anything about that), your best chance to achieve this is to store your script as a Stay-Open AppleScript Application and put the script proper in the on idle handler. The AppleScript Language Guide has the nitty-gritty on this, if you want to look it up, but the basic procedure is:
wrap your script above in an on idle handler, i.e.:
on idle
tell application "Rdio"
set theTrack to current track
set theArtist to artist of theTrack
set theName to name of theTrack
end tell
tell application "Messages"
if status is available then
set status message to ("♫ Playing in Rdio: " & (theArtist as string) & " - " & (theName as string))
end if
end tell
return 0 -- change this to stray from the default 30 sec. interval
end idle
save the script as an AppleScript Application, making sure you check Stay open in the saving sheet.
Launch your newly created AppleScript app, and you are good to go – it will keep running, executing the idle handler periodically (every 30 seconds by default – you can change that value by returning an integer value from the idle handler, which will be evaluated as the number of seconds until the next check. If you want to be fancy, and the Rdio AS interface supports it, you could use the remaining playing time of your song, say…)
I am trying to create a simple program that loops for user speech input using com.apple.speech.recognitionserver. My code thus far is as follows:
set user_response to "start"
repeat while user_response is not equal to "Exit"
tell application id "com.apple.speech.recognitionserver"
set user_response to listen for {"Time", "Weather", "Exit"} with prompt
"Good Morning"
end tell
if user_response = "Time" then
set curr_time to time string of (the current date)
set curr_day to weekday of (the current date)
say "It is"
say curr_time
say "on"
say curr_day
say "day"
else if user_response = "Weather" then
say "It is hot outside. What do you expect?"
end if
end repeat
say "Have a good day"
If the above is run on my system it says good morning and it then pops up with the speech input system and waits for either Time, Weather, or Exit. They all do what they say they are going to do, but instead of looping if I say Time and Weather and asking again until I say exit the speechserver times out and never pops up again. Is there a way of either keeping that application open until the program ends or is applescript not capable of looping for user speech input?
If you don't find a way to keep speech recognition open, try adding a delay before you call it again. I recall (long ago) finding that events can be just lost if you try to send an event to an application that's already in the middle of quitting (it doesn't reopen the application).
Before your end Repeat add
tell application "SpeechRecognitionServer"
quit
end tell
After about 35 seconds it will repeat, it is slow as honey on a cold day but it works. give it a try.
Here is a Simple Example:
repeat
tell application "SpeechRecognitionServer"
set theResponse to listen for {"yes", "no"} with prompt "open a finder?"
set voice to (theResponse as text)
end tell
if voice contains "yes" then
tell application "Finder"
activate
end tell
else
say "not understood"
end if
tell application "SpeechRecognitionServer"
quit
end tell
end repeat
I'm trying to set the tracks of a user playlist using AppleScript. I don't want the tracks to be added, I want them to replace the current tracks. Before I do that, I need to look up the tracks by their persistent IDs, which is working fine, but the statement that sets the tracks isn't working. Code snippet below:
set fixed indexing to true
set myPlaylist to the first item of (every user playlist whose persistent ID is "5C768EFF306E3366")
set tracksPIDs to {"66EB935073027EDD", "B6807694FEDD76B4"}
set resolvedTracks to {}
--resolve the tracks
repeat with trackPID in tracksPIDs
set myTrack to the first item of (every track whose persistent ID is equal to trackPID)
set end of resolvedTracks to myTrack
end repeat
set (the tracks of my myPlaylist) to duplicate of (resolvedTracks)
Also, how can I remove all tracks from a playlist (i.e set it to empty list)?
To do what you want, you will need to do two steps, first removing the existing tracks from the playlist, then adding in the tracks that you want to be in the playlist. The first step would look like:
delete every track of myPlaylist
Then the addition would look like:
duplicate resolvedTracks to myPlaylist