Applescript - remember state between executions? - applescript

Some Applescripts I have used have remembered state between executions, e.g., location for Open/Save dialogues.
Now I have written an AS that takes a string as input from the user (via a display dialog). I would like the script to remember that string between executions. Possible? How?

If you make the string a property, it will remember that string between executions, until the next time you open up and re-save the script.
Here’s an example:
property myName : ""
if myName is "" then
display dialog "What is your name?" default answer ""
set myName to the text returned of the result
end if
display notification "Hello, " & myName
Save the script as an “Application”, “Script”, or “Script bundle”. If saved as “Text” (or if run from Script Editor) it will not maintain properties between runs.
The first time you run it, it will notice that myName is the empty string and request your name.
Subsequent times you run it, it will already have your name in the property myName.
If you open the script again, and then resave the script, this resets all properties. If you need the script to retain data through edits, you’ll need to save it in a database, which could be as simple as a text file in a central location.
set nameFile to POSIX file "/Users/USERNAME/name.txt"
tell application "Finder"
if exists nameFile then
set nameFileHandle to open for access nameFile
set myName to read nameFileHandle
close access nameFileHandle
else
display dialog "What is your name?" default answer ""
set myName to the text returned of the result
set nameFileHandle to open for access nameFile with write permission
write myName to nameFileHandle
close access nameFileHandle
end if
end tell
display notification "Hello, " & myName
In this case the variable nameFile doesn’t need to be a property since it never changes. Because it doesn’t need to be a property, this version also does not need to be saved as non-Text, and can even be run from Script Editor.
It is also very simple; if you need to store and retrieve multiple items, you would need to follow up on the “File Read/Write” section of “StandardAdditions”. You can get there from Script Editor under “File:Open Dictionary…”.
For more complex memory, you may find the “Property List Suite” in the “System Events” dictionary useful.

Related

Global variable "not defined"

My AppleScript examines an image file and outputs some of that information. I need this information as normal output (stdout) of the script for further processing (in an InDesign script). But as soon as I open an image file in my AppleScript, the global variable which is meant to hold the result, gets lost.
This is fine (but useless):
global result
set result to "initialised"
set imgfile to POSIX file "/Users/hell/Pictures/interesting_stuff.jpg" as alias
tell application "Image Events"
-- start the Image Events application
launch
set result to "new text"
end tell
return quoted form of result
The following script is what I want, but throws the error "The variable 'result' is not defined (-2753)"
global result
set result to "initialised"
set imgfile to POSIX file "/Users/me/Pictures/interesting_stuff.jpg" as alias
tell application "Image Events"
-- start the Image Events application
launch
-- open image file
set img to open imgfile
-- here would go some commands about img instead of "new text"
set result to "new text"
-- close image file
close img
end tell
return quoted form of result
What is the problem here and how can I get the result out of my script?
result is a special identifier in AppleScript, which you may notice in Script Editor is printed in a different colour/font/style to other variable names you use. It's an AppleScript property that always contains the value returned by the command that is executed immediately before it.
The solution is most likely to choose a different word other than result for your identifier.
As your script stands, you also don't need to declare the variable as a global, since there are no scoping issues in your script that require access to variables outside of its block, which becomes a consideration when creating handlers or script objects.

"current record" doesn't work: applescripting Filemaker Pro 13 in a loop

I have an filemaker Pro 13 database with around 120 records (it's for a conference). I want to team it up with BBEdit to create individual files for each abstract, thus applescript. Much to my surprise (and despite a lot of web tips on scripting) '[tag:current record]' is not recognised in the script.
The relevant bit is this:
FM Script:
Loop
Perform Applescript
tell application "FileMaker Pro"
activate
set MyFileName to cell "WebAbstractFileName" of table "SelectionProcess"
set MyWebAbstract to cell "WebAbstract" of table "SelectionProcess" as text
end tell
-- (BBEdit bit, which works fine in testing)
Go to Next Record (exit after last)
End Loop
This works fine if I only want to retrieve the first record!
This applescript is set within a filemaker script which loops through the records but the script doesn't care which record it's in.
I've tried adding 'of current record' before the table reference but it then gives me errors (eg error "FileMaker Pro got an error: Object not found." number -1728 from cell "WebAbstractFileName" of current record of table "SelectionProcess") Without 'current record' it works fine, but only gives me the first record.
Here's (roughly) how you could do this in a Filemaker script:
Go to Layout [ “YourTable” ]
# FIND THE RECORDS OF INTEREST
Perform Find [ Restore ]
Go to Record/Request/Page [ First ]
Loop
New Window [ ]
# ISOLATE THE CURRENT RECORD
Show All Records
Omit Record
Show Omitted Only
Set Variable [ $path; Value:Get ( DocumentsPath ) & "someFolder/" & YourTable::Somefield & ".html" ]
Export Records [ No dialog; “$path” ]
Close Window [ Current Window ]
Go to Record/Request/Page [ Next; Exit after last ]
End Loop
This will export every record in the found set as an individual file into the folder "someFolder" located in the user's Documents folder, using the contents of the YourTable::Somefield field as the filename.
If, as you say, you don't need the separate files, then of course this can be much simpler.
More tinkering solved this. The crucial bit was to change the syntax. The script now reads:
tell application "FileMaker Pro"
activate
tell current record to set MyFileName to cell "WebAbstractFileName"
tell current record to set MyWebAbstract to cell "WebAbstract"
end tell
What seems to happen is that the fields must be visible (yet I had that not be a problem at one point...go figure. If they're visible, you can drop the table specification). This script, wrapped in a Loop block, will act on the found set and (if instructed) exit after the last record.
I append the bbedit script to create a new file and save it with a variable taken from another field in case it's of interest.
tell application "BBEdit"
set notesPath to ":Users:ophiochos:Dropbox:TL Conference Admin:Webpage materials:Abstracts:"
set newFilePath to notesPath & MyFileName & ".html"
set newDoc to make new text document with properties {contents:MyWebAbstract}
tell newDoc
set source language to "HTML"
save to newFilePath
close window
end tell
end tell
Or you could simply create a calculated field that contains the contents of the desired export file for each record, loop through the records one by one, and just use an Export Field Contents ['YourCalculatedField_c'] script step.
You can also use FM to preview the html output by using a web viewer to display your html. This, along with exporting individually, you can get all this functionality without the need for an external program.
If you need to change the text encoding for output files, you can also specify those in an xslt for outputting files:
http://filemakerhacks.com/2012/09/23/export-field-contents-as-utf-8/
Also, if performing applescript from within FileMaker, the "tell application" line is not needed since it is implied.

Create Apple Script to Map SMB Shares with custom servers

I want to make a applescript that will let the user type in the server name and name of the shared folder and map it via applescript.
I know how to map a set in stone smb share but I want this to be user friendly so they can they type in the share name.
Example
smb://share3/installs
The script would ask what server is it on: share3
Script would ask what is the folder name: installs
Then the script would popup the default connect to server logon info that the user needs to type.
Well, what you're asking for is display dialog and a bit of do shell script, which is detailed in the AppleScript Language Guide (PDF).
So, to answer your question directly, you probably want something like the following:
set server to text returned of (display dialog "Type the name of the server" with title "Open Share" default answer "10.0.10.50")
set share to text returned of (display dialog "Type the name of the share" with title "Open Share" default answer "installs")
do shell script "open smb://" & server & "/" & share
However, if your users are "simple" as you say, then you might not want them typing in server names and share names. Instead, you could provide them with pick lists.
set serverShares to {{"share2", {"installA", "installB"}}, {"share3", {"install1", "install2"}}}
set serverList to {}
repeat with servers in serverShares
set the end of serverList to item 1 of servers
end repeat
set serverChoice to item 1 of (choose from list serverList with title "Open Shared Volume")
set shareList to {}
repeat with i from 1 to length of serverShares
set server to item 1 of item i of serverShares
if server is equal to serverChoice then
set shareList to item 2 of item i of serverShares
exit repeat
end if
end repeat
set shareChoice to item 1 of (choose from list shareList with title "Open Shared Volume")
do shell script "open smb://" & serverChoice & "/" & shareChoice
Just customize the server/share name nested list at the top to customize which shares are available on which servers. Using the shell script open smb://server/share will prompt the user for login credentials if they don't already have them saved in their keychain.

How to Specify filepath but not name InDesign applescript

I am new to applescript.
I am trying to create an Automator script app that opens a batch existing files in InDesign, finds and changes text within the file. ( I thought this would be the complicated bit but it's not it was easy)
What I'm struggling with is then saving these files in another location but using the original filenames as I need to keep the original files.
I have a script to specify a path and a filename but I need to specify the path only and use the existing filename. Is this possible?
The code I tried was this:
tell application "Adobe InDesign CS5.5"
save document 1 to "users:xxx:Desktop:"
close document 1
end tell
It doesn't seem to work for the reason that I'm not specifying a filename BUT I DON'T WANT TO! Is there a way of calling up the original filename?
I'm assuming there must be a way of doing this, as I can't see the point of a script that is specific to one particular file.
My next step is to then rename the files by replacing the last bit of the filename eg:
xxx_xxx_M6.indd to xxx_xxx_M7.indd
I know how to do this in another script but if it can be done in the above section that would be great.
If you want to use the original file name when saving, you can just pull it from the file's properties and combine it with the path you want to save to, like so:
set origName to the name of document 1 as string
save document 1 to ("your:path:here:" & origName)
EDIT: If you already have your own routine for replacing the suffix, you can just perform those operations on origName before you pass it to the save command. I'll leave my look at suffix replacement below just in case it's helpful to anyone.
As for the second part of your question, about replacing a suffix, it depends on what exactly you want to do. From your example I’m guessing you want to increment a number, which you could do with the following code:
set thePoint to the offset of "." in origName
set firstPart to (characters 1 through (thePoint - 1) of origName) as string
set fpLength to the length of firstPart
set newSuffix to ((the last character of firstPart) as number) + 1
set newName to (characters 1 through (fpLength - 1) of firstPart) & newSuffix ¬
& ".indd" as string
This takes separates the file’s name from its extension, creates a new suffix by incrementing the last character (coerced to a number) of that name by 1, and then combines the lot to form a full file name that you can then use in the save command.
The key is breaking apart the original file name, then performing operations on the parts.
Now, this currently has a few limitations: any suffix other than a single digit makes things more complicated (though not impossible), and assumes that anyone running the script has “Show all filename extensions” enabled in the Finder’s preferences (this can be worked around, though).
Wrapping everything up gives us this:
tell application "Adobe InDesign CS5.5"
set origName to the name of document 1 as string
set thePoint to the offset of "." in origName
set firstPart to (characters 1 through (thePoint - 1) of origName) as string
set fpLength to the length of firstPart
set newSuffix to ((the last character of firstPart) as number) + 1
set newName to (characters 1 through (fpLength - 1) of firstPart) ¬
& newSuffix & ".indd" as string
save document 1 to ("your:path:here:" & newName)
end tell
If you could provide some more information about the suffixes you’d intend to use I’d be happy to update my answer.
InDesign documents have 3 properties that could interests you:
name : "xxx_xxx_M6.indd"
file path : file "Macintosh HD:sourceFolder:"
full name : file "Macintosh HD:sourceFolder:xxx_xxx_M6.indd"
So, to save (& close) the open file on the desktop, with same name, you could do this :
tell application "Adobe InDesign CS5.5"
save document 1 to "users:xxx:Desktop:" & name of document 1
close document 1
end tell

How do I diagnose a compiled Applescript that just quits at startup?

I wrote two applescripts so that my wife could launch mt-daapd and shut it down easily. They work fine in the Script Editor app but when I compile them into stand-alone apps, the apps work the first time I test them. Then they embarrass me as I proudly show them off to my wife. I see the "open" animation and then they just sit there. I've created other stand-alone apps before and this hasn't happened.
I tried changing the app type to a bundle (same problem). I even tried attaching to the executable via gdb to see if I could break on something magic to tell me what was going on. I looked in the Console for some information. Nothing was ther The scripts laughed in my face.
How do I fix this problem?
I've included one of the scripts below; the second is pretty much the same. I'm running 10.5.8.
property userpassword : ""
if userpassword is "" then
display dialog "Please enter your user password:" default answer "" with hidden answer
set userpassword to text returned of result
set the_password to "Undefined"
repeat until the_password is "Correct"
try
do shell script "/opt/local/sbin/mt-daapd -c /etc/mt-daapd.conf" password userpassword with administrator privileges
set the_password to "Correct"
on error
display dialog "Sorry, the password entered was not correct. Please try again:" default answer "" with hidden answer
set userpassword to text returned of result
end try
end repeat
if the_password is "Correct" then
display dialog "Your music is being shared!" buttons {"Done"} default button "Done"
end if
end if
I'm not sure how this is happening but the script is saving the value of userpassword between calls so once it has been set to whatever value, it retains that value and just exits the program. I discovered this after looking at how I created my other stand alone apps.
properties in applescripts are not fixed, they're like the properties of any other object. You can change them at run time, or evn from another script. so if your script1 was
property potato: "potayto"
say potato
and you ran another script
set potato of script1 to "potahto"
then running script1 again would make your computer say "potahto".
Properties can be useful ways of storing preferences in scripts.
Just delete the first if statement, it's redundant anyway. Check if the password is correct, rather than if it is empty.
thus:
property userpassword :""
set the_password to "Undefined"
repeat until the_password is "Correct"
try
do shell script "/opt/local/sbin/mt-daapd -c /etc/mt-daapd.conf" password userpassword with administrator privileges
set the_password to "Correct"
on error
display dialog "Sorry, the password was not correct. Please try again:" default answer "" with hidden answer
set userpassword to text returned of result
end try
end repeat
if the_password is "Correct" then
display dialog "Your music is being shared!" buttons {"Done"} default button "Done"
end if

Resources