My bad, I should’ve gave you this other version. Since it’s a JXA script you have to either run it via osascript
in Terminal or, as I did in the script below, wrap it in a run script
call so that it works in Script Debugger:
set JXAScript to "webTarget = 'https://www.macscripter.net';
outputLocation = '~/Desktop';
outputDimensions = { width: 1680, height: 1050 };
NSApp = null;
currentApplication = null;
function run(argv) {
ObjC.import('AppKit');
ObjC.import('ApplicationServices');
ObjC.import('CoreGraphics');
ObjC.import('PDFKit');
ObjC.import('Quartz');
ObjC.import('WebKit');
ObjC.import('objc');
currentApplication = Application.currentApplication();
currentApplication.includeStandardAdditions = true;
const targetURL = $.NSURL.URLWithString(webTarget);
const fileName = targetURL.host.js;
const outputContainer = outputLocation.replace('~', currentApplication.pathTo('home folder'));
const outputPath = `${outputContainer}/${fileName}.pdf`;
outputLocation = outputPath;
const outputURL = $.NSURL.fileURLWithPath(outputPath);
const frame = $.NSMakeRect(0, 0, outputDimensions.width, outputDimensions.height);
const webViewConfig = buildWebViewConfig();
const webView = $.WKWebView.alloc.initWithFrameConfiguration(frame, webViewConfig);
const webViewDelegate = registerWebViewDelegate();
webView.navigationDelegate = webViewDelegate;
const request = $.NSMutableURLRequest.requestWithURL(targetURL);
request.setTimeoutInterval(10);
request.setAllowsExpensiveNetworkAccess(true);
request.setValueForHTTPHeaderField('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15', 'User-Agent')
webView.loadRequest(request)
while (webViewDelegate.result.js == undefined) {
runLoop = $.NSRunLoop.currentRunLoop;
today = $.NSDate.dateWithTimeIntervalSinceNow(0.1);
runLoop.runUntilDate(today);
}
const image = imageFromBase64String(webViewDelegate.result);
return createPDFFromImage(image, outputURL);
}
function registerWebViewDelegate() {
const WKNavigationDelegate = $.objc_getProtocol('WKNavigationDelegate')
if (!$['WebViewDelegate']) {
ObjC.registerSubclass({
name: 'WebViewDelegate',
superclass: 'NSObject',
protocols: ['WKNavigationDelegate'],
properties: {
result: 'id',
},
methods: {
'webView:didFinishNavigation:': {
types: ['void', ['id', 'id']],
implementation: function (webView, navigation) {
while (webView.isLoading) {
$.NSRunLoop.currentRunLoop.runUntilDate($.NSDate.dateWithTimeIntervalSinceNow(0.01));
}
runJavaScriptInWebView(webView, '[document.body.scrollWidth, Array.from(document.body.children).findLast((child) => child.clientHeight > 0 && child.offsetTop > 0)?.getBoundingClientRect()?.bottom ?? 0]', (result) => {
const documentHeight = result.js[1].js;
const finalHeight = documentHeight > outputDimensions.height ? documentHeight : outputDimensions.height;
webView.setFrame($.NSMakeRect(0, 0, outputDimensions.width, finalHeight));
takeSnapshot(webView, outputDimensions.width, finalHeight, this);
});
}
},
},
});
}
return $.WebViewDelegate.alloc.init;
}
function buildWebViewConfig() {
const config = $.WKWebViewConfiguration.alloc.init;
config.setSuppressesIncrementalRendering(true);
config.setMediaTypesRequiringUserActionForPlayback($.WKAudiovisualMediaTypeNone);
const preferences = $.WKPreferences.alloc.init;
preferences.setShouldPrintBackgrounds(true);
preferences.setInactiveSchedulingPolicy($.WKInactiveSchedulingPolicyNone);
preferences._setAllowFileAccessFromFileURLs(true);
preferences._setUniversalAccessFromFileURLsAllowed(true);
config.setPreferences(preferences);
return config;
}
function runJavaScriptInWebView(webView, jsScript, handleResult) {
webView.evaluateJavaScriptCompletionHandler(jsScript, (result, error) => {
if (error.localizedDescription) {
$.NSLog(error.localizedDescription);
this.result = $.NSString.stringWithString('Error');
return;
}
handleResult?.(result)
});
}
function takeSnapshot(webview, width, height, sender) {
const snapConfig = $.WKSnapshotConfiguration.alloc.init;
snapConfig.setRect($.NSMakeRect(0, 0, width, height));
snapConfig.setSnapshotWidth(width);
snapConfig.setAfterScreenUpdates(true);
webview.takeSnapshotWithConfigurationCompletionHandler(snapConfig, (image, error) => {
if (error.localizedDescription) {
$.NSLog(error.localizedDescription);
this.result = $.NSString.stringWithString('Error');
return;
}
const CGImage = image.CGImageForProposedRectContextHints(null, $.NSGraphicsContext.currentContext, $.NSDictionary.alloc.init);
const bitmap = $.NSBitmapImageRep.alloc.initWithCGImage(CGImage);
const data = bitmap.representationUsingTypeProperties($.NSPNGFileType, $.NSDictionary.alloc.init);
sender.result = data.base64EncodedStringWithOptions(null);
})
}
function imageFromBase64String(base64String) {
const imageData = $.NSData.alloc.initWithBase64EncodedStringOptions(base64String, 0);
return $.NSImage.alloc.initWithData(imageData);
}
function createPDFFromImage(image, outputURL) {
const pdfDoc = $.PDFDocument.alloc.init;
const pdfPage = $.PDFPage.alloc.initWithImage(image);
pdfDoc.insertPageAtIndex(pdfPage, 0);
pdfDoc.writeToURL(outputURL);
const se = Application('System Events');
se.includeStandardAdditions = true;
se.openLocation(outputURL.absoluteString.js);
return outputURL.path.js;
}"
run script JXAScript in "JavaScript"
This script is functionally very similar to the earlier one, but I cleaned it up a bit and made it export a PDF.