Now Playing window in AppleScript - applescript

I was wondering how I would go about making a script using the Script Utility that, when clicked, would return a window that shows the Song name and Artist of whatever is playing in iTunes. Very new to AppleScript and have spent an unsuccessful hour trying to make it work!
Thanks,
Nathan

There is a current track property:
tell application "iTunes"
tell current track to artist & " - " & name
display dialog result
--do shell script "terminal-notifier -message '' -title " & quoted form of result
end tell
If you need to update the window continuously, using something like GeekTool might be a better option.

Related

Making a dialog that bugs me in Applescript

I know this question is kinda messy. I don't know how to make it more specific. I want to make an applescript that asks me every hour what I've been doing for the past hour.
The issue I'm having is that I want it to pop up, make a sound, and wait for my response. If I do a normal dialog, and I'm busy, it will go behind the other windows on my mac. I thought maybe having a persistent banner notification would be great, but applescript doesn't allow for much control over banners.
I want something to float over all windows so that I can see that the applescript has been waiting for a response from me until I fill out the dialog.
What you're looking for is a global floating window, similar to what LittleSnitch does. You can do that, but not with pure AppleScript. You'd have to write a Cocoa app.
Adding an activate command just before a display dialog command in your AppleScripts, will ensure the pop-up dialog window will become frontmost and visible no matter what other apps and documents are currently opened (until another app or document gets activated, thus bringing that item to the front).
This following AppleScript may be of some use to you.
Save this following AppleScript code as a "stay open application" in Script Editor.app.
When running your new AppleScript applet, it will remain running (because it has an idle handler) until you press "Cancel" in any of the dialog pop-ups or choosing to quit the app in the Dock.
This code also logs everything it receives in the dialog pop-ups, to file for you.
property myComputerActivitiesLog : (path to desktop as text) & "My_Computer_Activities.log"
property theDialog : missing value
property theDate : missing value
property insertTime : missing value
property logContent : missing value
on idle
set theDate to (current date)
set insertTime to " ------ " & theDate & " ------ "
beep 5
say "It's time to log your activities"
activate
try
set theDialog to display dialog ¬
"Itemize my activities." default answer ¬
"Itemize my activities for yhe past hour." & linefeed & linefeed ¬
buttons {"Cancel", "OK"} default button 2 cancel button 1 ¬
with title "Account For My Activities" with icon 1
end try
if theDialog = missing value then
quit me
else
set logContent to insertTime & linefeed & (text returned of theDialog) & linefeed
do shell script "echo " & quoted form of logContent & ¬
" >> " & quoted form of POSIX path of myComputerActivitiesLog
set theDialog to missing value
return 3600 -- in seconds
end if
end idle
on quit -- Executed when the script quits
-- Additional code to perform (if any) goes here
continue quit -- allows the script to quit
end quit

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. :)

Constant to String in AppleScript

I have the following line of code:
tell application "iTunes"
if player state is playing then
set trackMediaKind to media kind of current track
display dialog trackMediaKind
end if
end tell
When I print trackMediaKind I get the following: «constant ****kMdS»
In iTunes the media kind looks like:
Is there way to make it print Music instead of «constant ****kMdS»?
-Edit-
tell application "iTunes"
if player state is playing then
set trackMediaKind to media kind of current track
log trackMediaKind as string
end if
end tell
I ran the code up via the terminal by typing: osascript myscript.scpt it stills returns: «constant ****kMdS».
You need to change the following line of code from:
display dialog trackMediaKind
To:
display dialog trackMediaKind as string
If you really want it to display "Music" then you need to do something such as:
tell application "iTunes"
if player state is playing then
set trackMediaKind to media kind of current track
if trackMediaKind as string is "song" then
display dialog "Music"
end if
end if
end tell
BTW In the AppleScript Dictionary for iTunes (12.7.*) , looking at the properties of a track, the media kind shows:
media kind (alert tone/‌audiobook/‌book/‌home video/‌iTunesU/‌movie/‌song/‌music video/‌podcast/‌ringtone/‌TV show/‌voice memo/‌unknown) : the media kind of the track
In other words, you'll need to test the results against what could be returned and process it accordingly to your needs/wants if you want to display differently the returned. Also, anytime it returns things like e.g. «constant ****kMdS» try coercing to text with as string or as text.
Update to address the after the fact edit to your question:
While you didn't originally state in the OP you were running your script in Terminal using osascript, nonetheless there seems to be an issue between running the same code as a .scpt file in the two different environments. One would think that what works correctly in Script Editor, it would work correctly in Terminal using osascript, but in this particular case it doesn't.
The workaround in this particular case is to not use the .scpt file format and instead use a plain text format:
As an example, the following code should display a dialog box with "song" when a song track is playing iTunes and saved in Script Editor as Text, e.g. myscript.applescript, and then run in Terminal using: osascript myscript.applescript
tell application "iTunes"
if player state is playing then
set trackMediaKind to media kind of current track
display dialog trackMediaKind as string
end if
end tell
One can also use the AppleScript code in plain text format and make the file executable to be used directly without having to first type osascript on the command line. Save the following example AppleScript code using an osascript shebang.
#!/usr/bin/osascript
tell application "iTunes"
if player state is playing then
set trackMediaKind to media kind of current track
display dialog trackMediaKind as string
end if
end tell
Make executable with chmod in Terminal, e.g.:
chmod u+x myscript.applescript
Then, if it's in the current directory, execute the script using:
./myscript.applescript
Otherwise, use the pathname to it, if it's not in the PATH.
Note: With this method, it is not necessary to use the .applescript extension or any extension. It's a users preference, even though Script Editor uses that extension by default for plain text AppleScript code files.

Directing an app to run off of a different script in AppleScript.

I'm making an applescript to help with school. You type the subject you wish to access, and then it opens that folder (inside the app). However, some subjects have ebooks, so I want there to be another dialog box asking you wether you want to open the ebook or the folder. Unfortunately, a display dialog can't branch off of another display dialog.
So far, the only way I've found around this is to direct the app to run off of another script (in the "Scripts" folder of the app). I've tried
tell application "Script Editor" to run script (path to me as sting) & "Contents:Resources:Scripts:Subject.scpt"`
But it didn't work. Sorry if I'm barking up the wrong tree and seem completely stupid. Thanks
As far as I understood what you're trying to achieve, the following script would work.
set listOfSubjects to {"Math", "Biology", "History", "Languages"}
set subjectsWithEbook to {"Biology", "History"}
choose from list listOfSubjects with prompt "Select the subject"
set subject to item 1 of result
set openEbook to false
repeat with subjectItem in subjectsWithEbook
if subjectItem contains subject then
choose from list {"Open folder", "Open Ebook"} with prompt "What to open?"
set openType to item 1 of result
if openType contains "Open Ebook" then
set openEbook to true
end if
exit repeat
end if
end repeat
if openEbook then
--Open ebook
else
--Open folder
end if
I am guessing that you want to type the subject name? Here is an example that uses dialog boxes.
set subjectFolderPath to (path to me as string) & "Contents:Resources:Subjects:"
set subjectsWithEbook to {"English", "Spanish"}
display dialog "What subject would you like to access?" default answer ""
set theSubject to text returned of the result
if theSubject is in subjectsWithEbook then
display dialog "Would you like to open the Folder or the Book?" buttons {"Folder", "Book"} default button 1
set toOpen to button returned of the result
if toOpen is "Book" then
-- tell app "Preview" to open ???
beep
else
tell application "Finder" to open folder (subjectFolderPath & theSubject & ":")
end if
else
tell application "Finder" to open folder (subjectFolderPath & theSubject & ":")
end if
You might also want to have a list of subjects that are allowed and error check for them.

Smooth UI changes in cocoa-applescript (Xcode)

I'm trying to write a simple Xcode cocoa-applescript program that executes a bash script on each subfolder of a folder and shows a progressbar while doing it.
I have a NSProgressIndicator set up to be linked to barStatus and well a NSTextField to be linked to lblStatus to show some informative text:
property barStatus : missing value
property lblStatus : missing value
this is the loop where the main action takes place:
tell application "Finder" to set subfolders to every folder of folder macPath
barStatus's setIndeterminate_(false)
barStatus's setDoubleValue_(0)
barStatus's setMaxValue_(count of subfolders)
repeat with eachFolder in subfolders
set posixPath to (POSIX path of (eachFolder as text)) as text
-- set text of progress indicator text
lblStatus's setStringValue_("Resizing '" & ( do shell script "basename \"" & (posixPath) & "\" | sed \"s/^.*_//\"" ) & "'...")
delay 0.5
-- do the shell script
do shell script "bash ~/.uploader/image.sh \"" & posixPath & "\""
-- step the indicator
barStatus's incrementBy_(1)
end repeat
lblStatus's setStringValue_("Done!")
All seems to work properly, yet the UI is somewhat glitchy. Instead of just increasing smoothly, the progressbar disappears on each step and gets shown for a short while, then dissappears again. The text in lblStatus does get changed smoothly.
Things get totally lost when I remove the delay from the loop: no UI changes are made (even though the scripts get run properly) until the loop is finished. So the progressbar just dissappears and reappears filled out when the loop is done.
Here's a youtube video of the flickery UI.
What am I doing wrong? How can I have xcode draw the progressbar smoothly?
Note that this is the first time I write an Xcode app, and that my knowledge of Applescript is somewhat sketchy.
EDIT:
I found that calling the function that processes the same function does not have a flickery UI when called form a menu item (or with a key combo bound to that menu item).
I'm not sure why the progress bar hides itself. Did you bind the visible property of it to something that may make it hide?
Things get totally lost when I remove the delay from the loop: no UI
changes are made
In general though when "no UI changes are made" it's because the application is too busy on the main thread to update the interface items in real time. All of your code is running on the main thread. You need to make some of it happen on a background thread. As such I have 2 suggestions for you to try.
First try using the progress bar's method "setUsesThreadedAnimation:". Add this just above your repeat loop...
barStatus's setUsesThreadedAnimation_(true)
Second, if that doesn't help then try moving your repeat loop work onto a background thread (using NSThread's detachNewThreadSelector:)... but make the interface updates happen on the main thread. I don't know ApplescriptObjC language so the following code is probably completely wrong. You'll have to write it properly but it will show you the idea...
[NSThread detachNewThreadSelector:#selector(processFolderListOnBacgroundThread_) toTarget:self withObject:subfolders];
-- this will happen on the main thread
on updateProgressBarByOne_()
barStatus's' incrementBy_(1)
end updateProgressBarByOne_
-- this will happen on the main thread
on updateStatusTextWithText_(statusText)
lblStatus's' setStringValue_(statusText)
end updateInterfaceItemsOnMainThreadWithObject_
-- this will happen on a background thread
on processFolderListOnBacgroundThread_(subFolders)
repeat with eachFolder in subfolders
set posixPath to (POSIX path of (eachFolder as text)) as text
-- set text of progress indicator text
my updateStatusTextWithText_("Resizing '" & ( do shell script "basename \"" & (posixPath) & "\" | sed \"s/^.*_//\"" ) & "'...")
-- do the shell script
do shell script "bash ~/.uploader/image.sh \"" & posixPath & "\""
-- step the indicator
my updateProgressBarByOne_()
end repeat
my updateStatusTextWithText_("Done!")
end processFolderListOnBacgroundThread_
If you use the background thread approach you'll probably have to make the buttons in your interface inactive while the background thread is working (so the user can't press them and start a new task). So just set their enabled property to false prior to calling "detachNewThreadSelector:" and enable them again after the work is finished. You can do this by having another handler which enables them and call that from the end of the background thread code.

Resources