OK so I answer my own question.
It is possible to do what I wanted, although I did not find a satisfactory solution.
The short answer is: I could find no way to use applescript with the direct manipulation of the graphical interface (eg. clicks). I did find a way by using key alternatives. To do the exact bit of work that I needed, the following sequence will do:
-- after opening the document in Numbers, open the share window:
tell application "System Events"
tell process "Numbers"
delay 1
tell menu bar 1
tell menu bar item "Share"
tell menu "Share"
delay 1
click menu item "Share Link via iCloud…"
end tell
end tell
end tell
end tell
-- once the share dropdown window is open, use the following key combination
tell application "System Events"
--add tabs
delay 1
key code 48
delay 1
key code 48
delay 1
-- use arrows to move to the right part of the 'Share' window
key code 124
delay 1
key code 124
delay 3
-- click return
key code 36
delay 8
-- save the file and close it
keystroke "s" using {command down}
delay 4
keystroke "w" using {command down}
The long answer is: it is a pain in the neck for a series of reasons.
First, when you create a Numbers file, it is a simple file. However, when it is shared, or when it is being saved in iCloud, it becomes a package. Applescript sees packages as folders, so you have to do some check before doing anything as to whether what you are dealing with is a folder or a package. Then you can go on to the sharing operations.
Now, I found NO principle way to intercept when exactly a file becomes a package. That is, when you open a Numbers file and ask it to be shared, you will see that Numbers gives you a "preparing the document to share" message. This, I found, is when the file is transformed into a package. There is a property that one can use in order to check if a given path corresponds to a package or a single file: one could loop while (package folder of the item_info is false) and then continue, but this property becomes set as true well before Numbers has finished its own "preparing the document to share" work. So I could only guess when I can continue and go to the sharing part of the script. I put a rough delay of 30 seconds when a file is not yet a package, which should give plenty of time for Numbers to finish its transformations of the file to share:
if (this_package_folder is false) and (this_extension is in the extension_list) then
delay 30
end if
Second, you must be on a good network, so that all operations related to Numbers in iCloud can be done smoothly -- otherwise, iCloud will give you error messages that will block the execution of the script
Third, you have to take care of the .DS_Store files and other files that may be inside the folder where you put your Numbers documents to be shared.
Fourth, if you want to identify where the iCloud folder with the documents to be shared is, from inside AppleScript you won't see it as you see it from the finder (i.e., in the iCloud Drive), but you will have to look for it in /yourUser/Library/Mobile Documents/iCloud Drive/yourfolder.
With all these caveats, here is the script that I am using now. In my system, it works. It assumes several things:
- there is a folder in your iCloud where your Numbers documents are
- you have a file where you want to save the paths of the files that will be shared, so that you know the paths that you have to communicate to those with who you want to share your files. In my case, I use a Pages document.
- the files to be shared ARE NOT already shared. Otherwise, the script will give errors.
- you don't care about errors and style. The script has no error checks. I am not a programmer.
The script will ask you to first identify the folder with the documents to be shared, then the Pages file where you want to save the paths of the shared documents, and then will open the documents to be shared one by one, will share them, will save them, will copy their path to the Pages document that you selected, and finally will quit Numbers and Pages. Give plenty of time for the script to execute and don't interfere with it. Notice that when you open each Numbers file, you can modify the script so that you insert specific operations that you want to be done on your files, always with the same technique (for example, in my case I need to find a cell, find a value, copy it somewhere else and save it. This part of the procedure is not in the script below. You can add whatever your fantasy leads you to invent as contorted and complicated operations).
Now, if somebody finds a way to REVERSE the operation, unsharing the shared files, and especially, a way to tell if a file is ALREADY shared or not, so that the script acquires generality....
I paste the script below.
-- Beginning of the script
global f
property extension_list : {"numbers"}
tell application "Finder"
set source_folder to choose folder with prompt "Please select directory."
set posixSource_Folder to POSIX path of source_folder
tell application "System Events"
set these_items to POSIX path of disk items of folder posixSource_Folder
end tell
my createList(these_items)
end tell
on createList(these_items)
tell application "System Events"
tell application "Finder"
set f to (choose file with prompt "Choose a file where to store the paths")
end tell
end tell
set posixF to POSIX path of f
delay 2
tell application "Finder" to open file f
delay 1
repeat with i from 1 to the count of these_items
set this_item to item i of these_items
set the item_info to info for this_item
set this_extension to the name extension of item_info
if folder of the item_info is true and (package folder of the item_info is false) and (this_extension is not in the extension_list) then
process_folder(this_item)
else
if (this_extension is in the extension_list) then
process_item(this_item)
end if
end if
end repeat
close_files()
end createList
-- this sub-routine processes folders
on process_folder(this_folder)
-- set these_items to list folder this_folder without invisibles
set posix_this_folder to POSIX path of this_folder
tell application "System Events"
set these_items to POSIX path of disk items of folder posix_this_folder
end tell
repeat with i from 1 to the count of these_items
--set this_item to alias ((this_folder as Unicode text) & (item i of these_items))
set the item_info to info for this_item
set this_extension to the name extension of item_info
--if folder of the item_info is true and (this_extension is not in the extension_list) then
if folder of the item_info is true and (package folder of the item_info is false) and (this_extension is not in the extension_list) then
process_folder(this_item)
else
if (package folder of the item_info is true) and (this_extension is in the extension_list) and (alias of the item_info is false) then
process_item(this_item)
end if
end if
end repeat
end process_folder
-- this sub-routine processes files
on process_item(this_item)
set the item_info to info for this_item
set this_extension to the name extension of item_info
set this_package_folder to the package folder of item_info
set Posix_Item to POSIX path of this_item
set Posix_File to POSIX file Posix_Item
delay 1
--opening the Numbers file
tell application "Finder" to open Posix_File
delay 3
-- going to Numbers and making the file shared
tell application "System Events"
tell process "Numbers"
delay 1
tell menu bar 1
tell menu bar item "Share"
tell menu "Share"
delay 1
click menu item "Share Link via iCloud…"
end tell
end tell
end tell
end tell
-- extra time allowed for non packages
delay 3
end tell
if (this_package_folder is false) and (this_extension is in the extension_list) then
delay 30
end if
--tabs
tell application "System Events"
delay 1
key code 48
delay 1
key code 48
delay 1
-- arrows
key code 124
delay 1
key code 124
delay 3
-- returns
key code 36
-- leave some time for Numbers to actually share the file. Maybe you need more time for your system.
delay 8
-- saving and closing documents
keystroke "s" using {command down}
delay 4
keystroke "w" using {command down}
-- Now returning to the file where the paths have to be pasted
tell application "Finder" to open file f
delay 2
-- pasting the local Unix path
keystroke "v" using {command down}
delay 1
key code 48
delay 2
-- pasting the iCloud remote path of the shared document
set the clipboard to Posix_Item
delay 1
keystroke "v" using {command down}
delay 1
key code 48
key code 36
delay 1
keystroke "s" using {command down}
end tell
end process_item
--closing files
on close_files()
tell application "System Events"
tell process "Numbers"
tell menu bar 1
tell menu bar item "Numbers"
tell menu "Numbers"
delay 1
click menu item "Quit Numbers"
end tell
end tell
end tell
end tell
tell application "Finder" to open file f
delay 2
keystroke "q" using {command down}
delay 1
end tell
end close_files
-- end of the script
Using Automator, in macOS Sierra 10.12.5, I created a Folder Action with a single Run AppleScript action, using the AppleScript code below, and set it to run on my Downloads folder. (It has also been tested and works on OS X 10.8.5 and OSX 10.11.6.)
- Open Automator and select File > New, then Folder Action.
- Add a Run AppleScript action, replacing the default code with the code below.
- Modify the
set theBlackWhiteList to POSIX path of ...
line of code, accordingly as necessary.
- Set the Folder Action receives files and folders added to Choose folder list box to your Downloads folder.
- Before saving the Folder Action, create the plain text data file that will be used by this Folder Action.
- It's not absolutely necessary to do it before, however, if you are going to save it in Downloads, I would create the file first.
- Save the Automator Folder Action workflow.
Read the comments, included with the code, for what's necessary to use this code in the Folder Action.
To test the Folder Action, open Terminal and cd Downloads
, then create the test file with,
touch 'Youtube_MyVideofile_(1080p_30fps_H264-128kbit_AAC).mp4'
, which will create a zero length file that will be processed by the Folder Action and be renamed to MyVideofile 1080p H264.mp4
as shown in Downloads in Finder or Terminal with: ls -l My*.mp4
AppleScript code:
-- #
-- # The AppleScript code of this Folder Action requires a data file, which is laid out as follows:
-- #
-- # Lines 1 and 3 state what are on lines 2 and 4 respectively. (These lines are just reminders.)
-- #
-- # Line 2 must start with a single space character ' ', followed by the comma delimiter ','!
-- # Line 2 must also not contain an underscore character '_' as it's used as a 'text item delimiter',
-- # and all of them will be removed and replaced with a single space, as appropriate, in the last
-- # part of the processing to form the final filename.
-- #
-- # This is used as part of the overall logic applied to creating the finished filename, so as to
-- # only have a single space character between words of the filename, while ensuring the finished
-- # filename does not start with nor have directly before the filename extension, a space character.
-- #
-- # Line 2 is a list of strings that will be removed from the filename. (The Black List.)
-- # Line 4 is a list of filename extensions of the file types that will be processed. (The White List.)
-- #
-- # Modify lines 2 and 4 as appropriate, while leaving the single space character at the start of line 2,
-- # and do not include an underscore character in Line 2.
-- #
-- # Example contents of the plain text data file:
-- #
-- # # Do Not Remove This Line!: The next line contains a comma-delimited list of strings to be removed:
-- # ,Youtube,30fps,128kbit,-,AAC,(,)
-- # # Do Not Remove This Line!: The next line contains a comma-delimited list of file extensions to process:
-- # mp4,mkv,avi,flv,flac
-- # For the purposes of testing this script, the name of the data file used is
-- # "FileNameExtensionBlackWhiteCleanupList.txt", and is in the User's Downloads folder.
-- # Obviously you can name it whatever you want and place it where appropriate access exists.
-- # Modify the 'set theBlackWhiteList to POSIX path of ...' line of code, accordingly as necessary.
on run {input, parameters}
try
set theBlackWhiteList to POSIX path of (path to downloads folder) & "FileNameExtensionBlackWhiteCleanupList.txt"
-- # Make sure the data file exists and set its contents to the target variables.
tell application "System Events"
if (exists file theBlackWhiteList) then
tell current application
set theBlackWhiteList to (read theBlackWhiteList)
set AppleScript's text item delimiters to {","}
set theStringsToRemoveList to text items of paragraph 2 of theBlackWhiteList as list
set theFileExtensionsList to text items of paragraph 4 of theBlackWhiteList as list
set AppleScript's text item delimiters to {}
end tell
else
tell current application
activate
display dialog "The required file, " & quoted form of theBlackWhiteList & ", is missing!" & ¬
linefeed & linefeed & "Replace the missing file from backup." buttons {"OK"} ¬
default button 1 with title "File Not Found" with icon 0 -- (icon stop)
return
end tell
end if
end tell
-- # Process the target file(s) added to the target folder, that have the target filename extensions.
tell application "Finder"
set theFileList to input
repeat with thisFile in theFileList
set theFileName to name of thisFile
set theOriginalFileName to theFileName
-- # Get the filename extension of thisfile.
set AppleScript's text item delimiters to {"."}
set thisFileExtension to last text item of theFileName as string
-- # Only process if thisFileExtension is in theFileExtensionsList.
if theFileExtensionsList contains thisFileExtension then
repeat with i from 1 to count of theStringsToRemoveList
set AppleScript's text item delimiters to item i of theStringsToRemoveList
set theTextItems to text items of theFileName
set AppleScript's text item delimiters to {"_"}
set theFileName to theTextItems as string
set AppleScript's text item delimiters to {}
end repeat
-- #
-- # Using the example filename in the OP, 'Youtube_MyVideofile_(1080p_30fps_H264-128kbit_AAC).mp4',
-- # at this point in the processing it would be, '__MyVideofile__1080p___H264_____.mp4', and while one
-- # probably could continue to use AppleScript 'text items' and 'text item delimiters', nonetheless I can do
-- # it easier using 'sed' to finish getting the final filename. This is also part of the reason I started the
-- # 'theStringsToRemoveList' with a single space character and do not allow an underscore character in Line 2.
-- #
tell current application
set theFileName to (do shell script "printf " & quoted form of theFileName & " | sed -E -e 's/[_]{2,}/_/g' -e 's/^_//' -e 's/_\\./\\./g' -e 's/_/ /g'")
end tell
-- # Only change the filename if it has actually changed by the processing above.
-- # There's no sense in telling Finder to name a file the same name it already is.
if theFileName is not equal to theOriginalFileName then
try
set the name of thisFile to theFileName
end try
end if
-- # At this point the final filename, using the example filename, would be 'MyVideofile 1080p H264.mp4'.
-- # This assumes this filename didn't already exist and why the 'do shell script' command is within a 'try'
-- # statement. Additional coding and logic could be applied to increment the filename if it already existed.
end if
end repeat
set AppleScript's text item delimiters to {}
end tell
on error eStr number eNum
set AppleScript's text item delimiters to {}
display dialog eStr & " number " & eNum buttons {"OK"} default button 1 with icon caution
return
end try
end run
Example contents of the plain text data file used by the Folder Action:
# Do Not Remove This Line!: The next line contains a comma-delimited list of strings to be removed:
,Youtube,30fps,128kbit,-,AAC,(,)
# Do Not Remove This Line!: The next line contains a comma-delimited list of file extensions to process:
mp4,mkv,avi,flv,flac
The logic behind the renaming process:
Using the variable theStringsToRemoveList
, which starts with a single space character followed by the comma-delimiter, in conjunction with the underscore character as the text item delimiter
, turns all spaces along with all other strings to be removed, into underscores during the AppleScript's text items
and text items delimiters
portion of the code.
This is done so sed
can be used to replace all concurrent underscore characters with a single underscore character, then remove the leading underscore, if it exists, followed by an underscore preceding the dot before the filename extension, if it exists, and finally all remaining single underscore characters are replaced with a single space character.
set theFileName to (do shell script "printf " & quoted form of theFileName & " | sed -E -e 's/[_]{2,}/_/g' -e 's/^_//' -e 's/_\\./\\./g' -e 's/_/ /g'")
set theFileName to
- The variable theFileName
will contain the output of the do shell script
command.
do shell script "_command_"
- Runs the command in a shell
.
printf " & quoted form of theFileName & " |
- Prints the value of the variable theFileName
, and pipes |
it to the sed
command.
sed -E -e 's/[_]{2,}/_/g' -e 's/^_//' -e 's/_\\./\\./g' -e 's/_/ /g'
sed
- Stream EDitor.
-E
- Interpret regular expressions as extended (modern) regular expressions rather than basic regular expressions (BRE’s). The re_format(7) manual page fully describes both formats.
-e command
- Append the editing commands specified by the command argument to the list of commands.
s/[_]{2,}/_/g
s
- Substitute pattern flag.
[_]{2,}
- Match a single character present in the list, matches the character _
literally (case sensitive).
{2,}
- Quantifier — Matches between 2 and unlimited times, as many times as possible, giving back as needed (greedy).
/_/
- Replaces matched pattern with a single character _
literally (case sensitive).
g
- Global pattern flag g
modifier, matches all occurrences of the pattern, (doesn't return after first match).
s/^_//
^
- Asserts position at start of the string.
_
- Matches the character _
literally (case sensitive).
//
- Replaces the matched pattern with literally nothing.
s/_\\./\\./g
_
- Matches the character _
literally (case sensitive).
\\.
- Matches the character .
literally (case sensitive).
/\\./
- Replaces the matched pattern with the character .
literally (case sensitive).
- Note: The double back-slash
\\
is necessary when use in a do shell script
command, however, from the command line a single back-slash \
would be used to make the character that follows a literal .
character, in this case.
s/_/ /g
- Replaces the character
_
literally, with a character
literally (case sensitive).
Note that the info above is abbreviated in places, however, it should provide a bit of an understanding of what's happening.
On a added note, if you want to also ensure capitalization of each word in the filename, then replace the existing do shell script
command with the do shell script
command below, which has an added awk
command that receives the output from sed
to preform the capitalization. Note that I found this awk
command on the Internet and tested it that it works, however, will not be adding an explanation of how it functions for lack of time.
set theFileName to (do shell script "printf " & quoted form of theFileName & " | sed -E -e 's/[_]{2,}/_/g' -e 's/^_//' -e 's/_\\./\\./g' -e 's/_/ /g' | awk '{for(i=1;i<=NF;i++){ $i=toupper(substr($i,1,1)) substr($i,2) }}1'")
Update to address .
's in the filename, per the comments.
In the plain text data file, on Line 2, add a .,
after the leading space and its comma-delimiter. In other words, the first item in the list on Line 2 is a blank space followed by a comma-delimiter followed by .
followed by a comma-delimiter and so on.
Add the following lines of code after the repeat
loop that directly before the comment starting with -- # Using the example filename in the OP. ...
which is above the tell current application
... do shell script
block of code.
set AppleScript's text item delimiters to {"_" & thisFileExtension}
set theTextItems to text items of theFileName
set AppleScript's text item delimiters to {"_"}
set theFileName to (theTextItems as string) & "." & thisFileExtension
set AppleScript's text item delimiters to {}
By adding the .,
to line 2 in the plain text data file, all .
in the filename are replaced with _
in the original code. Then with the extra lines of code above, it replaces e.g. _mp4
with .mp4
, or .
and whatever the actual filename extension is.
Now when it gets to the do shell script
command there is only the .
for the filename extension and all the underscores are process out of the name as they should.
Obviously the way the original code is coded, underscores cannot be a part of the final filename, and this modification to the original code doesn't change that.
Best Answer
The AppleScript in the linked page queries Spotlight's metadata to get the page count for each PDF document. (Specifically, the
kMDItemNumberOfPages
value.)It's up to applications to provide metadata to Spotlight, and MS Word doesn't provide page numbers to Spotlight.
So you can't change the script easily, and will need another method.