test crash fix + layout fix

This commit is contained in:
cranci1 2025-07-01 18:11:16 +02:00
parent d707858ad7
commit 09b1d9b0b1
4 changed files with 167 additions and 77 deletions

View file

@ -9,7 +9,6 @@ import Foundation
import JavaScriptCore
extension JSController {
func fetchDetails(url: String, completion: @escaping ([MediaItem], [EpisodeLink]) -> Void) {
guard let url = URL(string: url) else {
completion([], [])
@ -94,15 +93,29 @@ extension JSController {
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
var hasLeftDetailsGroup = false
let detailsGroupQueue = DispatchQueue(label: "details.group")
let promiseValueDetails = extractDetailsFunction.call(withArguments: [url.absoluteString])
guard let promiseDetails = promiseValueDetails else {
Logger.shared.log("extractDetails did not return a Promise", type: "Error")
detailsGroupQueue.sync {
guard !hasLeftDetailsGroup else { return }
hasLeftDetailsGroup = true
dispatchGroup.leave()
}
completion([], [])
return
}
let thenBlockDetails: @convention(block) (JSValue) -> Void = { result in
detailsGroupQueue.sync {
guard !hasLeftDetailsGroup else {
Logger.shared.log("extractDetails: thenBlock called but group already left", type: "Debug")
return
}
hasLeftDetailsGroup = true
if let jsonOfDetails = result.toString(),
let dataDetails = jsonOfDetails.data(using: .utf8) {
do {
@ -125,11 +138,20 @@ extension JSController {
}
dispatchGroup.leave()
}
}
let catchBlockDetails: @convention(block) (JSValue) -> Void = { error in
detailsGroupQueue.sync {
guard !hasLeftDetailsGroup else {
Logger.shared.log("extractDetails: catchBlock called but group already left", type: "Debug")
return
}
hasLeftDetailsGroup = true
Logger.shared.log("Promise rejected of extractDetails: \(String(describing: error.toString()))", type: "Error")
dispatchGroup.leave()
}
}
let thenFunctionDetails = JSValue(object: thenBlockDetails, in: context)
let catchFunctionDetails = JSValue(object: catchBlockDetails, in: context)
@ -140,22 +162,43 @@ extension JSController {
dispatchGroup.enter()
let promiseValueEpisodes = extractEpisodesFunction.call(withArguments: [url.absoluteString])
var hasLeftEpisodesGroup = false
let episodesGroupQueue = DispatchQueue(label: "episodes.group")
let timeoutWorkItem = DispatchWorkItem {
Logger.shared.log("Timeout for extractEpisodes", type: "Warning")
episodesGroupQueue.sync {
guard !hasLeftEpisodesGroup else {
Logger.shared.log("extractEpisodes: timeout called but group already left", type: "Debug")
return
}
hasLeftEpisodesGroup = true
dispatchGroup.leave()
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0, execute: timeoutWorkItem)
guard let promiseEpisodes = promiseValueEpisodes else {
Logger.shared.log("extractEpisodes did not return a Promise", type: "Error")
timeoutWorkItem.cancel()
episodesGroupQueue.sync {
guard !hasLeftEpisodesGroup else { return }
hasLeftEpisodesGroup = true
dispatchGroup.leave()
}
completion([], [])
return
}
let thenBlockEpisodes: @convention(block) (JSValue) -> Void = { result in
timeoutWorkItem.cancel()
episodesGroupQueue.sync {
guard !hasLeftEpisodesGroup else {
Logger.shared.log("extractEpisodes: thenBlock called but group already left", type: "Debug")
return
}
hasLeftEpisodesGroup = true
if let jsonOfEpisodes = result.toString(),
let dataEpisodes = jsonOfEpisodes.data(using: .utf8) {
do {
@ -179,12 +222,21 @@ extension JSController {
}
dispatchGroup.leave()
}
}
let catchBlockEpisodes: @convention(block) (JSValue) -> Void = { error in
timeoutWorkItem.cancel()
episodesGroupQueue.sync {
guard !hasLeftEpisodesGroup else {
Logger.shared.log("extractEpisodes: catchBlock called but group already left", type: "Debug")
return
}
hasLeftEpisodesGroup = true
Logger.shared.log("Promise rejected of extractEpisodes: \(String(describing: error.toString()))", type: "Error")
dispatchGroup.leave()
}
}
let thenFunctionEpisodes = JSValue(object: thenBlockEpisodes, in: context)
let catchFunctionEpisodes = JSValue(object: catchBlockEpisodes, in: context)

View file

@ -59,8 +59,18 @@ extension JSController {
let group = DispatchGroup()
group.enter()
var chaptersArr: [[String: Any]] = []
var hasLeftGroup = false
let groupQueue = DispatchQueue(label: "extractChapters.group")
let thenBlock: @convention(block) (JSValue) -> Void = { jsValue in
Logger.shared.log("extractChapters thenBlock: \(jsValue)", type: "Debug")
groupQueue.sync {
guard !hasLeftGroup else {
Logger.shared.log("extractChapters: thenBlock called but group already left", type: "Debug")
return
}
hasLeftGroup = true
if let arr = jsValue.toArray() as? [[String: Any]] {
Logger.shared.log("extractChapters: parsed as array, count = \(arr.count)", type: "Debug")
chaptersArr = arr
@ -80,10 +90,18 @@ extension JSController {
}
group.leave()
}
}
let catchBlock: @convention(block) (JSValue) -> Void = { jsValue in
Logger.shared.log("extractChapters catchBlock: \(jsValue)", type: "Error")
groupQueue.sync {
guard !hasLeftGroup else {
Logger.shared.log("extractChapters: catchBlock called but group already left", type: "Debug")
return
}
hasLeftGroup = true
group.leave()
}
}
result.invokeMethod("then", withArguments: [thenBlock])
result.invokeMethod("catch", withArguments: [catchBlock])
group.notify(queue: .main) {
@ -182,9 +200,18 @@ extension JSController {
group.enter()
var extractedText = ""
var extractError: Error? = nil
var hasLeftGroup = false
let groupQueue = DispatchQueue(label: "extractText.group")
let thenBlock: @convention(block) (JSValue) -> Void = { jsValue in
Logger.shared.log("extractText thenBlock: received value", type: "Debug")
groupQueue.sync {
guard !hasLeftGroup else {
Logger.shared.log("extractText: thenBlock called but group already left", type: "Debug")
return
}
hasLeftGroup = true
if let text = jsValue.toString(), !text.isEmpty {
Logger.shared.log("extractText: successfully extracted text", type: "Debug")
extractedText = text
@ -193,14 +220,23 @@ extension JSController {
}
group.leave()
}
}
let catchBlock: @convention(block) (JSValue) -> Void = { jsValue in
Logger.shared.log("extractText catchBlock: \(jsValue)", type: "Error")
groupQueue.sync {
guard !hasLeftGroup else {
Logger.shared.log("extractText: catchBlock called but group already left", type: "Debug")
return
}
hasLeftGroup = true
if extractedText.isEmpty {
extractError = JSError.jsException(jsValue.toString() ?? "Unknown error")
}
group.leave()
}
}
result.invokeMethod("then", withArguments: [thenBlock])
result.invokeMethod("catch", withArguments: [catchBlock])

View file

@ -341,6 +341,8 @@ struct SettingsViewGeneral: View {
.font(.caption)
.foregroundStyle(.gray)
.frame(maxWidth: .infinity, alignment: .center)
.padding(.top, -6)
.padding(.bottom, 8)
}
.environment(\.editMode, .constant(.active))
}

View file

@ -634,8 +634,8 @@
isa = PBXGroup;
children = (
134A387B2DE4B5B90041B687 /* Downloads */,
04536F702E04BA3B00A11248 /* JSController-Novel.swift */,
133D7C8B2D2BE2640075467E /* JSController.swift */,
04536F702E04BA3B00A11248 /* JSController-Novel.swift */,
132AF1202D99951700A0140B /* JSController-Streams.swift */,
132AF1222D9995C300A0140B /* JSController-Details.swift */,
132AF1242D9995F900A0140B /* JSController-Search.swift */,