AppleScript: how do I check which apps are playing audio? - applescript

I'm new to AppleScript and I'm trying to write a script that changes the volume in whatever app is playing audio [iTunes, Spotify, whatever].
Is there a way for AppleScript to check which apps are currently playing audio? I've searched for an answer to this but came up empty...
correction:
I found this link http://hypertext.net/2011/11/applescript-powermate-media-apps/
which has this script:
--Define the lastPaused property and give it a default value
property lastPaused : ""
--Get current states of iTunes and Spotify
tell application "iTunes" to set itunesState to (player state as text)
tell application "Spotify" to set spotifyState to (player state as text)
--Pause the active app; play the last-paused app
if itunesState is equal to "playing" then
tell application "iTunes" to playpause
set lastPaused to "iTunes"
else if spotifyState is equal to "playing" then
tell application "Spotify" to playpause
set lastPaused to "Spotify"
else if ((itunesState is equal to "paused") and (lastPaused is equal to "iTunes")) then
tell application "iTunes" to playpause
else if ((spotifyState is equal to "paused") and (lastPaused is equal to "Spotify")) then
tell application "Spotify" to playpause
end if
so, this works for iTunes/Spotify but not for anything else playing audio.
can't applescript just check what app is playing audio and stop it [without having to hard code the app names?]

Short answer: AppleScript can't do that as a generic solution

Related

Open/search Spotify track in Apple Music (with Applescript)

I'd like an easy way to switch from a Spotify release to the same release in Apple Music.
I already found a way to search for the currently playing Spotify track in the Apple Music web player with Applescript:
tell application "Spotify"
if player state is not stopped then
set currentArtist to artist of current track as string
set currentTrack to name of current track as string
open location "https://music.apple.com/search?term=" & currentArtist & " " & currentTrack
end if
end tell
I'd love to:
Open the search in the native Music.app, not the web player. Is this supported?
Ideally not do a search, but go straight to the same release. Maybe with ISRC codes?
Take any selected Spotify track, not just the currently playing one. Looking at the Spotify Applescript dictionary tells me this in not possible.
had a similar problem right now and quickly hacked it out. In my case I want to simply trigger a search on the Music app.
Opened Automator and created a new "Service".
Workflow receives current > "Text" > in "every application".
Here's the AppleScript:
on run {input, parameters}
tell application "Music"
activate
end tell
tell application "System Events"
tell process "Music"
set window_name to name of front window
set value of text field 1 of UI element 1 of row 1 of outline 1 of splitter group 1 of window window_name to input
keystroke ""
key code 36
end tell
end tell
return input
end run
I saved it as "Find on Music" in Automator and now I can select text, right click > Service > Find on Music and Music plops open and shows me the results for the selected text. I hope you can use some parts of it.
I just figured out how to pass text from wherever to the search field in Music, with help from daemon's answer, which no longer works. This should work for what you want to do in conjunction with what you have.
Replace your "open location" line with a variable name for your concatenated string. Add this code below yours and pass that variable in place of 'input' (in my case 'input' is text from any application, which I use to select text of an artist name in an email/webpage/message that I want to send to Music's search).
First it checks to see if the main Music window is open vs the MiniPlayer, and open it if not to enable search via cmd-O, the cmd-F to find, then passes the input and hits return:
tell application "Music"
activate
end tell
tell application "System Events"
if not (exists (window "Music" of process "Music")) then
tell process "Music"
keystroke "0" using command down
end tell
end if
tell process "Music"
keystroke "f" using command down
keystroke input
key code 36
end tell
end tell
So, something like this (I don't have Spotify to check that section, but this should work assuming your code there is correct):
tell application "Spotify"
if player state is not stopped then
set currentArtist to artist of current track as string
set currentTrack to name of current track as string
set spotTrack to currentArtist & " " & currentTrack
end if
end tell
tell application "Music"
activate
end tell
tell application "System Events"
if not (exists (window "Music" of process "Music")) then
tell process "Music"
keystroke "0" using command down
end tell
end if
tell process "Music"
keystroke "f" using command down
keystroke spotTrack
key code 36
end tell
end tell
The only thing I couldn't figure out is how to check if the search field is already in focus, because if it is, the cmd-F causes a system alert sound. Generally not an issue as typically you'll search and interact with something else before running this script again, so calling it good. :)

Getting osascript to work with iPhone and QuickTime Player

I run this script and applescript can detect the devices just fine
tell application "QuickTime Player"
video recording devices
end tell
It gives a the reply below
{screen compression preset "FaceTime HD Camera" of application "QuickTime Player", screen compression preset "Gangzheng's iPhone" of application "QuickTime Player"}
But when I run my actual script
tell application "QuickTime Player"
video recording devices
set newMovieRecording to new movie recording
tell newMovieRecording
set current camera of newMovieRecording to "Gangzheng's iPhone"
set current microphone of newMovieRecording to "Gangzheng's iPhone"
start
end tell
end tell
it says QuickTime Player got an error: Can’t make "Gangzheng's iPhone" into type video recording device.
Is there a way to make applescript record anything from iPhone?
I had accomplished what you want to do, but in a different way because I also tried with
set current camera of newMovieRecording to "Gangzheng's iPhone"
but had no luck.... So here is my script for setting a camera
tell application "System Events" to tell process "QuickTime Player"
#Set volume to 100%
click button 1 of window 1
#To open dialog to show available cameras
click button 3 of window 1
#To select our device
click menu item "Gangzheng's iPhone" of menu 1 of button 3 of window 1
end tell
My script was a bit longer because I wanted to record the screen of my iphone at my MAC... So I had to set QuickTime Player to full screen, move mouse pointer outside the screen and so on...
tell application "Finder"
set bigBounds to (get bounds of window of desktop)
end tell
tell application "QuickTime Player"
activate
start
#Start new recording cmd + option + N
tell application "System Events" to key code 45 using {option down, command down}
set iBounds to (get bounds of front window)
if bigBounds = iBounds then
delay 1
else
#Full screen only if is not already at full screen control + cmd + F
tell application "System Events" to key code 3 using {control down, command down}
delay 1
end if
tell application "System Events" to tell process "QuickTime Player"
#Set volume to 100%
click button 1 of window 1
#To open dialog to show available cameras
click button 3 of window 1
#To select our device
click menu item "iPhone de User" of menu 1 of button 3 of window 1
end tell
#To move mouse to the right side of the screen
set mouseToolsPath to "/Users/Shared/MouseTools"
set x to (item 3 of bigBounds) - 1
set y to (item 4 of bigBounds) / 2
#Por si el archivo no existe...
try
do shell script quoted form of POSIX path of mouseToolsPath & " -x " & (x as text) & " -y " & (y as text)
on error errMsg number errNum
display dialog "An unknown error occurred: " & errNum as text
end try
end tell
Hope it is helpful to someone.
barbudito, can you try this?
tell application "QuickTime Player"
get video recording device "Gangzheng's iPhone"
set newMovieRecording to new movie recording
tell newMovieRecording
start
delay 10
do shell script "env"
pause
save newMovieRecording in "/Users/pmlg673f/Movies/test.mov"
stop
close newMovieRecording
end tell
end tell
I had encountered this exact problem and made the following blog post which covers how I solved it https://kevinjalbert.com/applescript-that-mirrors-iphone-to-quicktime/. I had used some inspiration from this post and others as I looked around for a way to set the video/audio inputs via AppleScript.
The source for the AppleScript is here: https://gist.github.com/kevinjalbert/d7661a6a34c1d66dccf701f64eb09be4#file-mirror-scpt.

Spotify's "player state" is available in the editor, but in a packaged app, it gets only "«constant ****kPSP»"

Here's a testing code:
tell application "Spotify"
set playerState to player state as string
end tell
display dialog playerState
Works fine from the AppleScript editor. However, when I export my script as an app, all I get is this:
Why is this happening?
It seems that Spotify is not coercing the constant into a string. Since the editor can't coerce it from an applet as it does when you are running the script in AppleScript Editor, the four-letter constant code is returned. Since you can't test the player state's value as a string, try to test it against the constants themselves.
property spotPause : «constant ****kPSp»
property spotPlay : «constant ****kPSP»
tell application "Spotify" to set playerState to player state
if playerState = spotPause then
display dialog "paused"
else if playerState = spotPlay then
display dialog "playing"
end if
It's better to use this code to obtain the player state. You don't need to know the exact constant values. Works on OS X 10.13
tell application "Spotify"
if player state is playing then
display dialog "Player running"
else if player state is paused then
display dialog "Player paused"
else if player is stopped then
display dialog "Player is stopped"
else
display dialog "Unknow state"
end if
end tell
I wasn't able to comment adayzdone's answer yet here's an alternative:
if player state is playing or player state is paused then
E.G
if application "Spotify" is running then
tell application "Spotify"
if player state is playing or player state is paused then
set trackID to (get id of current track)
end if
end tell
end if
This atleast worked on Catalina (10.15.7) when working on a Spotify-Applescript project of my own.
The source of the idea came from this thread.

Closing QuickTime by Applescript

I am trying to play a movie fullscreen one time, then close the player programmably.
I have tried using QTMovieView, command line and AppleScript and found the Applescript is the most simple way.
BUT, as I really don't know Applescript, I can not make the QuickTime auto close after movie playing.
Everything works fine but the "done" was unrecognized in the repeat line.
Here is the script with this error:
error "QuickTime Player got an error: Can't make done of document 1 into type specifier." number -1700 from done of document 1 to specifier
tell application "QuickTime Player"
activate
open "/Users/...real path of the movie.mov"
present document 1
play document 1
repeat until (get done of document 1)
end repeat
delay 2
close document 1
end tell
Finally, I changed to this, is this ok?
tell application "QuickTime Player"
quit
end tell
tell application "QuickTime Player"
activate
open "/Users/.../...mov"
tell document 1
present
play
repeat until playing is false
end repeat
delay 2
close
end tell
quit
end tell
New problem: app hang before video finish.
This works for me, however it doesn't seem very robust. Is it guaranteed that the current time will always end up being equal to the duration, given that they're both reals? You may want to put some "within epsilon" logic into the repeat condition.
tell application "QuickTime Player"
play document 1
repeat until (current time of document 1 = duration of document 1)
end repeat
delay 2
close document 1
end tell
Try:
tell application "QuickTime Player"
tell document 1
present
play
repeat until playing is false
delay 1
end repeat
end tell
quit
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

Resources