mirror of
https://github.com/cranci1/Sora.git
synced 2026-05-12 04:50:41 +00:00
Click support for network fetcher (#240)
* Update JSController-NetworkFetch.swift * Shitty AI code by paul --------- Co-authored-by: cranci1 <100066266+cranci1@users.noreply.github.com>
This commit is contained in:
parent
d67229800c
commit
cc65bc1634
1 changed files with 248 additions and 51 deletions
|
|
@ -13,12 +13,26 @@ struct NetworkFetchOptions {
|
||||||
let headers: [String: String]
|
let headers: [String: String]
|
||||||
let cutoff: String?
|
let cutoff: String?
|
||||||
let returnHTML: Bool
|
let returnHTML: Bool
|
||||||
|
let clickSelectors: [String]
|
||||||
|
let waitForSelectors: [String]
|
||||||
|
let maxWaitTime: Int
|
||||||
|
|
||||||
init(timeoutSeconds: Int = 10, headers: [String: String] = [:], cutoff: String? = nil, returnHTML: Bool = false) {
|
init(
|
||||||
|
timeoutSeconds: Int = 10,
|
||||||
|
headers: [String: String] = [:],
|
||||||
|
cutoff: String? = nil,
|
||||||
|
returnHTML: Bool = false,
|
||||||
|
clickSelectors: [String] = [],
|
||||||
|
waitForSelectors: [String] = [],
|
||||||
|
maxWaitTime: Int = 5
|
||||||
|
) {
|
||||||
self.timeoutSeconds = timeoutSeconds
|
self.timeoutSeconds = timeoutSeconds
|
||||||
self.headers = headers
|
self.headers = headers
|
||||||
self.cutoff = cutoff
|
self.cutoff = cutoff
|
||||||
self.returnHTML = returnHTML
|
self.returnHTML = returnHTML
|
||||||
|
self.clickSelectors = clickSelectors
|
||||||
|
self.waitForSelectors = waitForSelectors
|
||||||
|
self.maxWaitTime = maxWaitTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,12 +47,18 @@ extension JSContext {
|
||||||
let headers = optionsDict["headers"] as? [String: String] ?? [:]
|
let headers = optionsDict["headers"] as? [String: String] ?? [:]
|
||||||
let cutoff = optionsDict["cutoff"] as? String
|
let cutoff = optionsDict["cutoff"] as? String
|
||||||
let returnHTML = optionsDict["returnHTML"] as? Bool ?? false
|
let returnHTML = optionsDict["returnHTML"] as? Bool ?? false
|
||||||
|
let clickSelectors = optionsDict["clickSelectors"] as? [String] ?? []
|
||||||
|
let waitForSelectors = optionsDict["waitForSelectors"] as? [String] ?? []
|
||||||
|
let maxWaitTime = optionsDict["maxWaitTime"] as? Int ?? 5
|
||||||
|
|
||||||
options = NetworkFetchOptions(
|
options = NetworkFetchOptions(
|
||||||
timeoutSeconds: timeoutSeconds,
|
timeoutSeconds: timeoutSeconds,
|
||||||
headers: headers,
|
headers: headers,
|
||||||
cutoff: cutoff,
|
cutoff: cutoff,
|
||||||
returnHTML: returnHTML
|
returnHTML: returnHTML,
|
||||||
|
clickSelectors: clickSelectors,
|
||||||
|
waitForSelectors: waitForSelectors,
|
||||||
|
maxWaitTime: maxWaitTime
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +86,10 @@ extension JSContext {
|
||||||
timeoutSeconds: options.timeoutSeconds || 10,
|
timeoutSeconds: options.timeoutSeconds || 10,
|
||||||
headers: options.headers || {},
|
headers: options.headers || {},
|
||||||
cutoff: options.cutoff || null,
|
cutoff: options.cutoff || null,
|
||||||
returnHTML: options.returnHTML || false
|
returnHTML: options.returnHTML || false,
|
||||||
|
clickSelectors: options.clickSelectors || [],
|
||||||
|
waitForSelectors: options.waitForSelectors || [],
|
||||||
|
maxWaitTime: options.maxWaitTime || 5
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
|
|
@ -80,7 +103,9 @@ extension JSContext {
|
||||||
totalRequests: result.requests.length,
|
totalRequests: result.requests.length,
|
||||||
cutoffTriggered: result.cutoffTriggered || false,
|
cutoffTriggered: result.cutoffTriggered || false,
|
||||||
cutoffUrl: result.cutoffUrl || null,
|
cutoffUrl: result.cutoffUrl || null,
|
||||||
htmlCaptured: result.htmlCaptured || false
|
htmlCaptured: result.htmlCaptured || false,
|
||||||
|
elementsClicked: result.elementsClicked || [],
|
||||||
|
waitResults: result.waitResults || {}
|
||||||
});
|
});
|
||||||
}, reject);
|
}, reject);
|
||||||
});
|
});
|
||||||
|
|
@ -99,6 +124,30 @@ extension JSContext {
|
||||||
cutoff: cutoff
|
cutoff: cutoff
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function networkFetchWithClicks(url, clickSelectors, options = {}) {
|
||||||
|
return networkFetch(url, {
|
||||||
|
timeoutSeconds: options.timeoutSeconds || 10,
|
||||||
|
headers: options.headers || {},
|
||||||
|
cutoff: options.cutoff || null,
|
||||||
|
returnHTML: options.returnHTML || false,
|
||||||
|
clickSelectors: Array.isArray(clickSelectors) ? clickSelectors : [clickSelectors],
|
||||||
|
waitForSelectors: options.waitForSelectors || [],
|
||||||
|
maxWaitTime: options.maxWaitTime || 5
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function networkFetchWithWaitAndClick(url, waitForSelectors, clickSelectors, options = {}) {
|
||||||
|
return networkFetch(url, {
|
||||||
|
timeoutSeconds: options.timeoutSeconds || 10,
|
||||||
|
headers: options.headers || {},
|
||||||
|
cutoff: options.cutoff || null,
|
||||||
|
returnHTML: options.returnHTML || false,
|
||||||
|
clickSelectors: Array.isArray(clickSelectors) ? clickSelectors : [clickSelectors],
|
||||||
|
waitForSelectors: Array.isArray(waitForSelectors) ? waitForSelectors : [waitForSelectors],
|
||||||
|
maxWaitTime: options.maxWaitTime || 5
|
||||||
|
});
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.evaluateScript(networkFetchDefinition)
|
self.evaluateScript(networkFetchDefinition)
|
||||||
|
|
@ -115,7 +164,7 @@ class NetworkFetchManager: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func performNetworkFetch(urlString: String, options: NetworkFetchOptions, resolve: JSValue, reject: JSValue) {
|
func performNetworkFetch(urlString: String, options: NetworkFetchOptions, resolve: JSValue, reject: JSValue) {
|
||||||
Logger.shared.log("NetworkFetchManager: Starting fetch for \(urlString) with options: returnHTML=\(options.returnHTML)", type: "Debug")
|
Logger.shared.log("NetworkFetchManager: Starting fetch for \(urlString) with options: returnHTML=\(options.returnHTML), clicks=\(options.clickSelectors), waitFor=\(options.waitForSelectors)", type: "Debug")
|
||||||
|
|
||||||
let monitorId = UUID().uuidString
|
let monitorId = UUID().uuidString
|
||||||
let monitor = NetworkFetchMonitor()
|
let monitor = NetworkFetchMonitor()
|
||||||
|
|
@ -146,6 +195,8 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
private var completionHandler: (([String: Any]) -> Void)?
|
private var completionHandler: (([String: Any]) -> Void)?
|
||||||
private var timer: Timer?
|
private var timer: Timer?
|
||||||
private var options: NetworkFetchOptions?
|
private var options: NetworkFetchOptions?
|
||||||
|
private var elementsClicked: [String] = []
|
||||||
|
private var waitResults: [String: Bool] = [:]
|
||||||
|
|
||||||
@Published private(set) var networkRequests: [String] = []
|
@Published private(set) var networkRequests: [String] = []
|
||||||
@Published private(set) var statusMessage = "Initializing..."
|
@Published private(set) var statusMessage = "Initializing..."
|
||||||
|
|
@ -162,12 +213,20 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
cutoffUrl = nil
|
cutoffUrl = nil
|
||||||
htmlContent = nil
|
htmlContent = nil
|
||||||
htmlCaptured = false
|
htmlCaptured = false
|
||||||
|
elementsClicked.removeAll()
|
||||||
|
waitResults.removeAll()
|
||||||
|
|
||||||
if options.returnHTML {
|
var statusParts = ["Loading URL for \(options.timeoutSeconds) seconds"]
|
||||||
statusMessage = "Loading URL for \(options.timeoutSeconds) seconds, will capture HTML at end..."
|
if !options.waitForSelectors.isEmpty {
|
||||||
} else {
|
statusParts.append("waiting for elements")
|
||||||
statusMessage = "Loading URL for \(options.timeoutSeconds) seconds..."
|
|
||||||
}
|
}
|
||||||
|
if !options.clickSelectors.isEmpty {
|
||||||
|
statusParts.append("will click elements")
|
||||||
|
}
|
||||||
|
if options.returnHTML {
|
||||||
|
statusParts.append("will capture HTML")
|
||||||
|
}
|
||||||
|
statusMessage = statusParts.joined(separator: ", ") + "..."
|
||||||
|
|
||||||
guard let url = URL(string: urlString) else {
|
guard let url = URL(string: urlString) else {
|
||||||
completion([
|
completion([
|
||||||
|
|
@ -176,7 +235,9 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
"html": NSNull(),
|
"html": NSNull(),
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": "Invalid URL format",
|
"error": "Invalid URL format",
|
||||||
"htmlCaptured": false
|
"htmlCaptured": false,
|
||||||
|
"elementsClicked": [],
|
||||||
|
"waitResults": [:]
|
||||||
])
|
])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +253,7 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.shared.log("NetworkFetch started for: \(urlString) (timeout: \(options.timeoutSeconds)s, returnHTML: \(options.returnHTML))", type: "Debug")
|
Logger.shared.log("NetworkFetch started for: \(urlString) (timeout: \(options.timeoutSeconds)s, returnHTML: \(options.returnHTML), clicks: \(options.clickSelectors), waitFor: \(options.waitForSelectors))", type: "Debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func captureHTMLThenComplete() {
|
private func captureHTMLThenComplete() {
|
||||||
|
|
@ -424,6 +485,96 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
|
|
||||||
aggressiveJWHook();
|
aggressiveJWHook();
|
||||||
|
|
||||||
|
window.waitForElementAndClick = function(waitSelectors, clickSelectors, maxWaitTime) {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
const results = {
|
||||||
|
waitResults: {},
|
||||||
|
clickResults: []
|
||||||
|
};
|
||||||
|
|
||||||
|
waitSelectors.forEach(function(selector) {
|
||||||
|
results.waitResults[selector] = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
const checkInterval = 100;
|
||||||
|
|
||||||
|
const checkAndClick = function() {
|
||||||
|
const elapsed = (Date.now() - startTime) / 1000;
|
||||||
|
|
||||||
|
let allFound = waitSelectors.length === 0;
|
||||||
|
|
||||||
|
waitSelectors.forEach(function(selector) {
|
||||||
|
const element = document.querySelector(selector);
|
||||||
|
if (element && element.offsetParent !== null) {
|
||||||
|
results.waitResults[selector] = true;
|
||||||
|
console.log('Element found and visible:', selector);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
allFound = waitSelectors.every(function(selector) {
|
||||||
|
return results.waitResults[selector];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (allFound || elapsed >= maxWaitTime) {
|
||||||
|
clickSelectors.forEach(function(selector) {
|
||||||
|
try {
|
||||||
|
const elements = document.querySelectorAll(selector);
|
||||||
|
let clicked = false;
|
||||||
|
|
||||||
|
elements.forEach(function(element) {
|
||||||
|
if (element && element.offsetParent !== null) {
|
||||||
|
try {
|
||||||
|
element.click();
|
||||||
|
clicked = true;
|
||||||
|
console.log('Successfully clicked:', selector);
|
||||||
|
} catch(e1) {
|
||||||
|
try {
|
||||||
|
const event = new MouseEvent('click', {
|
||||||
|
view: window,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true
|
||||||
|
});
|
||||||
|
element.dispatchEvent(event);
|
||||||
|
clicked = true;
|
||||||
|
console.log('Successfully dispatched click:', selector);
|
||||||
|
} catch(e2) {
|
||||||
|
console.log('Failed to click element:', selector, e2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
results.clickResults.push({
|
||||||
|
selector: selector,
|
||||||
|
success: clicked,
|
||||||
|
elementsFound: elements.length
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
console.log('Error clicking selector:', selector, e);
|
||||||
|
results.clickResults.push({
|
||||||
|
selector: selector,
|
||||||
|
success: false,
|
||||||
|
error: e.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.webkit.messageHandlers.networkLogger.postMessage({
|
||||||
|
type: 'click-results',
|
||||||
|
results: results
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(results);
|
||||||
|
} else if (elapsed < maxWaitTime) {
|
||||||
|
setTimeout(checkAndClick, checkInterval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkAndClick();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const nuclearScan = function() {
|
const nuclearScan = function() {
|
||||||
console.log('Nuclear scan initiated');
|
console.log('Nuclear scan initiated');
|
||||||
|
|
||||||
|
|
@ -456,23 +607,6 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const clickableSelectors = [
|
|
||||||
'button', '.play', '.play-button', '[data-play]', '.video-play',
|
|
||||||
'.jwplayer', '.player', '[id*="player"]', '[class*="play"]',
|
|
||||||
'div[onclick]', 'span[onclick]', 'a[onclick]'
|
|
||||||
];
|
|
||||||
|
|
||||||
clickableSelectors.forEach(function(selector) {
|
|
||||||
document.querySelectorAll(selector).forEach(function(el) {
|
|
||||||
try {
|
|
||||||
el.click();
|
|
||||||
console.log('Force clicked:', selector);
|
|
||||||
} catch(e) {
|
|
||||||
console.log('Click failed:', e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(nuclearScan, 500);
|
setTimeout(nuclearScan, 500);
|
||||||
|
|
@ -511,7 +645,7 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
|
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
request.setValue(value, forHTTPHeaderField: key)
|
request.setValue(value, forHTTPHeaderField: key)
|
||||||
Logger.shared.log("Custom header set: \(key): \(value)")
|
Logger.shared.log("Custom header set: \(key): \(value)", type: "Debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.value(forHTTPHeaderField: "Referer") == nil {
|
if request.value(forHTTPHeaderField: "Referer") == nil {
|
||||||
|
|
@ -529,10 +663,42 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
webView.load(request)
|
webView.load(request)
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
|
||||||
self.simulateUserInteraction()
|
self.performCustomInteractions()
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.shared.log("Started loading: \(url.absoluteString)")
|
Logger.shared.log("Started loading: \(url.absoluteString)", type: "Debug")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func performCustomInteractions() {
|
||||||
|
guard let webView = webView, let options = options else { return }
|
||||||
|
|
||||||
|
if !options.waitForSelectors.isEmpty || !options.clickSelectors.isEmpty {
|
||||||
|
let waitSelectorsJS = options.waitForSelectors.map { "'\($0)'" }.joined(separator: ", ")
|
||||||
|
let clickSelectorsJS = options.clickSelectors.map { "'\($0)'" }.joined(separator: ", ")
|
||||||
|
|
||||||
|
let customInteractionJS = """
|
||||||
|
window.waitForElementAndClick(
|
||||||
|
[\(waitSelectorsJS)],
|
||||||
|
[\(clickSelectorsJS)],
|
||||||
|
\(options.maxWaitTime)
|
||||||
|
).then(function(results) {
|
||||||
|
console.log('Custom interaction completed:', results);
|
||||||
|
});
|
||||||
|
"""
|
||||||
|
|
||||||
|
statusMessage = "Performing custom interactions..."
|
||||||
|
Logger.shared.log("NetworkFetch: Starting custom interactions - wait for: \(options.waitForSelectors), click: \(options.clickSelectors)", type: "Debug")
|
||||||
|
|
||||||
|
webView.evaluateJavaScript(customInteractionJS) { result, error in
|
||||||
|
if let error = error {
|
||||||
|
Logger.shared.log("NetworkFetch: Custom interaction error: \(error)", type: "Error")
|
||||||
|
} else {
|
||||||
|
Logger.shared.log("NetworkFetch: Custom interaction JavaScript executed successfully", type: "Debug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
simulateUserInteraction()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func simulateUserInteraction() {
|
private func simulateUserInteraction() {
|
||||||
|
|
@ -540,18 +706,25 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
|
|
||||||
let jsInteraction = """
|
let jsInteraction = """
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
const playButtons = document.querySelectorAll('button, div, span, a').filter(function(el) {
|
const playButtons = document.querySelectorAll('button, div, span, a');
|
||||||
|
const filteredButtons = Array.from(playButtons).filter(function(el) {
|
||||||
const text = el.textContent || el.innerText || '';
|
const text = el.textContent || el.innerText || '';
|
||||||
const classes = el.className || '';
|
const classes = el.className || '';
|
||||||
return text.toLowerCase().includes('play') ||
|
const id = el.id || '';
|
||||||
|
return text.toLowerCase().includes('play') ||
|
||||||
classes.toLowerCase().includes('play') ||
|
classes.toLowerCase().includes('play') ||
|
||||||
|
id.toLowerCase().includes('play') ||
|
||||||
el.getAttribute('aria-label')?.toLowerCase().includes('play');
|
el.getAttribute('aria-label')?.toLowerCase().includes('play');
|
||||||
});
|
});
|
||||||
|
|
||||||
playButtons.forEach(function(btn, index) {
|
filteredButtons.forEach(function(btn, index) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
btn.click();
|
try {
|
||||||
console.log('Clicked play button:', btn);
|
btn.click();
|
||||||
|
console.log('Clicked play button:', btn);
|
||||||
|
} catch(e) {
|
||||||
|
console.log('Failed to click button:', e);
|
||||||
|
}
|
||||||
}, index * 200);
|
}, index * 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -609,14 +782,16 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
webView?.stopLoading()
|
webView?.stopLoading()
|
||||||
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "networkLogger")
|
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "networkLogger")
|
||||||
|
|
||||||
let result: [String: Any?] = [
|
let result: [String: Any] = [
|
||||||
"originalUrl": webView?.url?.absoluteString ?? "",
|
"originalUrl": webView?.url?.absoluteString ?? "",
|
||||||
"requests": networkRequests,
|
"requests": networkRequests,
|
||||||
"html": htmlContent,
|
"html": htmlContent as Any,
|
||||||
"success": true,
|
"success": true,
|
||||||
"cutoffTriggered": cutoffTriggered,
|
"cutoffTriggered": cutoffTriggered,
|
||||||
"cutoffUrl": cutoffUrl,
|
"cutoffUrl": cutoffUrl as Any,
|
||||||
"htmlCaptured": htmlCaptured
|
"htmlCaptured": htmlCaptured,
|
||||||
|
"elementsClicked": elementsClicked,
|
||||||
|
"waitResults": waitResults
|
||||||
]
|
]
|
||||||
|
|
||||||
webView = nil
|
webView = nil
|
||||||
|
|
@ -625,15 +800,15 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
statusMessage = "Cutoff triggered! Found \(networkRequests.count) requests"
|
statusMessage = "Cutoff triggered! Found \(networkRequests.count) requests"
|
||||||
Logger.shared.log("NetworkFetch stopped early due to cutoff: \(cutoffUrl ?? "unknown")", type: "Debug")
|
Logger.shared.log("NetworkFetch stopped early due to cutoff: \(cutoffUrl ?? "unknown")", type: "Debug")
|
||||||
} else if htmlCaptured {
|
} else if htmlCaptured {
|
||||||
statusMessage = "HTML captured! Found \(networkRequests.count) requests"
|
statusMessage = "HTML captured! Found \(networkRequests.count) requests, clicked \(elementsClicked.count) elements"
|
||||||
} else {
|
} else {
|
||||||
statusMessage = "Completed! Found \(networkRequests.count) requests"
|
statusMessage = "Completed! Found \(networkRequests.count) requests, clicked \(elementsClicked.count) elements"
|
||||||
}
|
}
|
||||||
|
|
||||||
completionHandler?(result as [String : Any])
|
completionHandler?(result)
|
||||||
completionHandler = nil
|
completionHandler = nil
|
||||||
|
|
||||||
Logger.shared.log("Monitoring stopped (\(reason)). Total requests: \(networkRequests.count), HTML captured: \(htmlCaptured)", type: "Debug")
|
Logger.shared.log("Monitoring stopped (\(reason)). Total requests: \(networkRequests.count), HTML captured: \(htmlCaptured), Elements clicked: \(elementsClicked.count)", type: "Debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addRequest(_ urlString: String) {
|
private func addRequest(_ urlString: String) {
|
||||||
|
|
@ -657,11 +832,11 @@ class NetworkFetchMonitor: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NetworkFetchMonitor: WKNavigationDelegate {
|
extension NetworkFetchMonitor: WKNavigationDelegate {
|
||||||
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {}
|
||||||
Logger.shared.log("WebView failed: \(error.localizedDescription)", type: "Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {}
|
||||||
|
|
||||||
|
private func webView(_ webView: WKNavigationAction, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||||
if let url = navigationAction.request.url {
|
if let url = navigationAction.request.url {
|
||||||
addRequest(url.absoluteString)
|
addRequest(url.absoluteString)
|
||||||
}
|
}
|
||||||
|
|
@ -672,9 +847,31 @@ extension NetworkFetchMonitor: WKNavigationDelegate {
|
||||||
extension NetworkFetchMonitor: WKScriptMessageHandler {
|
extension NetworkFetchMonitor: WKScriptMessageHandler {
|
||||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||||
if message.name == "networkLogger" {
|
if message.name == "networkLogger" {
|
||||||
if let messageBody = message.body as? [String: Any],
|
if let messageBody = message.body as? [String: Any] {
|
||||||
let url = messageBody["url"] as? String {
|
if let url = messageBody["url"] as? String {
|
||||||
addRequest(url)
|
addRequest(url)
|
||||||
|
} else if let type = messageBody["type"] as? String, type == "click-results" {
|
||||||
|
if let results = messageBody["results"] as? [String: Any] {
|
||||||
|
if let clickResults = results["clickResults"] as? [[String: Any]] {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
for clickResult in clickResults {
|
||||||
|
if let selector = clickResult["selector"] as? String,
|
||||||
|
let success = clickResult["success"] as? Bool, success {
|
||||||
|
self.elementsClicked.append(selector)
|
||||||
|
Logger.shared.log("NetworkFetch: Successfully clicked element: \(selector)", type: "Debug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let waitResults = results["waitResults"] as? [String: Bool] {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.waitResults = waitResults
|
||||||
|
Logger.shared.log("NetworkFetch: Wait results: \(waitResults)", type: "Debug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue