I've been looking around via Google for some pointers to get me going on something I need to do in iPhoto via AppleScript, but so far haven't found a whole lot. There are various old discussions of scripts for various old versions of iPhoto floating around, but nothing that's been particularly helpful with what I need. Basically, in pseudo-code, I'm looking to do this:
for each photo in library
if photo.Description contains "a known string"
photo.Description = photo.Description.Replace("a known string", "")
end if
end for
That is, I have a piece of errant text which has made its way into every (well, nearly every) photo in my library. I'm guessing I botched up a batch change at some point in the past and didn't notice it until now. Either that or the upgrade from iPhoto '08 to '11 did it somehow. Either way, the net result is the same.
I'm not well-versed in AppleScript, and am having trouble just finding the right syntax/vocabulary to use in this. Basically, I'm at the tell application "iPhoto" part, but don't know what to tell it. If the hierarchy of how photos in the library are organized is important:
Every photo is organized chronologically into events. (Events are my primary form of organization.)
There are a good number of albums, but not everything is in an album.
There is a single smart album which contains every errant photo. This is, of course, based on the presence of the known string in the photo description. So I suppose that may need to be kept in mind if the final code loops through photos in this smart album, since the smart album may be changing the array being iterated over, no?
Does anybody have any references or sample code to help get me going? Conversely, does anybody know of a better way to do this one-time mass fix?
Edit: I ran a test with the following code:
tell application "iPhoto"
activate
set thePhotos to get every photo
repeat with aPhoto in thePhotos
if aPhoto's comment contains "[known string]" then
log aPhoto's comment
tell aPhoto to set it's comment to text 1 thru (offset of "[known string]" in aPhoto's comment) of aPhoto's comment
log aPhoto's comment
exit repeat
end if
end repeat
end tell
Which resulted in the following output:
tell application "iPhoto"
activate
get every photo
get comment of photo id 4.294977224E+9
(*comment of photo id 4.294977224E+9*)
offset of "[known string]" in comment of photo id 4.294977224E+9
«event ascrgdut»
offset of "[known string]" in comment of photo id 4.294977224E+9
end tell
tell current application
offset of "[known string]" in «class pcom» of «class ipmr» id 4.294977224E+9
Result:
error "iPhoto got an error: Can’t make comment of photo id 4.294977224E+9 into type string." number -1700 from comment of photo id 4.294977224E+9 to string
Edit: I had some time to tinker with it this morning and it looks like some type casting was all that was needed. This code is now successfully changing the first matching photo it finds:
tell application "iPhoto"
activate
set thePhotos to get every photo
repeat with aPhoto in thePhotos
if aPhoto's comment contains "[known string]" then
log aPhoto's comment as text
set theComment to aPhoto's comment as text
set theComment to text 1 thru (offset of "[known string]" in theComment) of theComment
tell aPhoto to set it's comment to theComment
log aPhoto's comment as text
exit repeat
end if
end repeat
end tell
Now to back up my library and remove the exit repeat. And probably go do something else for a while as it runs :)
Here's a 'brute force' version. This will loop through every photo. You could make this more elegant by restricting to certain albums if you wanted.
tell application "iPhoto"
set thePhotos to get every photo
repeat with aPhoto in thePhotos
if aPhoto's comment contains "theString" then
tell aPhoto to set it's comment to "newString"
end if
end repeat
end tell
What about this. You would need to make an album or smart album of the items you wish to impact, but this is less destructive anyway.
tell application "iPhoto"
activate
set thePhotos to get every photo in current album whose comment contains "TEST123"
repeat with aPhoto in thePhotos
tell aPhoto to set it's comment to "123TEST"
end repeat
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
I prefer to refresh my iTunes podcasts at times I control, so usually I right-click on the one I want to refresh, and choose Refresh Podcast. But sometimes I mistakenly select another menu item, and that's a real PITA. So I'd like to have an applescript which will only refresh a single podcast. I plan to hard-code the podcast into the script -- there's only one that I do near-daily, and the others can be done as and when I feel like it, with right-click. If I mess them up it's less of a PITA than with the main one.
The iTunes dictionary has updatePodcast and updateAllPodcasts -- clearly the former is the one I need to use (I don't want to have them all updated every time). But I can't figure out how to specify the podcast! The dictionary doesn't have a podcast class or anything similar, and item offers no obvious guidance either.
I've tried:
tell application "iTunes"
updatePodcast NameOfPodcast
end tell
Where NameOfPodcast is replaced by the exact string (AFAIK) that is in the iTunes podcast listing. Applescript tells me:
error "iTunes got an error: NameOfPodcast doesn’t understand the “updatePodcast” message." number -1708 from NameOfPodcast
Does anyone know how to get iTunes to refresh a single podcast from within applescript?
Edit:
Thanks to #user3439894 and #wp78de but referring to a track doesn't work. AS complains that the track doesn't understand the updatePodcast message. If I try to get a list of albums instead (every album of playlist "Podcasts" whose name is album_name), I get told that album is a property whereas it wants a class name.
Try it like this:
tell application "iTunes"
set allTracks to every track of playlist "Podcasts" whose album is "podcast_name"
repeat with singleTrack in allTracks
updatePodcast singleTrack
end repeat
end tell
Or try
tell application "iTunes"
updatePodcast (first track of playlist "Podcasts" whose album is "XY Podcast")
end tell
I am writing an applescript to iterate thru all photo in the default album 'Photos'
Here is my script:
tell application "Photos"
activate
set alls = albums "Photos"
repeat with photo in alls
say photo.name
end repeat
end tell
Line 3. throws the following syntax error:
I am new to this language and I am unable to find an remedy to the incorrect syntax. Can any one point out what is amiss here?
If you refer to the dictionary it helps to understand how each element is contained by other elements. To get the photos of all albums you have to loop through the media items of every album. This will get the filename of each photo.
tell application "Photos"
activate
set alls to every album
repeat with photoAlbum in alls
set photos to every media item in photoAlbum
repeat with photo in photos
get filename of photo
end repeat
end repeat
end tell
Sorry if this is a noob question, I am just trying to learn this lovely program known as applescript.
tell application "Numbers" ¬
activate
end
tell application "Numbers" to ¬
make new document with properties {name:"document 3"}
end
I can use this format of script to open most any other application (other than iWork) and it will open up, make a new document, and name it, but for whatever reason it will not work with iWork.
I have even tried to set a variable to use in the {name:variable} or {name:"variable"} with no luck.
Any help would be appreciated, thanks in advance.
PS...Snide comments will be tolerated if they bring me the solution!
I do have Numbers. Try this:
tell application "Numbers"
set myDoc to make new document with properties {name:"document 3"}
name of myDoc
end tell
The results window should show "document 3". Why do you say it is not working? Possibly because the window that contains the document is labeled "Untitled"? That's because a window does not show the document name until the document is saved. If you choose "Save" from the menu, you will see your document name right there in the save dialog, and the window title will update after the save.
i do not have "numbers" on my computer, would you try this:
tell application "TextEdit"
make new document at front with properties {name:"hello darkness"}
end tell
replace "textedit" with "numbers"
have fun :)
ok, try this one:
tell application "TextEdit"
make new document at front
tell document 1
set name to "hello darkness"
end tell
end tell
I also do not have Numbers to test this, but this should work in theory.
tell application "Numbers"
set mydoc to make new document
set name of mydoc to "My New Document"
end tell
In my opinion this approach is "safer" than the previous answer because you are capturing a reference to the document that you've just created rather than getting a generic reference to "document 1" after you create your document. Most of the time, you should have an issue with the "document 1" approach, but the time you do, it will be very frustrating and cause a lot of confusion.
Best of luck
Just to keep the whole solution within applescript, which allows creation without intervention:
tell application "Numbers"
set nDoc to make new document
save nDoc in file ((path to desktop as text) & "crap.numbers")
end tell
While these Numbers commands (make, save) have multiple parameters, they don't seem to work as defined in the dictionary.
I've got a script than on login, ask a user if they want to watch a movie. For the most part it works great. However on occasion and for reasons unknown to me I get an AppleEvent handler failed error. I've read other post on this error but they all seem to be unique. So, if possible can someone please take a look at my script and tell me why this occasionally pops up and if there's anything i can do to prevent it?
One thing that might help to know, is the one thing in the script that fails when this error occurs is the movie doesn't play. It opens in quicktime but doesn't start.
Thanks in advance, here's the script.
tell application "Welcome" to activate
set question to display dialog "Would you like a welcome video?" buttons {"No, I've seen it", "Yes, please"} default button 2
set answer to button returned of question
if answer is equal to "Yes, please" then tell application "QuickTime Player"
set theMovie to "Macintosh HD:Library:Desktop Pictures:Mac ML Opening Chalkbaord Video.mov"
set openMovie to open theMovie
present openMovie
play openMovie
delay 30
quit
end tell
if answer is equal to "No, I've seen it" then tell application "Welcome"
quit
tell application "System Events"
delete login item "Welcome"
end tell
end tell
My guess is that you probably need a delay between opening and playing the movie. Sometimes the code runs faster than the computer can react. If that's the case then the movie may still be trying to open when the code tells the movie to play... thus the error. As such I added 2 repeat loops which checks for things to make sure they're available before proceeding to the next step in the code. You also need "open file" in the code instead of just "open".
Your approach in your if statements of telling an application to do something is unusual. I wouldn't do that. I would also combine your if statements into one if/else if statement. Anyway, here's how I would write your code (I'm assuming application "Welcome" is the code itself). I hope this helps!
set theMovie to "Macintosh HD:Library:Desktop Pictures:Mac ML Opening Chalkbaord Video.mov"
tell me to activate
set question to display dialog "Would you like a welcome video?" buttons {"No, I've seen it", "Yes, please"} default button 2
set answer to button returned of question
if answer is equal to "Yes, please" then
tell application "QuickTime Player"
activate
set openMovie to open file theMovie
-- delay until the movie opens
set startTime to current date
repeat until exists document 1
delay 0.2
if (current date) - startTime is greater than 10 then return -- a precaution so you don't get stuck in the repeat loop forever
end repeat
present openMovie
play openMovie
-- delay until the movie stops playing
repeat until document 1 is not playing
delay 1
end repeat
quit
end tell
else if answer is equal to "No, I've seen it" then
tell application "System Events" to delete login item "Welcome"
end if