I did the following script in order to identify itunes songs that doesn't have artwork. It's based on other script that I found in net.
tell application "iTunes"
repeat with a in every track of playlist "Library"
if not (exists (artwork 1 of a)) then
add (get location of a) to (playlist "noart")
end if
end repeat
end tell
It seems to be working, it compiles well, and because I can that it in event log windows:
tell application "iTunes"
count every track of playlist "Library"
--> 10684
exists artwork 1 of item 1 of every track of playlist "Library"
--> true
exists artwork 1 of item 2 of every track of playlist "Library"
--> true
But after 4 hundred tracks, it starts to run slowly, and applescript stops responding after one thousand tracks.
I thought that maybe I could be exhausting my mac memory, but in Activity Monitor, I can see that Applescript is consuming 100% CPU and less than 50MB of memory. I'm running macos 10.7.4 on a macbook pro (i7 with 4GB ram).
As you can see my itunes library has 10684 tracks. It's not a small library, but it's not a huge one.
Does anyone has any advice? Or a script to identify tracks without artwork?
TIA,
Bob
Here's what I use. My main suggestion would be to use "duplicate" instead of "add" and then you do not need to get the location of a track. Also you'll see I'm using "a reference to" most things which makes it work faster. I also create the "no artwork" playlist with a time stamp on-the-fly so I can see when I ran the script.
set d to current date
set missingTracksCount to 0
tell application "iTunes"
set isFixedIndexing to fixed indexing
if not isFixedIndexing then set fixed indexing to true
-- make a new playlist to hold the tracks
set newPlaylist to make new playlist
set name of newPlaylist to "No Art - " & month of d & " " & day of d & " " & time string of d
set mainPlaylist to a reference to playlist "Library"
set noArtworkPlaylist to a reference to newPlaylist
set trackCount to count of tracks of mainPlaylist
repeat with i from 1 to trackCount
set trackRef to (a reference to (track i of mainPlaylist))
if (count of artworks of trackRef) is less than 1 then
duplicate trackRef to noArtworkPlaylist
set missingTracksCount to missingTracksCount + 1
end if
end repeat
if not isFixedIndexing then set fixed indexing to isFixedIndexing
display dialog "Finished!" & return & (missingTracksCount as text) & " tracks didn't have artwork." buttons {"OK"} default button 1 with icon note giving up after 5
end tell
Related
I have an issue with my music library.
Some songs I am unable to play because they cannot be found locally.
Here's an example of the error messages I get when playing a specific song:
The song ... could not be used because the original file could not be found. Would you like to locate it?
I can simply press Cancel and the song will be matched via the Apple Music Service.
This allows me to then play the song.
This issue has been discussed here, albeit not in an automated way. Hence, I would like to find an automated solution.
For this, I took the approach of looping through my library by playing each song.
By default, if a song cannot be found, the script automatically skips to the next song.
However, I would like the script to deal with the "file not found" errors and press Cancel.
My current attempt unfortunately does not work:
-- Play first song in library (turn off shuffle and repeat)
set i to 4000 --number of songs in library
repeat while i > 0
tell application "Music" to play (next track)
tell application "System Events"
key code 53
end tell
set i to i - 1
end repeat
How can I force the script to deal with these pop-up errors?
Note: I am also open to any other, more efficient solution to my problem if you have any suggestions. I decided not to go for the Locate option because it takes more time and I will delete any unreferenced songs from my disk at a later stage anyways.
UPDATED VERSION. Following script doesn't play tracks and programatically clicks button "Cancel" when track is corrupted. Like described by OP fixing tracks manually workflow:
tell application "Music"
activate -- required
tell source "Library"
repeat with nextTrack in tracks
try
with timeout of 2 seconds
set theResult to play (contents of nextTrack)
end timeout
theResult
on error
delay 1
tell application "System Events" to tell process "Music" to tell window 1 to if UI element "Cancel" exists then click UI element "Cancel"
end try
stop
end repeat
end tell
end tell
As you can see from my code below I am extremely new to this. My code just about works, but my major issue is that it hogs up Finder and sometimes it does not set the Desktop picture, but does most of the time!
The script just monitors a folder, and if an "***.jpg" is added then the Desktop picture set to it.
This is my very first script so I have a lot to learn,
set reset to ""
display notification "Alarm Front Active " & (current date) as string
tell application "Finder"
set path_to_sourceFull to ":photo:FRONT CAM 1:20190929:images" -- from nsa310 network drive
set path_to_source to ":photo:FRONT CAM 1:20190929:images" -- from nsa310 network drive
set directory1 to "/Volumes/photo/FRONT CAM 1/20190929/images" as text -- from nsa310 network drive
set path_to_destinationFull to "Macintosh HD:Users:rekordbox:Documents:temp folder 2"
set path_to_destination to ":Users:rekordbox:Documents:temp folder 2"
set directory2 to "/Users/rekordbox/Documents/temp folder 2" as text
repeat while reset = ""
set allok to ""
set filelist to name of every item in folder path_to_source --of startup disk
set listSizesaved to count of filelist
delay 1
repeat while allok = ""
set filelist to name of every item in folder path_to_source --of startup disk
set listSize to count of filelist
if listSize = listSizesaved then
else
set filelist to name of every item in folder path_to_source --of startup disk
set listSize to count of filelist
set LastAddedFile to item listSize of filelist
set allok to "ALARM"
set listSizesaved to listSize -- (save the updated) count
set activefile to (path_to_source & LastAddedFile)
set selectedpicture to (directory1 & "/" & LastAddedFile)
tell application "System Events" to tell every desktop to set picture to selectedpicture
delay 1
display notification "ALARM FRONT TRIGGERED...." & (current date) as string
delay 1
end if
end repeat
end repeat
end tell
The script you want, I think, is this:
on adding folder items to thisFolder after receiving filelist
set droppedFile to first item of filelist
tell application "System Events"
tell every desktop
set picture to droppedFile
end tell
end tell
end adding folder items to
(I've left out the 'Alarm' bit, since I wasn't sure what the point of it was.)
To use this script, copy it into Script Editor, save it in the folder ~/Library/Scripts/Folder Action Scripts/, then open the applet 'Folder Actions Setup'. Add the folder you want on the left-hand side, and choose the file you just saved on the right. It should look something like this:
...where the checkmark on the left shows that folder actions are enabled for the folder (which I called 'test folder') and the script (which I called 'FADtop.scpt') is attached.
Drop an image in the folder, and it should just work.
As a general rule, don't script the Finder unless you absolutely need to; always use System Events. The Finder is a busy app, and scripting it can gum up the system. And also try to avoid this design pattern:
(* Don't do this! *)
repeat
(* test for something *)
delay x
end
The delay command is not particularly resource-efficient. If you really want to use a polling system to test for some event, it's often better to create a stand-alone app with an on idle handler. That way you let the system wake and sleep the script, with significant performance improvements.
EDIT
Since folder actions don't seem to be working with ftp drops onto remote drives, here's a reasonably efficient folder-polling approach. Save the following script as a stay-open application (choose 'Application' as the file type, and click the 'stay open' checkbox). Then launch the application and leave it running in the background.
property dateOfLastFileChosen : missing value
property targetFolder : "/Volumes/photo/FRONT CAM 1/20190929/images"
property idleTime : 300 -- 300 seconds is five minutes
on run
end run
on idle
tell application "System Events"
if exists folder targetFolder then
if dateOfLastFileChosen is missing value then
set recentFiles to every file of folder targetFolder whose visible is true
else
set recentFiles to every file of folder targetFolder whose modification date > dateOfLastFileChosen and visible is true
end if
set newFile to my mostRecentFileOfList(recentFiles)
if newFile is not missing value then
set dateOfLastFileChosen to modification date of newFile
tell every desktop
set picture to (POSIX path of newFile)
end tell
end if
end if
end tell
return idleTime -- check every 5 minutes (300 seconds)
end idle
on mostRecentFileOfList(fileList)
set maxDateObj to missing value
repeat with thisFile in fileList
if maxDateObj is missing value then
set maxDateObj to contents of thisFile
else if modification date of thisFile is greater than modification date of maxDateObj then
set maxDateObj to thisFile
end if
end repeat
return maxDateObj
end mostRecentFileOfList
Without trying to steal the thunder from #Ted Wrigley, whose solution provided the AppleScript code for the folder action, I felt there were enough comments and items for me to add to post it as another answer to the OP's dilemma.
First I will address the tell every desktop set picture to droppedFile lines of code in the following AppleScript Folder Action. If the user has only one monitor/display attached to the computer, but has created several different "Spaces", the tell every desktop set picture to droppedFile lines of code will only change the Desktop Picture for the Desktop of the current active "Space" only. The other Desktop backgrounds will not be changed. However, if the user has several monitors/displays attached to the computer, the tell every desktop set picture to droppedFile lines of code will change the Desktop Pictures for the Desktops of the current active "Space" for each attached monitor/display. If the latter is not the desired result, then tell every desktop should be changed to tell current desktop.
After testing the AppleScript Folder Action code provided by #Ted Wrigley, I noticed the image file being downloaded from an FTP server, to the test folder where I have the folder action script attached to, looked like this before the image was actually finished transferring. Because the file was kind of there and not there, it did not trigger the Folder Action.
Next, I figured I would add a delay to be beginning of the Folder Action code to allow for the transfer of the image file from the FTP server, to complete. I added a delay of 180 seconds to allow for the transfer to complete and it worked. When the transfer was complete, the file look like this.
Depending on how many files you foresee being transferred at any given time along with factoring in for file sizes... It's possible you may need to significantly increase the Delay time.
on adding folder items to thisFolder after receiving theseFiles
delay 180
set newBackground to first item of theseFiles
tell application "System Events"
set picture of current desktop to newBackground -- Single Display Attached
--set picture of every desktop to newBackground -- Multiple Displays Attached
end tell
end adding folder items to
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.
I'm a total beginner in apple script.
I would like to open a folder directory that contains hundreds of photos and to view each photo 1 second with quick look and then go to the next (suppose to use down arrow / key code '124').
I don't have any idea of how to build the script. I tried to compile some formulas from other questions or use the manual rec but it doesn't work.
Thanks!
Try following script. I made the delay longer so you have time to stop the script (to test it):
set timePerPreview to 5
set thisFolder to (choose folder with prompt "Pick the folder containing the files to process:") as string
tell application "Finder"
activate
open folder thisFolder
select every item in folder thisFolder
delay 2
set fileCount to (count items in (get selection)) # (count files in folder thisFolder) is faster but counts also .DS_Store and other invisible files
if fileCount = 0 then
beep
return
end if
end tell
pressSpaceInFinder()
delay timePerPreview / 2 # first it has to open the window which seems to need a little time
repeat fileCount - 1 times # -1 because the first item is already displayed
delay timePerPreview
# do shell script "sleep" & space & timePerPreview as text
tell application "System Events"
tell application process "Finder"
set frontmost to true
# cursor right = 124, left = 123
key code 124
end tell
end tell
end repeat
delay timePerPreview
pressSpaceInFinder()
on pressSpaceInFinder()
tell application "System Events"
tell application process "Finder"
set frontmost to true
keystroke space
end tell
end tell
end pressSpaceInFinder
Be aware that it is hard to stop the script since the Finder gets activated every second. Will see if I can add a check to see if the Preview window is open and if not, stop the script.
Also: (without that check) the script will, when the Preview window is open before running, close it but you can just press the space key to open it again.
Also, the first part (getting the file count) isn't so great and may fail when the delay is to short. We could scan the whole folder for images and only count / select those (it has a file template for the scanner, see menu File) but of course you can remove the whole counting thing and just do repeat 1000 times.
I need to get a count of all windows per application. Every way I've tried to do this, I only get a count of windows that are assigned to the current (Mission Control) Desktop. (I'm currently running Mac OS X 10.7, so post-Spaces.) Is there any way to get a per-application count of all windows across all Desktops?
The crux of what I've tried:
tell application "System Events"
repeat with _app in (every process whose visible is true)
tell _app
log (name as string) & ": " & (count of every window)
end tell
end repeat
end tell
Note that the whose visible is true clause isn't the problem. It finds all of the appropriate processes, but once I ask the processes for windows, they only count the ones in the active Desktop.
I've tried pulling the log line out of the tell and using name of _app and count of every window of _app, but there's no difference. I've tried grabbing things other than processes from System Events, but anything useful ends up effectively being just a different way to get the same object. I've tried iterating over UI elements, but no windows show up that aren't on the current Desktop, though I do get a menubar for each application.
I'm fine with iterating across all Desktops (though not actually switching to all of them), but I can't even find a way to get a list of Desktops. This answer claims to describe how to do that, but I only ever get a single element inside every desktop. Not that there's an obvious way to get windows once you have that Desktop object anyway.
It's also worth pointing out that desktops are controlled by the Dock, and not by Mission Control. I'm not aware of any way for AppleScript to talk to the Dock, so if you know of something, then an answer or comment about that might help point me in the right direction.
Am I trying to do something impossible?
I ran your code, setting up the Applescript version to 2.4 (do that as a habit); on the first run, your code presented me with the appropriate count of all the windows per application.
This code is what I tried, and the results seem to be satisfactory. Is there something I'm not seeing?
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application "System Events"
set my_list to {}
repeat with _app in (every process whose visible is true)
tell _app
log (name as string) & ": " & (count of every window)
set my_list to my_list & {name as string, count of every window}
end tell
end repeat
log my_list
end tell
As the OP is over six years old and I am unable to test under OS X 10.7, which is what was being used at that time, nonetheless, the following example AppleScript code works for me under macOS Catalina and returned the correct window count across all Desktops/Spaces, with the exception of any application that does understand the given AppleScript command and why the try and on error statements are being used.
Example AppleScript code:
tell application "System Events" to ¬
set appBundleIdentifierList to ¬
the bundle identifier of ¬
(every process whose visible is true)
repeat with appBundleIdentifier in appBundleIdentifierList
try
tell application id appBundleIdentifier to ¬
set {appName, winCount} to {name, (count windows)}
log appName & ": " & winCount
on error errorMessage
log errorMessage
end try
end repeat
Sample output on my system that has multiple Desktops/Spaces with windows of the application on all or some of the Desktops/Spaces and the window count for each is correct across all Desktops/Spaces, not just the active Desktop/Space the script was run from.
(*Safari: 6*)
(*Terminal: 2*)
(*TextEdit: 4*)
(*Script Editor: 7*)
(*Finder: 3*)
(*BBEdit: 1*)
(*Norton Secure VPN got an error: every window doesn’t understand the “count” message.*)
(*Music: 2*)
Notes:
Not all applications are AppleScript scriptable, in that some do not contain an AppleScript dictionary within their application bundle.
Since the application process cannot return the correct number of windows across all Desktops/Spaces, this method relies on the application to return the number of windows across all Desktops/Spaces.
Update:
The following example AppleScript code does the following:
Gets the bundle identifier of every process whose visible is true.
For each bundle identifier, get its name and the window count by querying the application directly. If the application understands the AppleScript command, then if goes to the next item in the appBundleIdentifierList list. If it does not understand, then the window count is calculated by the following:
Attempts to get an invisible window count as they would not show up on the Window menu of an application.
Calculates the window count by the number of windows shown on the Window menu of the application.
Failing these methods it get the window count by querying the application process, with is only accurate fo the active Desktop/Space and is included only for completeness of trying to ascertain the window count just using basic vanilla AppleScript.
Goes to the the application in the appBundleIdentifierList list.
Example AppleScript code:
set menuName to "Window"
tell application id "com.apple.systemevents" to ¬
set appBundleIdentifierList to ¬
the bundle identifier of ¬
(every process whose visible is true)
repeat with appBundleIdentifier in appBundleIdentifierList
try
tell application id appBundleIdentifier to ¬
set {appName, winCount} to {name, (count windows)}
log appName & ": " & winCount & ¬
" -- By querying the application directly."
on error
set winCount to 0
set notVisibleWindowList to {}
set errAppName to ¬
name of application id appBundleIdentifier
tell application id "com.apple.systemevents"
try
tell application process errAppName
set notVisibleWindowList to ¬
(windows whose visible is false)
if notVisibleWindowList is {} then ¬
set winCount to ¬
length of notVisibleWindowList
end tell
end try
try
set theTargetMenuItemsList to ¬
the reverse of ¬
(get name of ¬
menu items of ¬
menu menuName of ¬
menu bar item menuName of ¬
menu bar 1 of ¬
application process errAppName)
on error
set theTargetMenuItemsList to {}
end try
end tell
if theTargetMenuItemsList is not {} then
repeat with anItem in theTargetMenuItemsList
if contents of anItem is ¬
missing value then exit repeat
set winCount to winCount + 1
end repeat
log errAppName & ": " & winCount & ¬
" -- By querying the Window menu of the application process."
else
try
tell application id "com.apple.systemevents" to ¬
set winCount to ¬
(count windows of ¬
application process errAppName)
log errAppName & ": " & winCount & ¬
" -- By querying the application process. " & ¬
"May not be accurate, verify as necessary."
end try
end if
end try
end repeat
Running both versions of the example AppleScript code to show the difference in output:
First version of example AppleScript code:
(*Safari: 6*)
(*TextEdit: 4*)
(*Finder: 3*)
(*BBEdit: 1*)
(*Norton Secure VPN got an error: every window doesn’t understand the “count” message.*)
(*Music: 2*)
(*Sublime Text 2 got an error: every window doesn’t understand the “count” message.*)
(*DiskCatalogMaker got an error: every window doesn’t understand the “count” message.*)
(*Script Editor: 7*)
(*System Preferences: 2*)
(*VMware Fusion got an error: every window doesn’t understand the “count” message.*)
(*Activity Monitor got an error: every window doesn’t understand the “count” message.*)
(*Terminal: 2*)
Second version of example AppleScript code:
(*Safari: 6 -- By querying the application directly.*)
(*TextEdit: 4 -- By querying the application directly.*)
(*Finder: 3 -- By querying the application directly.*)
(*BBEdit: 1 -- By querying the application directly.*)
(*Norton Secure VPN: 0 -- By querying the application process. May not be accurate, verify as necessary.*)
(*Music: 2 -- By querying the application directly.*)
(*Sublime Text 2: 4 -- By querying the Window menu of the application process.*)
(*DiskCatalogMaker: 2 -- By querying the Window menu of the application process.*)
(*Script Editor: 7 -- By querying the application directly.*)
(*System Preferences: 2 -- By querying the application directly.*)
(*VMware Fusion: 1 -- By querying the Window menu of the application process.*)
(*Activity Monitor: 0 -- By querying the Window menu of the application process.*)
(*Terminal: 2 -- By querying the application directly.*)
As you can see even Activity Monitor, a native default macOS application, the Window menu had to be queried as the application directly didn't understand the basic count windows AppleScript command.
Although the output of the second version of the code was accurate across all Desktops/Spaces at the time it was executed, any application that has "By querying the application process. May not be accurate, verify as necessary." as part of its output only includes the window count of the active Desktop/Space it was executed form. The bottom line is using basic vanilla AppleScript there is no guarantee to get a complete accurate window count of every visible application unless all the applications at that time cen be queried directly. Querying the Window menu by its application process should also be accurate.
With that said, I think other methods may need to be used to get an accurate count.