Hello.
I have wanted a script that saved all the tabs in a window for some time now. Well, that isn’t particularily easy to do with just AppleScript. I actually did take the trouble of trying, hard with wget, but it was just too impractical, and the webarchives isn’t that easy to make as good with textutil as with Safari.
Well, thanks for the snippet StefanK, here it is, it has properties that you can set for whether you like it to overwrite pages with the same name in a folder, and if you want it to close the tabs after it has saved it, with some tinkering you may have two scripts, or one according to your taste.
If you have regular files open in your browser, those will be aliased into the folder you want as a destination folder.
I have minimized the UI scripting as much as I could, but it handles overwrites of files presumably the way you want it, with UI scripting. The current configuration is to overwrite tabs. and not to close saved windows.
This is tested, but you can see it has release 1.0.0, I’ll update it asap, if I find any bugs. I hope this is useful for more people than just me.
property tlvl : me
# Release 1.0.1
# © 2012 McUsr and put in Public Domain under GPL 1.0
# Please refer to this post: http://macscripter.net/post.php?tid=30892
property shallClose : false # set this to false if you don't want to close the windows, just saving them
property dontOverWriteSavedTabs : false # set this to true if you don't want to overwrite already saved tabs in the folder
script saveTabsInSafariWindowsToFolder
property parent : AppleScript
property scripttitle : "SafariSaveTabs"
on run
if downloadWindowInFront() then return 0 # activates Safari
local script_cache
set script_cache to my storage's scriptCache()
set saveFolder to POSIX path of (getHFSFolder({theMessage:"Choose or create folder to save Safari-tabs in.", hfsPath:DefaultLocation of script_cache as alias}))
if saveFolder = false then return 0 -- we were obviously mistaken, about what we wanted to do.
my storage's saveParenFolderInScriptCache(saveFolder, script_cache)
tell application "Safari"
tell its window 1
local tabc, oldidx
set tabc to count tabs of it
if not tlvl's shallClose then
set oldidx to index of current tab
tell tab tabc to do JavaScript "self.focus()"
end if
local saveCounter
set saveCounter to 1 -- regulates setting of save folder to only first time in Safari.
repeat while tabc > 0
local theUrl, theIdx, theProtocol, alreadyClosed
set {theUrl, theIdx, alreadyClosed} to {URL of its current tab, index of its current tab, false}
if my isntAduplicateTab(theIdx, it) then
set theProtocol to my urlprotocol(theUrl)
if theProtocol is in {"http", "https"} then
# save it
set saveCounter to my saveCurrentTab(saveFolder, saveCounter)
else if theProtocol is "file" then
# make an alias of it
my makeAliasForAFurl(saveFolder, theUrl)
end if
else
if tlvl's shallClose then
close current tab
set alreadyClosed to true
end if
end if
if not alreadyClosed and tlvl's shallClose then
close current tab of it
set tabc to tabc - 1
else if not tlvl's shallClose then
set tabc to tabc - 1
if tabc > 0 then tell tab tabc to do JavaScript "self.focus()"
end if
end repeat
# move forwards
if not tlvl's shallClose then
tell tab oldidx to do JavaScript "self.focus()"
end if
end tell
end tell
end run
to makeAliasForAFurl(destinationFolder, furl)
local ti, tids, thefilePath
set ti to "file://"
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ti}
set thefilePath to text item 2 of furl
set AppleScript's text item delimiters to tids
set theFile to POSIX file thefilePath as alias
set theFolder to POSIX file destinationFolder
tell application "Finder"
make alias at theFolder to theFile
# I don't care if there was one there from before, as it could equally
# be a file with the same name.
end tell
end makeAliasForAFurl
to saveCurrentTab(destinationFolder, timeNumber)
tell application id "sfri" to activate
tell application "System Events"
set UI elements enabled to true
tell process "Safari"
keystroke "s" using {command down}
tell window 1
repeat until exists sheet 1
delay 0.2
end repeat
tell sheet 1
if timeNumber = 1 then -- We'll set the savepath upon first call
keystroke "g" using {command down, shift down}
repeat until exists sheet 1
delay 0.2
end repeat
tell sheet 1
set value of text field 1 to destinationFolder
click button 1
delay 0.1
end tell
end if
keystroke return
delay 0.2
if exists sheet 1 then -- We are being asked if we want to overwrite already saved tab
if dontOverWriteSavedTabs then
keystroke return # if it was already saved. We don't overwrite it
click button 3
else
keystroke tab
keystroke space # we are to overwrite
end if
else
try
set dummy to focused of sheet 1
on error
# click button 1 of panel of application "Safari"
keystroke return
delay 0.2
if exists sheet 1 then -- We are being asked if we want to overwrite already saved tab
if dontOverWriteSavedTabs then
keystroke return # if it was already saved. We don't overwrite it
click button 3
else
keystroke tab
keystroke space # we are to overwrite
end if
end if
end try
end if
end tell
end tell
end tell
end tell
set timeNumber to timeNumber + 1
return timeNumber
end saveCurrentTab
on downloadWindowInFront()
tell application "Safari"
activate
set tabCount to count tabs of its window 1
if tabCount < 1 then
tell application "SystemUIServer" to activate
activate
return true # Downloads window or somethingelse
end if
end tell
return false
end downloadWindowInFront
on isntAduplicateTab(idxOfCurrentTab, theWin)
using terms from application "Safari"
tell theWin
set curTabname to name of tab idxOfCurrentTab
set curTabUrl to URL of tab idxOfCurrentTab
repeat with i from (idxOfCurrentTab - 1) to 1 by -1
if name of tab i = curTabname and URL of tab i = curTabUrl then return false
end repeat
return true
end tell
end using terms from
end isntAduplicateTab
on getHFSFolder(R) -- Returns hfsPathAsText
-- R : {Amessage:theMessage,hfsPath:aStartPath}
local new_path, failed
set failed to false
tell application "SystemUIServer"
activate
repeat while true
try
set new_path to (choose folder with prompt (theMessage of R) default location (hfsPath of R) without invisibles) as text
on error e number n
if n is -128 then
set failed to true
exit repeat
end if
end try
exit repeat
end repeat
end tell
if failed is true then
return false
else
return new_path
end if
end getHFSFolder
on urlprotocol(anUrl)
# returns the protocol of an Url, i.e. http, https, file, localhost etc.
local tids, theProtocol
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "://"}
set theProtocol to text item 1 of anUrl
set AppleScript's text item delimiters to tids
return theProtocol
end urlprotocol
to parentfolder for aPath
local colons, slashes, origDelims
set {colons, slashes} to {false, false}
if (offset of ":" in aPath) > 0 then set colons to true
if (offset of "/" in aPath) > 0 then set slashes to true
if colons and slashes then
return null
else if colons then
set origDelims to ":"
else if slashes then
set origDelims to "/"
else
return null
end if
local tids
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, origDelims}
if aPath = "/" then
-- we return root when we get root
set AppleScript's text item delimiters to tids
return "/"
end if
local theParentFolder
if text -1 of aPath is in {":", "/"} then
set theParentFolder to text items 1 thru -2 of text 1 thru -2 of aPath
else
set theParentFolder to text items 1 thru -2 of aPath
end if
set theParentFolder to theParentFolder as text
if slashes and theParentFolder = "" then set theParentFolder to "/"
-- sets the root path if we got a folder one level below it
if colons and (":" is not in theParentFolder) then set theParentFolder to theParentFolder & ":"
-- we return volumename, if we are given volumename
set AppleScript's text item delimiters to tids
return theParentFolder
end parentfolder
script storage
property cachespath : ((path to library folder from user domain as text) & "caches:" & "net.mcusr." & scripttitle)
on scriptCache()
local script_cache
try
set script_cache to load script alias (my cachespath)
on error
script newScriptCache
property DefaultLocation : (path to desktop folder as text)
# edit any of those with default values
end script
set script_cache to newScriptCache
end try
return script_cache
end scriptCache
to saveScriptCache(theCache)
store script theCache in my cachespath replacing yes
end saveScriptCache
to saveParenFolderInScriptCache(theFolderToSaveIn, script_cache)
local containingFolder
set containingFolder to (parentfolder of saveTabsInSafariWindowsToFolder for theFolderToSaveIn) & "/"
local theLoc
set theLoc to POSIX file containingFolder as alias
set DefaultLocation of script_cache to theLoc
my saveScriptCache(script_cache)
end saveParenFolderInScriptCache
end script
end script
tell saveTabsInSafariWindowsToFolder to run
property tlvl : me
# Release 1.0.1
# © 2012 McUsr and put in Public Domain under GPL 1.0
# Please refer to this post: http://macscripter.net/post.php?tid=30892
property shallClose : false # set this to false if you don't want to close the windows, just saving them
property dontOverWriteSavedTabs : false # set this to true if you don't want to overwrite already saved tabs in the folder
script saveTabsInSafariWindowsToFolder
property parent : AppleScript
property scripttitle : "SafariSaveTabs"
on run
if downloadWindowInFront() then return 0 # activates Safari
local script_cache
set script_cache to my storage's scriptCache()
set saveFolder to POSIX path of (getHFSFolder({theMessage:"Choose or create folder to save Safari-tabs in.", hfsPath:DefaultLocation of script_cache as alias}))
if saveFolder = false then return 0 -- we were obviously mistaken, about what we wanted to do.
my storage's saveParenFolderInScriptCache(saveFolder, script_cache)
tell application "Safari"
tell its window 1
local tabc, oldidx
set tabc to count tabs of it
if not tlvl's shallClose then
set oldidx to index of current tab
tell tab tabc to do JavaScript "self.focus()"
end if
local saveCounter
set saveCounter to 1 -- regulates setting of save folder to only first time in Safari.
repeat while tabc > 0
local theUrl, theIdx, theProtocol, alreadyClosed
set {theUrl, theIdx, alreadyClosed} to {URL of its current tab, index of its current tab, false}
if my isntAduplicateTab(theIdx, it) then
set theProtocol to my urlprotocol(theUrl)
if theProtocol is in {"http", "https"} then
# save it
set saveCounter to my saveCurrentTab(saveFolder, saveCounter)
else if theProtocol is "file" then
# make an alias of it
my makeAliasForAFurl(saveFolder, theUrl)
end if
else
if tlvl's shallClose then
close current tab
set alreadyClosed to true
end if
end if
if not alreadyClosed and tlvl's shallClose then
close current tab of it
set tabc to tabc - 1
else if not tlvl's shallClose then
set tabc to tabc - 1
if tabc > 0 then tell tab tabc to do JavaScript "self.focus()"
end if
end repeat
# move forwards
if not tlvl's shallClose then
tell tab oldidx to do JavaScript "self.focus()"
end if
end tell
end tell
end run
to makeAliasForAFurl(destinationFolder, furl)
local ti, tids, thefilePath
set ti to "file://"
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ti}
set thefilePath to text item 2 of furl
set AppleScript's text item delimiters to tids
set theFile to POSIX file thefilePath as alias
set theFolder to POSIX file destinationFolder
tell application "Finder"
make alias at theFolder to theFile
# I don't care if there was one there from before, as it could equally
# be a file with the same name.
end tell
end makeAliasForAFurl
to saveCurrentTab(destinationFolder, timeNumber)
tell application id "sfri" to activate
tell application "System Events"
set UI elements enabled to true
tell process "Safari"
keystroke "s" using {command down}
tell window 1
repeat until exists sheet 1
delay 0.2
end repeat
tell sheet 1
if timeNumber = 1 then -- We'll set the savepath upon first call
keystroke "g" using {command down, shift down}
repeat until exists sheet 1
delay 0.2
end repeat
tell sheet 1
set value of text field 1 to destinationFolder
click button 1
delay 0.1
end tell
end if
keystroke return
delay 0.2
if exists sheet 1 then -- We are being asked if we want to overwrite already saved tab
if dontOverWriteSavedTabs then
keystroke return # if it was already saved. We don't overwrite it
click button 3
else
keystroke tab
keystroke space # we are to overwrite
end if
else
try
set dummy to focused of sheet 1
on error
# click button 1 of panel of application "Safari"
keystroke return
delay 0.2
if exists sheet 1 then -- We are being asked if we want to overwrite already saved tab
if dontOverWriteSavedTabs then
keystroke return # if it was already saved. We don't overwrite it
click button 3
else
keystroke tab
keystroke space # we are to overwrite
end if
end if
end try
end if
end tell
end tell
end tell
end tell
set timeNumber to timeNumber + 1
return timeNumber
end saveCurrentTab
on downloadWindowInFront()
tell application "Safari"
activate
set tabCount to count tabs of its window 1
if tabCount < 1 then
tell application "SystemUIServer" to activate
activate
return true # Downloads window or somethingelse
end if
end tell
return false
end downloadWindowInFront
on isntAduplicateTab(idxOfCurrentTab, theWin)
using terms from application "Safari"
tell theWin
set curTabname to name of tab idxOfCurrentTab
set curTabUrl to URL of tab idxOfCurrentTab
repeat with i from (idxOfCurrentTab - 1) to 1 by -1
if name of tab i = curTabname and URL of tab i = curTabUrl then return false
end repeat
return true
end tell
end using terms from
end isntAduplicateTab
on getHFSFolder(R) -- Returns hfsPathAsText
-- R : {Amessage:theMessage,hfsPath:aStartPath}
local new_path, failed
set failed to false
tell application "SystemUIServer"
activate
repeat while true
try
set new_path to (choose folder with prompt (theMessage of R) default location (hfsPath of R) without invisibles) as text
on error e number n
if n is -128 then
set failed to true
exit repeat
end if
end try
exit repeat
end repeat
end tell
if failed is true then
return false
else
return new_path
end if
end getHFSFolder
on urlprotocol(anUrl)
# returns the protocol of an Url, i.e. http, https, file, localhost etc.
local tids, theProtocol
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "://"}
set theProtocol to text item 1 of anUrl
set AppleScript's text item delimiters to tids
return theProtocol
end urlprotocol
to parentfolder for aPath
local colons, slashes, origDelims
set {colons, slashes} to {false, false}
if (offset of ":" in aPath) > 0 then set colons to true
if (offset of "/" in aPath) > 0 then set slashes to true
if colons and slashes then
return null
else if colons then
set origDelims to ":"
else if slashes then
set origDelims to "/"
else
return null
end if
local tids
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, origDelims}
if aPath = "/" then
-- we return root when we get root
set AppleScript's text item delimiters to tids
return "/"
end if
local theParentFolder
if text -1 of aPath is in {":", "/"} then
set theParentFolder to text items 1 thru -2 of text 1 thru -2 of aPath
else
set theParentFolder to text items 1 thru -2 of aPath
end if
set theParentFolder to theParentFolder as text
if slashes and theParentFolder = "" then set theParentFolder to "/"
-- sets the root path if we got a folder one level below it
if colons and (":" is not in theParentFolder) then set theParentFolder to theParentFolder & ":"
-- we return volumename, if we are given volumename
set AppleScript's text item delimiters to tids
return theParentFolder
end parentfolder
script storage
property cachespath : ((path to library folder from user domain as text) & "caches:" & "net.mcusr." & scripttitle)
on scriptCache()
local script_cache
try
set script_cache to load script alias (my cachespath)
on error
script newScriptCache
property DefaultLocation : (path to desktop folder as text)
# edit any of those with default values
end script
set script_cache to newScriptCache
end try
return script_cache
end scriptCache
to saveScriptCache(theCache)
store script theCache in my cachespath replacing yes
end saveScriptCache
to saveParenFolderInScriptCache(theFolderToSaveIn, script_cache)
local containingFolder
set containingFolder to (parentfolder of saveTabsInSafariWindowsToFolder for theFolderToSaveIn) & "/"
local theLoc
set theLoc to POSIX file containingFolder as alias
set DefaultLocation of script_cache to theLoc
my saveScriptCache(script_cache)
end saveParenFolderInScriptCache
end script
end script
tell saveTabsInSafariWindowsToFolder to run