Detect the end of a Spotify track with Applescript? - macos

I'm writing an Applescript that displays a notification with the name, album, and artist of the current Spotify track. Yes, I'm aware there is already an app that does this, but even with the latest version, it's very buggy and behaves erratically.
So far, I have a good little script. Here it is:
repeat until application "Spotify" is not running
tell application "Spotify"
set theSong to name of current track
set theAlbum to album of current track
set theArtist to artist of current track
set theTime to player position
set theDuration to duration of current track
end tell
(* This sets the amount of delay to the length of the song minus the current place in the song, which leaves us with the amount of time left until the next song plays.*)
set delayTime to theDuration - theTime + 0.5
tell application "Spotify"
if player state is playing then
display notification theArtist with title theSong subtitle theAlbum
end if
delay delayTime
end tell
end repeat
Basically, the problem with this is if I pause or change the track, delay stays the same and thus doesn't display the notification when the song starts.
I used delay in this script because I don't really know a better way of checking for the end of a track. Is there any Applescript event for the end of a song (or the beginning of a new one?)
Thanks.
P.S., If this question is too complicated, feel free to ask more.

Use a loop to check the current track, exit the loop when the song change
repeat until application "Spotify" is not running
tell application "Spotify"
set theSong to name of current track
set theAlbum to album of current track
set theArtist to artist of current track
set thisTrack to current track
if player state is playing then
display notification theArtist with title theSong subtitle theAlbum
repeat until thisTrack is current track
delay 3
end repeat
end if
end tell
end repeat

Related

In Applescript, Retrive playlist information from Spotify, and enable/disable shuffling

I know that there are many commands in AppleScript for Spotify such as the simple playpause command, but how would I pull a playlist's information from Spotify, and paste it in a choose from list? I would like it to take all of the songs from wherever you're listening from, and paste them in a choose from list so you can choose which song you would like to listen to. Is this even possible? Can I do something similar?
Also, how would you enable/disable shuffling?
Additionally, is there a way to search Spotify through AppleScript?
I'm not sure if any of these are possible, and Google doesn't have any info on this right now. Does anyone know how to do this?
The Spotify AppleScript implementation does not have specific commands to get at playlist information -- it only exposes "current track" to get info about the currently-playing track and "next track" to play the next track. You can work around this limitation to build an AppleScript array containing all the tracks in a current playlist.
set trackNameList to {}
set trackIDList to {}
tell application "Spotify"
activate
set shuffling to false
set repeating to true
set sound volume to 0
if player state is not playing then
playpause
end if
set trackID to spotify url of current track
repeat while trackIDList does not contain trackID
set end of trackIDList to trackID
set end of trackNameList to name of current track
next track
delay 1 -- otherwise Spotify misbehaves
set trackID to spotify url of current track
end repeat
end tell
tell me to activate
set chosenNames to choose from list trackNameList without multiple selections allowed
set chosenName to (item 1 of chosenNames) as string
repeat with i from 1 to count of trackNameList
set itsName to (item i of trackNameList) as string
if itsName is chosenName then
exit repeat
end if
end repeat
set trackID to (item i of trackIDList) as string
tell application "Spotify"
activate
set sound volume to 100
play track trackID
end tell
There is no AppleScript support for searching in Spotify.

Preview songs in Spotify with Applescript - NeedleDrop from Doug

We all know Doug's applescripts for iTunes. However, with the growth of streaming music, I don't use iTunes so much anymore, but rather Spotify.
I was trying to adapt the NeedleDrop script to preview songs. The script allows to set
a - A start from given time, f.e. start playing the songs at 30 seconds
b - Play that song for a given time, f.e. 10 seconds.
The problem is the script starts the first song at the given time and plays for the given time, but then, the next songs play for a given time, but start at the beginning instead of the given value in time.
The script is under GNU license by Doug and the license is included.
I'm posting both the script and the exported app from it. If anyone has an idea ?!
LINK: Download
Here is the script provided in the download file:
-- handler to get a number from user
to get_a_number(pmpt, addenda, defnum)
set rez to (display dialog addenda & pmpt default answer defnum buttons {"Cancel ", "OK"} default button 2 with title "Needle Drop")
if button returned of rez starts with "cancel" then tell me to quit
set myNumber to text returned of rez
try
if myNumber is "" then get_a_number(pmpt, "Enter only numbers..." & return & return, defnum)
return (myNumber as integer)
on error -- m number n
get_a_number(pmpt, "Enter only numbers..." & return & return, defnum)
end try
end get_a_number
global start_time -- seconds into each track to begin playing
global needle_drop_interval -- seconds to play each track
on run
-- get number of seconds between songs
set needle_drop_interval to my get_a_number("Play each track for how many seconds?", "", "10")
-- get seconds into each track to play
set start_time to my get_a_number("How many seconds into each track to start playing?", "", "10")
-- play first song in the playlist
tell application "Spotify"
activate
set player position to start_time
play
delay needle_drop_interval
end tell
end run
on idle
tell application "Spotify"
if player state is not playing then tell me to quit
pause
next track
set player position to start_time
play
end tell
return needle_drop_interval
end idle
on quit
try
tell application "Spotify" to stop
end try
continue quit
error number -128
end quit
The provided script works fine for offline playlists but not for streamed ones. Spotify probably doesn't have time to buffer the track or something otherwise.
When I added a delay to give spotify time to buffer it worked fine. (You can experiment with shorter and longer delays)
tell application "Spotify"
if player state is not playing then tell me to quit
next track
pause
set player position to start_time
delay 1
play
end tell
Note the row switch between 'next track' and 'pause'
Amazing !
However, after some songs, the bug still happened sometimes, which seems to get totally fixed by adding a delay before the set player position.
This could sound contradictory, but worked better for me.
Thanks !
on idle
tell application "Spotify"
if player state is not playing then tell me to quit
next track
pause
delay 1
set player position to start_time
play
end tell
return needle_drop_interval
end idle

AppleScript to play a song with a specific artist in iTunes?

I'm trying to run an Applescript that will play a song in iTunes. The problem is I need the song to have a specific artist as well. Whenever I write some script that uses "artist" I get an error stating that artist could not be accessed.
tell application "iTunes"
activate
play track "My Song"
end tell
this code works to play a track but I also need to specify the artist so that a track with the same name isn't accidentally played. Any help is greatly appreciated.
Thanks,
Sam
Adjust as necessary.
tell application "iTunes"
set mySongs to every track of library playlist 1 whose artist is "Styx" and name is "boat on the river"
repeat with aSong in mySongs
play aSong
end repeat
end tell

Applescript for controlling iTunes and Rdio

I have an Applescript I use in conjunction with Alfred that plays or pauses the current track in iTunes or Rdio, depending on which I have open. In my script Rdio takes precedence because I always have iTunes open and only open Rdio when I need it for a specific purpose.
Often, when a track is playing in iTunes and I hit my global shortcut to run this script it takes up to 15 seconds to stop the track. I wanted to share the script here and see if there might be a glaring issue, or if there is a much simpler, more efficient way to handle it.
I appreciate any help I can get!
tell application "System Events"
if (name of processes) contains "iTunes" then
set iTunesRunning to true
else
set iTunesRunning to false
end if
if (name of processes) contains "Rdio" then
set RdioRunning to true
else
set RdioRunning to false
end if
end tell
if RdioRunning then
tell application "Rdio"
if player state is paused or player state is stopped then
play
else if player state is playing then
pause
end if
end tell
else if iTunesRunning then
tell application "iTunes"
if player state is paused or player state is stopped then
play
else if player state is playing then
pause
end if
end tell
end if
It's difficult to track down such issues. In general your script looks fine. Here's some ideas that may help with your problem though.
In general applescripts are interpreted at run-time which means that every time you run your script the byte-code has to be changed into machine language code by another program (applescript runner)... this is normally not a problem but in your case maybe it's causing some slowness. So the idea is to write your script so that doesn't need to happen. We can do that by saving the script as an applescript application because applications are saved in the machine language form and thus do not require another program to execute the code. In addition we can take advantage that the commands for both applications are identical, so we can use a "using terms from" block. In your code you query system events for the "name of processes" twice, so the last optimization we can make is to only do that once.
So try this and see if it helps. I'm not certain it will but it's worth a try. Remember to save it as an application.
tell application "System Events" to set pNames to name of application processes
if "Rdio" is in pNames then
set appName to "Rdio"
else if "iTunes" is in pNames then
set appName to "iTunes"
else
return
end if
using terms from application "iTunes"
tell application appName
if player state is paused or player state is stopped then
play
else if player state is playing then
pause
end if
end tell
end using terms from
EDIT: If the above code doesn't work then try this. As mentioned, try it as an application and see if it helps. The same principles apply... one less query of system events and saving as an application to prevent needing to interpret the code.
tell application "System Events" to set pNames to name of application processes
if "Rdio" is in pNames then
tell application "Rdio"
if player state is paused or player state is stopped then
play
else if player state is playing then
pause
end if
end tell
else if "iTunes" is in pNames then
tell application "iTunes"
if player state is paused or player state is stopped then
play
else if player state is playing then
pause
end if
end tell
end if

Limit ringtone length AppleScript

I have the AppleScript code shown below which tells iTunes to convert the track from the selection. I was wondering how I would limit the length of the track that will be converted?
tell application "iTunes"
set theFiles to the selection
repeat with theTrack in theFiles
with timeout of 120 seconds
set theSecondTrack to first item of (convert theTrack)
If you wanted to to limit the length of the converted track via the iTunes GUI, you would set the "Stop Time" of the original track in Get Info>Options. The corresponding AppleScript property for this is finish (of the track class).
So the steps in your repeat loop should be:
Get the original stop time of the track (usually this will just be the full duration of the track)
Set the stop time to your limit length (in seconds)
Convert the track
Set the stop time back to what it was at 1.
Example 60-sec limit:
repeat with theTrack in theFiles
tell theTrack
set originalFin to finish
set finish to 60
-- Track conversion code goes here
set finish to originalFin
end tell
end repeat

Resources