I'm working on a project that involves using Applescript to make a list of open URLs within the users Google Chrome Browser, in order to save them for when I eventually want to re-open Chrome. Finding that I needed to have a way to determine which tabs were present in which windows, I decided to try and make a nested list in Applescript, in which each window is it's own sublist of tab URLs, and then return it in the variable declared before the subshell.
The way I'm doing this is via the following code
tabs=$(/usr/bin/osascript << EOT
tell application "Google Chrome"
# save a variable to the number of windows open
set windowCount to number of windows
set myWindows to {}
repeat with x from 1 to windowCount
# count the tabs in the window we are iterated upon
set tabcount to number of tabs in window x
# this list will hold the URLs, delimited by commas
set myURLs to {}
# secondary loop, this time iterating tabs
repeat with y from 1 to tabcount
# grab URL from current tab
set tabURL to URL of tab y of window x
# append URL to end of list
copy tabURL to the end of myURLs
end repeat
# this means our end result will be a list of lists
# containing the URLs of all the tabs of all the windows
copy myURLs to the end of myWindows
end repeat
return myWindows
end tell
EOT)
The issue I'm running into is that, although Applescript is building the nested list properly, i.e.
{{"https://stackoverflow.com/questions/ask"}, {"https://twitter.com", "https://facebook.com"}}
Bash seems to flatten the list when I reference $tabs later into something like
https://stackoverflow.com/questions/ask, https://twitter.com, https://facebook.com
which leads me to believe Applescript and Bash aren't getting along when passing complex variables. Is this the case and is Bash not able to read multi-dimensional lists from Applescript? Or am I simply programming this incorrectly?
Thank you!
Here's a basic, barebones script that contains two handlers: storeURLs() and restoreURLs().
storeURLs() retrieves a nested list of currently-open Chrome tabs (grouped by window) and writes their URLs out to file. restoreURLs() reads this file and opens the URLs in Chrome, restoring the arrangement of tabs and windows.
Running the script in its current form will store the list of URLs in the file ~/.chrometabs. To get the script to restore the saved URLs, comment out the first occurrence of "storeURLs()" (line 6) by prepending it with two hyphens (--) or a hash (#); and uncomment the line below that, by deleting the two hyphens before "restoreURLs()".
property home : system attribute "HOME"
property file : home & "/.chrometabs" --> /Users/%YOU%/.chrometabs
on run
storeURLs()
--restoreURLs()
end run
on storeURLs()
close access (open for access my file)
tell application id "com.google.chrome" to set ¬
URLs to the URL of every tab in every window
write the URLs to my file
return the URLs
end storeURLs
to restoreURLs()
close access (open for access my file)
if (get eof of my file) = 0 then return false
set URLs to read my file as list
tell application id "com.google.chrome"
repeat with URLgroup in the reverse of URLs
tell (make new window)
set the active tab's URL to the URLgroup's 1st item
repeat with |URL| in the rest of the URLgroup
make new tab with properties {URL:|URL|}
end repeat
end tell
end repeat
activate
end tell
return the URLs
end restoreURLs
The script doesn't contain anything more than the most basic error-prevention, and as such, will benefit from additional error-handling. It was written and tested using AppleScript version 2.5 in macOS 10.12.6. The only potential problem I anticipate in more recent versions of macOS (Mojave, Catalina) would be security bollocks that could prevent the script creating and/or writing to the file path ~/.chrometabs, either due to its location, or due to the leading "." in the file name which denotes an invisible file in macOS.
Related
I work in media production at a university, we work on Mac systems, but our servers are windows based.
Illegal characters & long file names are causing us problems when transferring our production files to the server.
To prevent file transfers failing & being sent to a holding pen in our DAM system i'm looking to create a simple Automator App that can be used by the production team to do the following;
Accept source folder as input for the app.
Scan contents & replace the following characters ()\/[]"*?<>|+ with an underscore.
Scan contents & for file names longer than 100 characters
Log / report on the affected files for our producers to amend.
Within Automator I have had success with replacing the illegal characters using a find & replace rule for each, but I'm not sure of the apple script that would be required to check the file name lengths & reporting all changes.
I'll be eternally grateful if anyone would be able to suggest a route forwards!
Obviously, I have no clue what you might be passing along, nor how you might be replacing the text in filenames, nor exactly what you would like to report, as you don't really provide any of those details. However, here is a straightforward way to test for filenames longer than a given length within automator.
To provide the initial file list to test, I begin with three actions:
Get Selected Finder Items
Get Folder Contents ('repeat for each subfolder found' is checked)
Filter Finder Items ('kind is document')
This will pass along a list of alias file objects to the fourth 'run applescript' action, as input.
on run {input, parameters}
set fList to input
set nList to {} -- becomes list of filenames
set cList to {} -- becomes list of filename lengths
tell application "Finder"
repeat with ff in fList -- list of file aliases
set nn to name of ff
set end of nList to nn
set end of cList to length of nn
end repeat
end tell
set longList to {}
repeat with cc from 1 to length of cList
if item cc of cList is greater than 100 then
set end of longList to item cc of nList -- names with more than 100 characters
end if
end repeat
return longList
end run
This should be run when a folder is selected in the Finder.
Essentially, what this does is take the input (i.e. list of file aliases) and create corresponding lists of filenames and filename lengths. The script then loops through the list of lengths looking for items > 100 and and returns a list of matching filenames. If instead, you set end of longList… to items from fList then it will return a list of file aliases.
If this isn't what you're looking for, please advise. The above works under Sierra.
I currently have an AppleScript that reads a hardcoded plain text file, which contains a long list, into a variable, which is then read into another variable as paragraphs. The script works very well for my purposes. This is basically what I am using:
set fileHandler to (read POSIX file "/path/to/my/file.txt")
set newList to paragraphs of fileHandler
repeat with i in newList
# do stuff
end repeat
The omitted script opens a Safari location, invokes JavaScript using i as a variable on that page, writes the result to a new plain text file, closes the Safari window, then repeats. It continues until it reaches the end of the list, then outside the repeat runs a do shell script that cleans up the new text file a bit.
The trouble is that every time I want to run the script using a different list, I have to open the hardcoded file and paste in the list. I'd rather just drop any .txt file on to an Automator application that wraps around my current script.
I've tried to use "Combine Text Files" and I feel like I get pretty close but I can't quite pass in the contents of the .txt file the way I'd like. I can't pass it in the same, unless I am doing something wrong with it. And "Get Value of Variable"/"Set Value of Variable" add on an extra "Text" item to my list, which I don't understand.
Ideally, I'd like to do something like this:
set fileHandler to (read POSIX file arg) -- the dropped text file
set newList to paragraphs of fileHandler
repeat with i in newList
# do stuff
end repeat
...but it doesn't work that way, unfortunately.
I'd really rather not reinvent a whole new script if I can help it. Any suggestions would be great. Thanks.
Automator is actually not needed. Save this code in Script Editor as application (bundle) and drop files onto it.
on open theFiles
repeat with aFile in theFiles
set newList to paragraphs of (read aFile)
repeat with i in newList
# do stuff
end repeat
end repeat
end open
thanks in advance for your help.
New to Applescript.
Trying to open in Preview all files in folder and save them.
The problem is that saving pops up a dialog half the time, which requires me to sit there hitting enter.
Code:
tell application "Finder"
set fl to files of folder POSIX file "/Users/myname/Desktop/myfolder/" as alias list
end tell
repeat with f in fl
tell application "Preview"
activate
open f
# Trying to save before the window has appeared will fail.
# Note: - This assumes that NO window was initially open.
# - The code should be made more robust to eventually time out.
repeat until (count of windows) > 0
delay 0.3
end repeat
save front document
close front document
end tell
end repeat
Thank you for the help
I made several PDF files and download from different sites and I get sample of version 1.3, 1.4, 1.5, 1.7, ..but no 1.6 ! For all of them no issue.
Anyway, because I have not been able to reproduce what you have, I took different approach.
1) I have added at top of the script, a list of encoding/version list which may required special treatment (like hit return key). You can of course amend these 2 lists to manage other cases you may have.
2) I changed your script to allow the script to get encoding and version values of the pdf. This is done by using spotlight data base via shell command 'mdls'. I use it 2 times to get version and encoding characteristics. The shell command returns characters before and after the value we want to get, so I use text x thru Y to extract the encoding and the version itself.
3) if PDF version/encoding are in the list predefined which requires special treatment, then I set OKReturn to true.
4) Just after the save instruction, the script now test if OKReturn is true. then I ask the script to hit return key for you. you may have to adjust this part, for instance, it could be not only 1 return, but 2 or something else. this is something I have not been able to test, because all my pdf are working. please keep in mind that because I simulate return key, you should not use the keyboard during the script run.
based on my test, I don't think the encoding is the blocking criteria. I think the version 1.6 is.Here is the script. It includes comment to make you able to adjust it:
set CodingReturn to {"Mac OS X 10.7.3 Quartz PDFContext"}
set VersionReturn to {"1.6"}
set myFolder to choose folder
tell application "Finder"
set fl to files of myFolder as alias list
end tell
repeat with f in fl
set FVersion to do shell script "mdls -name kMDItemVersion " & quoted form of POSIX path of f
set FEncoding to do shell script "mdls -name kMDItemEncodingApplications " & quoted form of POSIX path of f
if (length of FVersion) > 21 then set FVersion to text 19 thru -2 of FVersion -- extract only version number
if (length of FEncoding) > 42 then set FEncoding to text 38 thru -4 of FEncoding -- extract only the coding
set OKReturn to ((FVersion is in VersionReturn) and (FEncoding is in CodingReturn)) -- special treatment true/false
tell application "Preview"
activate
open f
repeat until (count of windows) > 0
delay 0.3
end repeat
save front document
if OKReturn then -- we need special key to be pressed
tell application "System Events" to keystroke return
end if
close front document
end tell
end repeat
I would be very interested to get your feedback about this version.
To save without the "save as" dialog popping up, add "in f". Here "f" was the filename. You could also put in a different path.
save front document in f
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.
I was wondering how to return just the file extension from a string. I've tried the 'set variable to name extension of...' detailed in this question, but that only seems to work for recognized extensions. The idea is to sort files with the extension '.meta' into their own collection.
What I have now looks like
tell application "Finder'
set everyName to name of every item in entire contents of this_folder
end tell
set metaFiles to {}
repeat with n from 1 to count of everyName
set currentName to item n of everyName
set currentExt to last word of currentName --this assignment fails
if currentExt is "meta" then
set end of metaFiles to currentExt
end if
end repeat
I'm brand new to applescript so I appreciate any and all help/direction. Thanks!
Edit: Hacky Solution
I solved this by using the split function described here to break up the filename after every period. I grabbed the last string, made sure it wasn't the same as the first string in case there were no period characters, and then stored the corresponding filename.
The name includes the file extension, whether the Finder recognizes it or not. So just sort on the name like this...
tell application "Finder"
set metaFiles to (every item in entire contents of this_folder whose name ends with "meta") as alias list
end tell
If you aren't getting a name extension, make sure there actually is one and that you aren't looking at the end of the name. If you are going to be moving files around, you will also need to get the path, and not just the name. I don't think that making a list of your extensions is what you are going for, either - several different characters are used for word boundaries, but a period isn't one of them.
Why not just ask Finder for your file items?
tell application "Finder"
set metaFiles to (every item in entire contents of this_folder whose name extension is "meta") as alias list
end tell