Applescript prints "missing value" instead of empty string - applescript

I'm using this Applescript to display the Reminders from a list called "Cities" on my Desktop using GeekTool, but for some reason for every reminder in this list without anything in the body it prints out "missing value". How can I make it so it doesn't?
set theList to {}
set theOutput to ""
tell application "Reminders"
repeat with i from 1 to (count of every reminder of list "Cities")
if reminder i of list "Cities" is not completed then
set theList to theList & {name, body} of reminder i of list "Cities"
end if
end repeat
repeat with i from 1 to (count of every item of theList)
set theOutput to (theOutput & item i of theList as string) & return
end repeat
return theOutput
end tell
The output I'm after is:
Istanbul - visited Mar 2008
Las Vegas
Kyoto - visited Feb 2012
Currently its:
Istanbul
visited Mar 2008
Las Vegas
Kyoto
visited Dec 2012

This is happening because the value of an empty body is missing value, which, when you convert it to a string, becomes "missing value". To avoid this, you can explicitly check for a missing value in the reminder before adding it to theList.
repeat with i from 1 to (count of every reminder of list "Cities")
set theReminder to reminder i of list "Cities"
if theReminder is not completed then
if the body of theReminder is not missing value then
set theList to theList & {name, body} of theReminder
else
set theList to theList & {name of theReminder, ""}
end if
end if
end repeat
If you don't want a blank line between reminders with no body, you can simply use {name of theReminder} in the else clause.

Related

How to fix "Can't make missing value into type date"

I am trying to list all the reminders from the app where the due date is missing but I get the above mentioned error. Any body knows how to check for a missing value in such case?
Here is the code:
set remListOut to ""
set curDate to current date
tell application "Reminders"
activate
repeat with theRemList in remLists
tell list "#Call"
set remList to (every reminder whose due date is missing value)
repeat with theRem in remList
log (get properties of theRem)
set remListOut to remListOut & name of theRem & "
"
end repeat
end tell
end repeat
end tell
return remListOut
I regard this as a bug, the code is correct.
As a workaround use a second loop
set remListOut to ""
set curDate to current date
tell application "Reminders"
repeat with aList in lists
repeat with aReminder in reminders of aList
if due date of aReminder is missing value then
log (get properties of aReminder)
set remListOut to remListOut & name of aReminder & return & tab & tab
end if
end repeat
end repeat
end tell
return remListOut

Applescript: Highlight most recent file from group

I'd like to know how you'd go about creating an action where you could highlight a group of files and get the modification date from them, then have it highlight/select/label the file with the most recent date.
UPDATE: I want to do it on Applescript because I've gotten further in that. Here's what I have so far
set dateList to {}
tell application "Finder"
set inputList to get selection
repeat with i from 1 to count (inputList)
set end of dateList to get modification date of item i of inputList
end repeat
end tell
dateList
--Compare section...
set boolList to {}
set j to 1
repeat with i from 1 to count (dateList)
if i is (count (dateList)) then
set j to 0
end if
set end of boolList to item i of dateList > item (i + j) of dateList
end repeat
boolList
Looking at your existing applescript code this should sort any files you've selected by last modified date and return the latest result into a dialog box for you:
set dateList to {}
tell application "Finder"
set inputList to get selection
repeat with i from 1 to count (inputList)
set end of dateList to get modification date of item i of inputList
end repeat
end tell
--Compare section...
set modDate to item 1 of dateList
repeat with i from 1 to count (inputList)
if dateList's item i > modDate then
set modDate to dateList's item i
set theResult to displayed name of item i of inputList
set theResultDate to item i of dateList
end if
end repeat
--Display Result…
display alert "Most recently modified file in selection:" message "" & theResult & "
" & theResultDate
Dick got it, but I just fixed something and made it so it labels the file instead of a popup.
set dateList to {}
tell application "Finder"
set inputList to get selection
repeat with i from 1 to count (inputList)
set end of dateList to get modification date of item i of inputList
end repeat
end tell
--Compare section...
set theResult to item 1 of inputList as alias
set theResultDate to item 1 of dateList
set modDate to item 1 of dateList
repeat with i from 1 to count (inputList)
if dateList's item i > modDate then
set modDate to dateList's item i
set theResult to item i of inputList as alias
set theResultDate to item i of dateList
end if
end repeat
--Display Result…
--display alert "Most recently modified file in selection:" message "" & theResult & "
--" & theResultDate
tell application "Finder" to set label index of (theResult as alias) to 6
This will label it green, if you want a different color fiddle around with the index number 1-8, they're apparently not in order. Finder is also apparently smart enough to not count the selections in other open windows.
Thanks!
And finally, to make it useful as a right-click item, open Automator, make a Service, select at the top to use this on files/folders, drag Run Applescript in there, paste script, save. Now it will be available on right click. One downside is it seems the files need to stay selected until something is labeled. So no clicking while it's working.
You are making it more complicated than it needs to be:
tell application "Finder" to reveal item 1 of (sort (get selection) by modification date)
There is a bug in 10.7 and 10.8 that can make all of the suggested scripts almost unusable depending on the way they are run. If you open a new Finder window and select some files, tell application "Finder" to selection returns files selected in some window behind the frontmost window (or an empty list).
One workaround is to switch focus to another application and back:
activate app "SystemUIServer"
tell application "Finder"
activate
set label index of item 1 of (sort selection by modification date) to 6
end tell
You could also create an Automator service with a Run AppleScript action like this:
on run {input, parameters}
tell application "Finder"
sort (input as alias list) by modification date
set label index of item 1 of result to 6
end tell
end run

can i add several attachments from subfolders to Mail?

trying to send several mails with specific attachments for each address. every address has its own subfolder for attachments. the "grab attachments part" does not work and I am not sure if the handler is set up right: should I pass the subfolder to mail inside the handler or keep it as I have it. This is my first long script so please don't be too harsh ;-)
I'm thinking that i get closer to the working solution, I still don't get it to function. here is my script so far:
` with timeout of 600 seconds
-- Liste: Alle Empfänger
tell application "Contacts"
set emailList to {}
set testPersons to every person of group "Test"
repeat with thisTestPerson in testPersons
set end of emailList to (value of email of thisTestPerson) as string
end repeat
end tell
-- Liste fuer die Übergabe alphabetisch sortieren
set the_list to emailList
set otid to AppleScript's text item delimiters
set AppleScript's text item delimiters to {ASCII character 10} -- always a linefeed
set list_string to (the_list as string)
set new_string to do shell script "echo " & quoted form of list_string & " | sort -f"
set new_list to (paragraphs of new_string)
set AppleScript's text item delimiters to otid
-- Liste: Alle Subfolder
tell application "Finder"
set mainfolder to choose folder "select a folder"
set folderList to {}
set myFolders to every folder of mainfolder
repeat with attachFolder from 1 to (count of myFolders)
set end of folderList to attachFolder as string
end repeat
end tell
-- Sicherheits-Check
set count1 to count of myFolders
set count2 to count of new_list
if count1 is not equal to count2 then
display dialog "Houston, we have a problem:" & return & "Die beiden Listen sind nicht gleich lang..." buttons {"ok"} with icon 2
return
end if
end timeout
--handler processfolder(myFiles)
on processfolder(myFiles)
tell application "Mail"
activate
set theAddress to (item i of emailList)
set theMex to (make new outgoing message at end of outgoing messages with properties {visible:true, subject:"Subjectheader", content:"email body"})
tell content of theMex
make new attachment with properties {file name:FileList} at after last paragraph
end tell
tell theMex
make new to recipient at end of to recipients with properties {address:theAddress}
end tell
send theMex
end tell
end processfolder
-- grab attachments and send mail
tell application "Finder"
repeat with myFolder from 1 to (count of folderList)
set FileList to {}
set myFiles to entire contents of myFolder
repeat with thisFile in myFiles
set end of FileList to thisFile as string
end repeat
my processfolder(myFiles)
end repeat
end tell
display dialog (count1 as string) & " Nachrichten verschickt."
end`
i believe the handler should work alright. Matching the subfolder list with the address list still seems to be a problem, I am not sure if my repeat loop "grab attachment und send mail" does the trick. It is a tricky use of repeat loops and I am still struggling with it. any quick thoughts about what I am still doing wrong?
thanks for being helpful! i really appreciate this!
marco
You must pass the variables as parameters in the handler :
1- (item i of emailList) : i and emailList is not defined in the handler.
2- {file name:FileList} : FileList is not defined in the handler, file name must be a path of type alias or string, not a list of path.
set myFiles to entire contents of myFolder : the myfolder variable is an integer, entire contents will contains the folders and files, if the folder doesn't contains subfolders, entire contents is useless, use files of xFolder.
The rest is okay, but contains unnecessary lines.
Here is the script:
with timeout of 600 seconds
-- Liste: Alle Empfänger
tell application "Contacts"
set emailList to value of email 1 of every person of group "Test"
end tell
-- Liste fuer die Übergabe alphabetisch sortieren
set otid to AppleScript's text item delimiters
set AppleScript's text item delimiters to {linefeed}
do shell script "echo " & (quoted form of (emailList as string)) & " | sort -f"
set emailList to (paragraphs of the result)
set AppleScript's text item delimiters to otid
-- Liste: Alle Subfolder
activate
set mainfolder to choose folder "select a folder"
tell application "Finder" to set folderList to folders of mainfolder
-- Sicherheits-Check
set count1 to count folderList
if count1 is not equal to (count emailList) then
display dialog "Houston, we have a problem:" & return & "Die beiden Listen sind nicht gleich lang..." buttons {"ok"} cancel button "ok" with icon 2
end if
end timeout
-- grab attachments and send mail
repeat with i from 1 to count1
try
tell application "Finder" to set myFiles to (files of entire contents of (item i of folderList)) as alias list
my processfolder(myFiles, item i of emailList)
end try -- no error on empty folder
end repeat
display dialog (count1 as string) & " Nachrichten verschickt."
on processfolder(tFiles, theAddress)
tell application "Mail"
activate
tell (make new outgoing message at end of outgoing messages with properties {visible:true, subject:"Subjectheader", content:("email body" & linefeed & " ")})
make new to recipient at end of to recipients with properties {address:theAddress}
tell content to repeat with tFile in tFiles
make new attachment with properties {file name:tFile} at after last paragraph
make new character with data linefeed at after last paragraph
end repeat
send
end tell
end tell
end processfolder
it is done! Thanks to you and one or two other pros I now have a beautiful bulk mailing script routine using automator, a bash line and (mainly) applescript. I use it for job applications but you can use it for any case where you want individualised bulk emailing with Mail, MS Word and any given list of contacts in Excel (or Address Book for that matter). For the sake of being complete I will add all necessary steps. with any given list of x names, email addresses, personal addresses you can generate x subfolders, containing x personalized letters and not-personalized documents (thanks, Jack! adding the docs works perfectly). once you start the last script and select the folder you can watch mail sending them all out, addressing the person by name and attaching the right personalized letter! It corrects for foreign name spelling that is rendered differently in the email address. It works best for email addresses using the last name before the "#" and can now ignore the first name if it is set in front of the last name (i.e. firstname.lastname#company.com). Thank you all very much for the assistance! this was great team effort.
I shall post it as soon as I am home, should I post it up here and in the other related question or is there a sharing forum?

Get the recipient of a draft (AppleScript, Mail.app)

I want to get the recipients ("to" fields, etc) of a draft on my draft's folder of Mail.app, by using AppleScript. Can't seem to find the correct syntax to that.
Thanks.
Here's code to do it, in Scripting Bridge (Cocoa):
for (MailRecipient *recp in message.recipients) {
MailToRecipient *theRecipient = [[[mail classForScriptingClass:#"to recipient"] alloc] initWithProperties:[NSDictionary dictionaryWithObjectsAndKeys:recp.address, #"address", nil]];
}
Actually it is possible with pure AppleScript unlike the Cocoa solution proposed earlier. Here's a snippet of the code used to get the input values of the "TO" recipients field.
tell application "Mail"
set draftMessages to every message in drafts mailbox
set draftMessagesID to {}
# go through each draft message
repeat with draftMessage in draftMessages
set draftMessageID to id of draftMessage as string
copy draftMessageID to the end of draftMessagesID
end repeat
# go through the list of draft message ids and process the most recent item
if (count of the draftMessagesID) is greater than 1 then
set sortedDraftMessagesID to the reverse of my sortAlphabetically(the draftMessagesID)
# get only the first item, as this is the most recent
set lastDraftMessageID to first item of sortedDraftMessagesID as integer
# get the most recent draft message
set draftMessage to first message of drafts mailbox whose id is lastDraftMessageID
set toAddresees to {}
repeat with toRecipient in (get to recipients of draftMessage)
set toName to name of toRecipient
set toAddress to address of toRecipient
set toFinal to my composeNameAndAddress(toName, toAddress)
copy toFinal to end of toAddresees
end repeat
# now you have the input values of the TO field
log toAddresees
end if
end tell
#handler to compose name and address when one is missing
on composeNameAndAddress(name, address)
if name is missing value then
return address
else
return name & space & "<" & address & ">"
end if
end composeNameAndAddress
#handler to sort a list alphabetically
on sortAlphabetically(theList)
set the indexList to {}
set the sortedList to {}
repeat (the number of items in theList) times
set the lowItem to ""
repeat with i from 1 to (number of items in theList)
if i is not in the indexList then
set thisItem to item i of theList as string
if the lowItem is "" then
set the lowItem to thisItem
set the lowItemIndex to i
else if thisItem comes before the lowItem then
set the lowItem to thisItem
set the lowItemIndex to i
end if
end if
end repeat
set the end of sortedList to the lowItem
set the end of the indexList to the lowItemIndex
end repeat
return the sortedList
end sortAlphabetically
You mentioned that you needed a specific draft, for this script I've assumed that you can (for instance) obtain the latest draft by taking the draft message with the highest ID. This is what the above script does using the reverse command with a generic simple sort handler.
The drafts mailbox is contained by the message viewer. Since the messages have not been sent yet, you cannot get its "to recipients". However, you can get the message source that contains the list of recipients. The trick is to then extract the recipients from this text.
tell application "Mail"
set the_messages to every message in drafts mailbox
repeat with this_message in the_messages
set message_content to the source of this_message
log message_content
end repeat
end tell

How do I fix my AppleScript to delete a selection of tracks in iTunes?

I've created the following AppleScript for deleting all the selected tracks:
property okflag : false
-- check if iTunes is running
tell application "Finder"
if (get name of every process) contains "iTunes" then set okflag to true
end tell
if okflag then
tell application "iTunes"
if selection is not {} then
repeat with this_track in selection
try
try
set cla to class of this_track
set floc to (get location of this_track)
delete this_track
on error error_message number error_number
display alert error_message message ("Error number: ") & error_number & "."
end try
if cla is file track then
my delete_the_file(floc)
end if
end try
end repeat
end if
end tell
end if
to delete_the_file(floc)
try
-- tell application "Finder" to delete floc
do shell script "mv " & quoted form of POSIX path of (floc as string) & " " & quoted form of POSIX path of (path to trash as string)
on error
display dialog "Track deleted, but could not be moved to trash" buttons {"Hmm"} default button 1 with icon 1
end try
end delete_the_file
It works fine when I select a single item, but when I select more than one I get: "Can't get location of item 2 of selection" (error number -1728). I believe this is because by deleting a track, the script's index into the selection is corrupted.
I thought I'd try making my own list of tracks to be deleted first:
tell application "iTunes"
if selection is not {} then
set to_delete to {}
repeat with this_track in selection
try
set cla to class of this_track
set floc to (get location of this_track)
if cla is file track then
set pair to {this_track, floc}
set to_delete to to_delete & pair
end if
end try
end repeat
repeat with pair in to_delete
set the_track to item 1 of pair
set floc to item 2 of pair
delete the_track
my delete_the_file(floc)
end repeat
end if
end tell
But then I get 'Can't get item 1 of item 1 of selection of application "iTunes".' I think the problem is "this_track" is not an object of class Track, but an item of a selection. How do I get the actual track object from the selection item?
If you don't see the solution, I'll welcome tips on debugging or any other suggestions.
The variable this_track is a reference to an object specifier. You have to use the contents property to get the enclosed object specifier. The same is true for accessing the variable pair in the second loop. See the class reference section on the class reference in the AppleScript language guide.
Another problem exists in the way the list to_delete is being built. The statement set to_delete to to_delete & pair will not produce a list of pairs but a flat list. See the class reference section on the class list in the AppleScript language guide.
Here's a version of your second script, where these bugs have been removed:
tell application "iTunes"
if selection is not {} then
set to_delete to {}
repeat with this_track in selection
try
set cla to class of this_track
set floc to (get location of this_track)
if cla is file track then
set pair to {contents of this_track, floc}
copy pair to end of to_delete
end if
end try
end repeat
repeat with pair in to_delete
set the_track to item 1 of contents of pair
set floc to item 2 of contents of pair
delete the_track
my delete_the_file(floc)
end repeat
end if
end tell

Resources