This is my first post in stackoverflow. I've spent weeks trying to get an Applescript to remove people from established Groups (not Smart Groups) in Contacts (Mac Address Book). The script removes several people then issues an error. If I re-run the script after the error is issued, it will remove a few more people from the group and then issue the same error again. I can continue doing this until eventually everyone is removed from the group. I don't understand why the error is issued when re-running the script after the error is issued results in a few more people being removed before the error is issued again. - And again, I can continue re-running the script until eventually every person is removed from the group. This suggests the contact records are not corrupted.
I've tried moving the SAVE command around but that didn't help. The Group I'm removing contacts from is labeled "Family".
The error issued is...
error "Contacts got an error: Can’t get group \"Family\"." number -1728 from group "Family"
tell application "Contacts"
set group_list to name of every group
repeat with anItem in group_list
set AppleScript's text item delimiters to ""
repeat 1 times
if first item of anItem is not "$" then exit repeat
set AppleScript's text item delimiters to "$"
set gruppe to text item 2 of anItem
if group gruppe exists then
--remove every person from group
repeat with person_to_remove in every person in group gruppe
set firstName to first name of every person in group gruppe
set group_count to count every person in group gruppe
remove person_to_remove from group gruppe
save
end repeat
end if
end repeat
end repeat
save
return "Done"
end tell
I think you're trying to hard. There is no need to change applescripts text item delimiters you can still find out if the group has a $ a the beginning of the group name
creating a 1 time loop is just weird not sure why you chose to do it that way.
you know the group already exists because you are looping through them so no need for that either
so here it is
tell application "Contacts"
set group_list to name of every group
repeat with aGroup in group_list
if first item of aGroup is "$" then
set thePeople to every person in group aGroup
repeat with aPerson in thePeople
remove aPerson from group aGroup
end repeat
end if
end repeat
save
end tell
Related
My Apple Music library is too big. I want to weed it out by removing a whole load of tracks that I have never listened to. I already did the same thing successfully with playlists but my script isn't working to remove tracks:
tell application "Music"
activate
set mytracks_list to (get the id of (every track whose loved is false and played count is 0 and rating is less than 60))
repeat with mytrack_id in mytracks_list
delete (the track whose id is mytrack_id)
end repeat
end tell
The mytracks_list is populated with no problems. The error message I get is:
error "Can’t get track whose id = item 1 of {130098, [............] }
Am I doing something wrong, and can it be made to work?
P.S. This is what worked for my playlists:
tell application "Music"
activate
set myplaylists_to_delete to (get the name of every playlist whose name does not contain "Adrian" and name does not contain "Loved" and name does not contain "Shazam" and name does not contain "Library" and name is not "Music" and name does not contain "Recent" and name does not contain "5 Stars" and name does not contain "Duo")
repeat with myplaylist in myplaylists_to_delete
delete playlist myplaylist
end repeat
end tell
Did you try:
tell app "Music"
delete every track whose loved is false and played count is 0 and rating is less than 60
end tell
Well-designed, well-implemented “AppleScriptable" apps can usually apply a command to multiple objects; you don’t need to iterate the objects yourself. (Hint: Apple event IPC = RPC + queries, not OOP.)
I have written an AppleScript that is activated by a mail rule whenever an email comes in that contains "+".
Why? I host my own mail server that allows for address tagging. What this means is that for example when I'm at a store and they ask for my email address, so they can email the receipt, I can give them my email address like this: whatmyemailnormallyis+nameofstore#domain.com. The applescript should then get the string between the "+" and "#" character, create a mailbox called "nameofstore" and move the message to it. Everything works fine except for I'm getting the following error:
"Mail got an error: Can’t set text item delimiters to {"+", "#"}."
This is my script:
tell application "Mail"
set unreadmessages to the first message of mailbox "INBOX" of account "Account"
set theEmail to extract address from sender of item 1 of unreadmessages
set mystring to theEmail
set text item delimiters to {"+", "#"}
set textlist to text items of mystring
set mylist to {}
repeat with i from 2 to count of textlist by 2
set end of mylist to item i of textlist
end repeat
get mylist
set mailboxName to mylist
set messageAccount to account of (mailbox of item 1 of unreadmessages)
set newMailbox to make new mailbox at (end of mailboxes of messageAccount) with properties {name:mailboxName}
repeat with eachMessage in unreadmessages
set mailbox of eachMessage to newMailbox
end repeat
end tell
When I run only the text extract portion of the script it works fine:
set mystring to "whatmyemailnormallyis+nameofstore#domain.com"
set text item delimiters to {"+", "#"}
set textlist to text items of mystring
set mylist to {}
repeat with i from 2 to count of textlist by 2
set end of mylist to item i of textlist
end repeat
get mylist
result:
{"nameofstore"}
Any help would be greatly appreciated. If anyone with better AppleScript skills than me can improve the script in other areas that would also be greatly appreciated.
This is an inheritance problem. The property (text item delimiters) is a property of the current application (AppleScript) instance, but it's being referenced unqualified inside the tell application block that directs commands to and enumerates properties from the target application, in this case Mail.
The temptation might be to set the text item delimiters outside the tell block, by moving it from its current line position to just before the block declaration. That's reasonable, but I think you've positioned it perfectly, as it's important (and good practice) to keep track of this property to ensure it's always appropriately set and, more significantly, never inappropriately not set. The most reliable way to do this, which also makes it easier to follow for other people, is to do as you've done, which is to set the property immediately prior to any statement where it exerts influence (namely, any time a list is coerced to text, or text is split into text items).
So, to avoid shuffling lines of code around, we need to be able to make it clear to the compiler that the property that we're referencing doesn't belong to application "Mail", but to the top-level scripting object, which will most typically be the current application. The three ways to do this are:
set AppleScript's text item delimiters to ...
set the current application's text item delimiters to ...
set my text item delimiters to ...
Stylistically, I favour the last option. However, my is not a synonym for current application nor for AppleScript, but rather a reference to the parent of your script. Unless the parent property is specifically declared in your script, then it will default to current application. However, there are reasons one might choose to assign a different value, in which case only the first or second of the above three options will be viable.
Here's a slight reworking of your script, which I'm afraid you'll have to test in lieu of my purchase of a new MacBook. I noticed some oddities in yours:
You obtain the first message in the inbox, but on the next line, reference item 1... of, what I imagine you thought would be a list of messages, but would in fact be a single message class object.
This single message object is the only message your script utilises to process the sender's email address. However, later on, you loop through, again, what you expect to be a collection of inbox messages, which, if it were, may not all have the same + tag.
You loopp through the text items generated by splitting the email address, and quite smartly start at index 2, and skip over every other item in the list. However, this list will only have three items in it, so there's never any looping to be done, and you can simply make use of text item 2.
In creating a new mailbox, you didn't first check to see if the mailbox already exists. I'm not sure whether Mail would throw an error, or silently ignore this. But I've redrafted the line to check first, and create if necessary.
Lastly, the final repeat loop is presently not necessary given unreadmessages is not a list (so might actually throw an error). So I removed the loop construct, but otherwise kept the line as it was. I'm not sure whether the mailbox property of a message is one that can be set, i.e. it might be read-only. If this is the case, that will throw an error, and you'll have to invoke the move command in order to move a message to a new mailbox. I may be wrong, though, and it may work just the way you intended.
tell application "Mail"
set firstInboxMessage to the first message in the inbox
set theEmail to extract address from sender of the firstInboxMessage
set my text item delimiters to {"+", "#"}
-- Since the script will trigger only when an email address
-- contains "+", we know text item 2 will always exist and
-- will always represent the slice of text we're after
set mailboxName to text item 2 of theEmail
set messageAccount to account of mailbox of the firstInboxMessage
tell the messageAccount to if the name of its mailboxes does not contain ¬
the mailboxName then make new mailbox at the end of its mailboxes ¬
with properties {name:mailboxName}
set newMailbox to the mailbox named mailboxName in the messageAccount
set the mailbox of the firstInboxMessage to the newMailbox
end tell
In reality, if you're invoking this script as a mail rule, you'll probably want to enclose this within the special handler that you can look up in the Mail scripting dictionary, called something like on receiving messages <messages> for mailbox rule <rule>
I am trying to write a script that does the following job: it goes through all of the emails in the mailbox, finds the ones that have the word "French" in their subject line and then copies all the subject lines of those emails in a text file. Here is what I came up with
tell application "TextEdit"
make new document
end tell
tell application "Mail"
tell the mailbox "Inbox" of account "tigeresque#gmail.com"
set numm to count of messages
repeat with kk from 1 to numm
set wordsub to subject of the message kk
tell application "TextEdit"
if "French" is in wordsub then
set paragraph kk of front document to wordsub & return
end if
end tell
end repeat
end tell
end tell
Unfortunately, I keep receiving the error
"TextEdit got an error: The index of the event is too large to be valid."
and I have already spent a couple of hours trying to fix it without much success. Could you please take a look at my code and see what is wrong with it?
Your main problem is that the number of paragraphs in TextEdit and the number of email messages have nothing to do with each other, so if you're counting on the number of messages then TextEdit will not understand it. For example you may have 50 messages but TextEdit does not have 50 paragraphs so it errors. As such we just use a separate counter for TextEdit.
I made other changes too. I often see errors happen by having one "tell application" block of code inside another... so I separated them. Also notice that the only code inside of any "tell application" block is only what is necessary for that application to handle. This too avoids errors. These are good habits to have when programming.
Therefore give this a try...
set searchWord to "French"
set emailAddress to "tigeresque#gmail.com"
tell application "Mail"
set theSubjects to subject of messages of mailbox "INBOX" of account emailAddress
end tell
set paraCounter to 1
repeat with i from 1 to count of theSubjects
set thisSubject to item i of theSubjects
if thisSubject contains searchWord then
tell application "TextEdit"
set paragraph paraCounter of front document to thisSubject & return
end tell
set paraCounter to paraCounter + 1
end if
end repeat
I am trying to clean the holes out of my Mac address book. As a first step I want to ask all my friends for their birthday, to be able to congratulate them with cheesy Hallmark cards.
I need a "group" in my address book, to mailmerge personalized messages from.
This is the Applescript I came up with:
tell application "Address Book"
make new group with properties {name:"No Birthday"}
set birthdayPeople to (get every person whose birth date is greater than date "Monday, January 1, 1900 12:00:00 AM")
repeat with i from 1 to number of items in people
set thePerson to item i of people
if not (birthdayPeople contains thePerson) then
add thePerson to group "No Birthday"
end if
end repeat
save
end tell
It breaks, but from the error messages I cannot deduce what is wrong:
Result: error "Can’t make «class azf4»
id
\"05F770BA-7492-436B-9B58-E24F494702F8:ABPerson\"
of application \"Address Book\" into
type vector." number -1700 from «class
azf4» id
"05F770BA-7492-436B-9B58-E24F494702F8:ABPerson" to vector
(BTW: Did I mention this is my first AppleScript code, EVER? So, if this code can be simplified, or made more elegant, that is welcome too.)
We can simplify this down to five lines:
tell application "Address Book"
add (every person whose birth date is missing value) to ¬
make new group with properties {name:"No Birthday"}
save addressbook
end tell
It turns out that add can take a list as well as a single object, so we can skip the loop. (Note that if you had used a loop, you could have used the repeat with thePerson in people ... end repeat form, as that's cleaner than what you had.) Next, it appears that Address Book stores missing birthdays as missing value (effectively null), so we should check for that rather than comparing against an early date. Thus, to get a list of the birthdayless people, we write every person whose birth date is missing value, which does exactly what it says. The whose clause filters the preceding list so that it only contains values matching the given predicate. We then add that list to the new group, which we create inline. Finally, save addressbook saves the changes and makes them visible.
However, in this case, you don't need an AppleScript at all. Address Book supports smart groups; to create one, option-click the new group button. Choose "No Birthdays" for the smart group's name, and tell it to match cards for which "Birthday" (from the first dropdown) "is not set" (from the second dropdown). This will give you a dynamically-updating group of people who have no set birthday.
Edit: It seems that while add takes a list on Leopard, it doesn't on Snow Leopard, so we'll need to use an explicit repeat loop (which works on Leopard too):
tell application "Address Book"
set noBirthdays to make new group with properties {name:"No Birthday"}
repeat with p in (every person whose birth date is missing value)
add p to noBirthdays
end repeat
save addressbook
end tell
This works almost the same way as the above solution, except we make the group beforehand, and then add each item individually. Rather than iterating over the indices, we iterate over the elements directly, since that's all we care about here.
Edit: For other properties, things are similar; in fact, when using the smart group, things are identical. From the AppleScript side, the question is the format of the data. Most slots have missing value when they're unset, but email is an exception. As we can see by testing, they're stored in a list, so we want every person whose email is {}. However, this doesn't work for me—probably because email is a list, but I'm not sure—so you'll instead want
repeat with p in every person
if email of p is {} then add p to noEmails
end repeat
And voilà, everything should work.
In- and excluding businesses is also easy, but as far as I can tell, Address Book doesn't provide a way to create a smart group for them. However, the relevant property is company, which is true for businesses and false for others. Thus, to create a list without companies, you want to do
repeat with p in (every person whose company is false)
add p to noCompanies
end repeat
If you want one master list with all of these criteria, there are two ways. First, from AppleScript, you take the two condition and and them, then add conditioning on whether or not they have an email:
repeat with p in (every person whose company is false and ¬
birth date is missing value)
if email of p is {} then add p to masterGroup
end repeat
The other option is to do this from Address Book. You first need to create a No Companies group the AppleScript way. You then create a smart group matching all of three conditions (you add them with the + button): "Email is not set", "Birthday is not set", and "Card is a member of 'No Companies'". This is probably the best option, although it's unfortunate that you have to use AppleScript for the No Companies group (I feel like there should be a way, but I can't see what it is).
I've successfully managed to add files to a group with AppleScript, but I also need to be able to remove a child group.
I thought something like
tell currentGroup
--remove any groups already present
repeat with groupItem in groups
--display alert " " & name of groupItem
remove groupItem from groups
end repeat
end tell
but it tells me that remove is not supported by that container.
Any ideas?
Such can be accomplished by for example the following:
tell application "Xcode"
tell front project
set parent_group to first group
delete first group of parent_group
end tell
end tell
I figured it out. To remove all groups in a group I can just do
delete groups of currentGroup
I'm not sure how I would remove just a single group though.