Following script finds and saves all MacScripter topics related to indicated by the user application.
It works, but I have a suspicion that it can be improved.
It would be interesting to hear rational suggestions for improving the script from users of our site.
For example, I could not figure out how to determine the number of pages found through a page search (1,2,3,4 … NEXT). I solved this problem clumsily by simply loading the next possible page at random and checking that its links hadn’t been found before.
Well, other suggestions are also interesting to hear.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
property thePath : missing value
property login : "KniazidisR" -- set here your login name
property |password| : "myPassword" -- set here your password
property searchTopicsForApplication : "BBEdit" -- set here the application name
-- make folders (if need)
set desktopFolderHFS to (path to desktop folder) as text
tell application "Finder" to if not (exists folder (desktopFolderHFS & "MacScripter Topics:")) then make new folder at folder desktopFolderHFS with properties {name:"MacScripter Topics"}
set macscripterFolder to alias (desktopFolderHFS & "MacScripter Topics:")
set destinationFolderHFS to (macscripterFolder as text) & searchTopicsForApplication
tell application "Finder" to if not (exists folder destinationFolderHFS) then make new folder at macscripterFolder with properties {name:searchTopicsForApplication}
set destinationFolderPath to POSIX path of (alias destinationFolderHFS)
-- we will perform search for following expression
set searchExpression to "tell application \"" & searchTopicsForApplication & "\""
-- login to MacScripter
my loginToMacScripter(login, |password|)
my waitSafariWebPageLoading(10) -- wait maximum 10 seconds
-- search MacScripter Topics by indicated serach expression (by keywords)
set searchExpression to my encodeSearchExpression(searchExpression)
-- get URL indexes of topics from every page
set URLIndexes to my getURLIndexes(searchExpression)
-- save topics founded for indicated application as webarchives
my saveTopicsAsWebarchive(destinationFolderPath, URLIndexes)
------------------------------------------- HANDLERS --------------------------------------------
on archivePage:thePageURL toPath:aPath
set my thePath to aPath -- store path for use later
my performSelectorOnMainThread:"setUpWebViewForPage:" withObject:thePageURL waitUntilDone:true
end archivePage:toPath:
on setUpWebViewForPage:thePageURL
-- needs to be done on the main thread
-- make a WebView
set theView to current application's WebView's alloc()'s initWithFrame:{origin:{x:0, y:0}, |size|:{width:100, height:100}}
-- tell it to call delegate methods on me
theView's setFrameLoadDelegate:me
-- load the page
theView's setMainFrameURL:thePageURL
end setUpWebViewForPage:
-- called when the WebView loads a frame
on WebView:aWebView didFinishLoadForFrame:webFrame
-- the main frame is our interest
if webFrame = aWebView's mainFrame() then
-- get the data and write it to file
set theArchiveData to webFrame's dataSource()'s webArchive()'s |data|()
theArchiveData's writeToFile:thePath atomically:true
-- display notification "The webarchive was saved"
end if
end WebView:didFinishLoadForFrame:
on WebView:WebView didFailLoadWithError:theError forFrame:webFrame
-- got an error, bail
WebView's stopLoading:me
display notification "The webarchive was not saved"
end WebView:didFailLoadWithError:forFrame:
on stringOffsetBeginOrEnd:theString withOffset:theChar withOption:theOption
set aString to theString
set x to the offset of theChar in aString
if (theOption = "begin") then
return (text from x to 1 of aString)
else if (theOption = "end") then
return (text from (x + 2) to -1 of aString)
else
error number -128
end if
end stringOffsetBeginOrEnd:withOffset:withOption:
on saveTopicsAsWebarchive(destinationFolderPath, URLIndexes)
repeat with URLIndex in URLIndexes
-- open location
tell application "Safari" to make new document with properties ¬
{URL:("https://www.macscripter.net/viewtopic.php?id=" & URLIndex)}
set isLoaded to my waitSafariWebPageLoading(10) -- check page full loading
if isLoaded then
if document "Info / MacScripter" of application "Safari" exists then
-- badTopic URL : "The link you followed is incorrect or outdated."
close document "Info / MacScripter" of application "Safari" saving no
else
-- Tell Safari to get the name and URL of document 1
tell application "Safari" to tell document 1 to set {theName, theURL} to {name, URL}
-- Correct the name string.
set theName to (my stringOffsetBeginOrEnd:theName withOffset:"/" withOption:"end")
-- Output path of the file.
set thePath to destinationFolderPath & URLIndex & ". " & theName & " .webarchive"
-- Run the handler.
(my archivePage:theURL toPath:thePath)
-- Following 2 lines is optional. Remove them to speed up the process
display notification "Webpage saved"
delay 7 -- this is to to allow switching notification
end if
-- close current document
tell application "Safari" to close documents saving no
end if
end repeat
end saveTopicsAsWebarchive
on getURLIndexes(searchExpression)
set URLIndexes to {}
repeat with pageNumber from 1 to 1000
set searchURL to "https://macscripter.net/search.php?action=search&keywords=" & searchExpression & "&author=&forum=-1&sort_by=5&sort_dir=DESC&show_as=topics&search=Submit&p=" & pageNumber
tell application "Safari" to open location (searchURL)
my waitSafariWebPageLoading(10) -- wait maximum 10 seconds
set pageURLIndexes to my getPageURLIndexes()
if URLIndexes contains pageURLIndexes then exit repeat
set URLIndexes to URLIndexes & pageURLIndexes
tell application "Safari" to close front window
end repeat
return URLIndexes
end getURLIndexes
on getPageURLIndexes()
set pageURLIndexes to {}
set i to -1
set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"viewtopic.php?id=", quote}}
repeat
try
set i to i + 1
tell application "Safari" to set end of pageURLIndexes to text item 3 of (do JavaScript "document.getElementsByClassName('tclcon')[" & i & "].innerHTML" in document 1)
on error
exit repeat
end try
end repeat
set AppleScript's text item delimiters to ATID
return pageURLIndexes
end getPageURLIndexes
on loginToMacScripter(login, |password|)
tell application "Safari"
activate
open location ("http://macscripter.net/login.php")
my waitSafariWebPageLoading(10) -- wait maximum 10 seconds
do JavaScript "login.req_username.value = \"" & login & "\"" in document 1
do JavaScript "login.req_password.value = \"" & |password| & "\"" in document 1
do JavaScript "login.login.click()" in document 1
end tell
end loginToMacScripter
on encodeSearchExpression(searchExpression)
set ATID to AppleScript's text item delimiters
set AppleScript's text item delimiters to space
set searchExpression to text items of searchExpression
set AppleScript's text item delimiters to "+"
set searchExpression to searchExpression as text
set AppleScript's text item delimiters to "\""
set searchExpression to text items of searchExpression
set AppleScript's text item delimiters to "%22"
set searchExpression to searchExpression as text
set AppleScript's text item delimiters to ATID
return searchExpression
end encodeSearchExpression
on waitSafariWebPageLoading(loadingWaitMaximumSeconds as integer)
set lineChangingChars to {linefeed, return, character id 11, character id 12, character id 133, character id 8232, character id 8233}
set {ATID, htmlEnding} to {AppleScript's text item delimiters, ""}
tell application "Safari"
repeat 100 * loadingWaitMaximumSeconds times
delay 0.1
set AppleScript's text item delimiters to {"<", ">"}
try
copy text item -2 of (get source of front document) to htmlEnding
end try
set AppleScript's text item delimiters to lineChangingChars
set htmlEnding to text items of htmlEnding
set AppleScript's text item delimiters to ""
set htmlEnding to "<" & htmlEnding & ">"
if htmlEnding is "</html>" then exit repeat
end repeat
end tell
set AppleScript's text item delimiters to ATID
if htmlEnding is "</html>" then return true
display notification "The webpage loading failed"
return false
end waitSafariWebPageLoading