mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
start work on explore content module addition, fork / modify "aniworld.to" script "https://devsforge.de/Sora/aniworld.json", modify jscontext / loading and update routines, tests
This commit is contained in:
parent
6f7b4ba092
commit
5f62e7f05e
5 changed files with 94 additions and 43 deletions
|
|
@ -440,7 +440,7 @@
|
|||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Author:"
|
||||
"value" : "Author: %@"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
|
|
|
|||
|
|
@ -10,34 +10,32 @@ import JavaScriptCore
|
|||
// TODO: implement and test
|
||||
extension JSController {
|
||||
func fetchExploreResults(module: ScrapingModule, completion: @escaping ([ExploreItem]) -> Void) {
|
||||
completion([])
|
||||
/*let searchUrl = module.metadata.searchBaseUrl.replacingOccurrences(of: "%s", with: keyword.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
|
||||
|
||||
guard let url = URL(string: searchUrl) else {
|
||||
guard let exploreUrl = module.metadata.exploreBaseUrl,
|
||||
let url = URL(string: exploreUrl) else {
|
||||
completion([])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
URLSession.custom.dataTask(with: url) { [weak self] data, _, error in
|
||||
guard let self = self else { return }
|
||||
|
||||
guard let self else { return }
|
||||
|
||||
if let error {
|
||||
Logger.shared.log("Network error: \(error)",type: "Error")
|
||||
Logger.shared.log("Network error: \(error)", type: .error)
|
||||
DispatchQueue.main.async { completion([]) }
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let data, let html = String(data: data, encoding: .utf8) else {
|
||||
Logger.shared.log("Failed to decode HTML",type: "Error")
|
||||
Logger.shared.log("Failed to decode HTML", type: .error)
|
||||
DispatchQueue.main.async { completion([]) }
|
||||
return
|
||||
}
|
||||
|
||||
Logger.shared.log(html,type: "HTMLStrings")
|
||||
if let parseFunction = self.context.objectForKeyedSubscript("searchResults"),
|
||||
|
||||
Logger.shared.log(html, type: .html)
|
||||
if let parseFunction = self.context.objectForKeyedSubscript("exploreResults"),
|
||||
let results = parseFunction.call(withArguments: [html]).toArray() as? [[String: String]] {
|
||||
let resultItems = results.map { item in
|
||||
SearchItem(
|
||||
ExploreItem(
|
||||
title: item["title"] ?? "",
|
||||
imageUrl: item["image"] ?? "",
|
||||
href: item["href"] ?? ""
|
||||
|
|
@ -47,88 +45,82 @@ extension JSController {
|
|||
completion(resultItems)
|
||||
}
|
||||
} else {
|
||||
Logger.shared.log("Failed to parse results",type: "Error")
|
||||
Logger.shared.log("Failed to parse results", type: .error)
|
||||
DispatchQueue.main.async { completion([]) }
|
||||
}
|
||||
}.resume()
|
||||
*/
|
||||
}
|
||||
|
||||
func fetchJsExploreResults(module: ScrapingModule, completion: @escaping ([ExploreItem]) -> Void) {
|
||||
completion([])
|
||||
/*
|
||||
if let exception = context.exception {
|
||||
Logger.shared.log("JavaScript exception: \(exception)",type: "Error")
|
||||
Logger.shared.log("JavaScript exception: \(exception)", type: .error)
|
||||
completion([])
|
||||
return
|
||||
}
|
||||
|
||||
guard let searchResultsFunction = context.objectForKeyedSubscript("searchResults") else {
|
||||
Logger.shared.log("No JavaScript function searchResults found",type: "Error")
|
||||
|
||||
guard let exploreResultsFunction = context.objectForKeyedSubscript("exploreResults") else {
|
||||
Logger.shared.log("No JavaScript function exploreResults found", type: .error)
|
||||
completion([])
|
||||
return
|
||||
}
|
||||
|
||||
let promiseValue = searchResultsFunction.call(withArguments: [keyword])
|
||||
|
||||
let promiseValue = exploreResultsFunction.call(withArguments: [])
|
||||
guard let promise = promiseValue else {
|
||||
Logger.shared.log("searchResults did not return a Promise",type: "Error")
|
||||
Logger.shared.log("exploreResults did not return a Promise", type: .error)
|
||||
completion([])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let thenBlock: @convention(block) (JSValue) -> Void = { result in
|
||||
|
||||
Logger.shared.log(result.toString(),type: "HTMLStrings")
|
||||
Logger.shared.log(result.toString(), type: .html)
|
||||
if let jsonString = result.toString(),
|
||||
let data = jsonString.data(using: .utf8) {
|
||||
do {
|
||||
if let array = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
|
||||
let resultItems = array.compactMap { item -> SearchItem? in
|
||||
let resultItems = array.compactMap { item -> ExploreItem? in
|
||||
guard let title = item["title"] as? String,
|
||||
let imageUrl = item["image"] as? String,
|
||||
let href = item["href"] as? String else {
|
||||
Logger.shared.log("Missing or invalid data in search result item: \(item)", type: .error)
|
||||
return nil
|
||||
}
|
||||
return SearchItem(title: title, imageUrl: imageUrl, href: href)
|
||||
return ExploreItem(title: title, imageUrl: imageUrl, href: href)
|
||||
}
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(resultItems)
|
||||
}
|
||||
|
||||
} else {
|
||||
Logger.shared.log("Failed to parse JSON",type: "Error")
|
||||
Logger.shared.log("Failed to parse JSON", type: .error)
|
||||
DispatchQueue.main.async {
|
||||
completion([])
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.shared.log("JSON parsing error: \(error)",type: "Error")
|
||||
Logger.shared.log("JSON parsing error: \(error)", type: .error)
|
||||
DispatchQueue.main.async {
|
||||
completion([])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Logger.shared.log("Result is not a string",type: "Error")
|
||||
Logger.shared.log("Result is not a string", type: .error)
|
||||
DispatchQueue.main.async {
|
||||
completion([])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let catchBlock: @convention(block) (JSValue) -> Void = { error in
|
||||
Logger.shared.log("Promise rejected: \(String(describing: error.toString()))",type: "Error")
|
||||
Logger.shared.log("Promise rejected: \(String(describing: error.toString()))", type: .error)
|
||||
DispatchQueue.main.async {
|
||||
completion([])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let thenFunction = JSValue(object: thenBlock, in: context)
|
||||
let catchFunction = JSValue(object: catchBlock, in: context)
|
||||
|
||||
|
||||
promise.invokeMethod("then", withArguments: [thenFunction as Any])
|
||||
promise.invokeMethod("catch", withArguments: [catchFunction as Any])
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,9 +172,26 @@ class ModuleManager: ObservableObject {
|
|||
let localUrl = getDocumentsDirectory().appendingPathComponent(fileName)
|
||||
try jsContent.write(to: localUrl, atomically: true, encoding: .utf8)
|
||||
|
||||
var exploreFileName: String?
|
||||
if let exploreScriptValue = metadata.exploreScriptUrl {
|
||||
guard let exploreScriptUrl = URL(string: exploreScriptValue) else {
|
||||
throw NSError(domain: "Invalid script URL", code: -1)
|
||||
}
|
||||
|
||||
let (exploreScriptData, _) = try await URLSession.custom.data(from: exploreScriptUrl)
|
||||
guard let exploreJsContent = String(data: exploreScriptData, encoding: .utf8) else {
|
||||
throw NSError(domain: "Invalid script encoding", code: -1)
|
||||
}
|
||||
|
||||
exploreFileName = "\(UUID().uuidString).js"
|
||||
let exploreLocalUrl = getDocumentsDirectory().appendingPathComponent(exploreFileName!)
|
||||
try exploreJsContent.write(to: exploreLocalUrl, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
let module = ScrapingModule(
|
||||
metadata: metadata,
|
||||
localPath: fileName,
|
||||
exploreLocalPath: exploreFileName,
|
||||
metadataUrl: metadataUrl
|
||||
)
|
||||
|
||||
|
|
@ -201,6 +218,15 @@ class ModuleManager: ObservableObject {
|
|||
return try String(contentsOf: localUrl, encoding: .utf8)
|
||||
}
|
||||
|
||||
func getModuleExploreContent(_ module: ScrapingModule) throws -> String? {
|
||||
if let exploreLocalPath = module.exploreLocalPath {
|
||||
let exploreLocalUrl = getDocumentsDirectory().appendingPathComponent(exploreLocalPath)
|
||||
return try String(contentsOf: exploreLocalUrl, encoding: .utf8)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func refreshModules() async {
|
||||
for (index, module) in modules.enumerated() {
|
||||
do {
|
||||
|
|
@ -220,10 +246,27 @@ class ModuleManager: ObservableObject {
|
|||
let localUrl = getDocumentsDirectory().appendingPathComponent(module.localPath)
|
||||
try jsContent.write(to: localUrl, atomically: true, encoding: .utf8)
|
||||
|
||||
var exploreFileName: String?
|
||||
if let exploreScriptValue = newMetadata.exploreScriptUrl {
|
||||
guard let exploreScriptUrl = URL(string: exploreScriptValue) else {
|
||||
throw NSError(domain: "Invalid script URL", code: -1)
|
||||
}
|
||||
|
||||
let (exploreScriptData, _) = try await URLSession.custom.data(from: exploreScriptUrl)
|
||||
guard let exploreJsContent = String(data: exploreScriptData, encoding: .utf8) else {
|
||||
throw NSError(domain: "Invalid script encoding", code: -1)
|
||||
}
|
||||
|
||||
exploreFileName = module.exploreLocalPath ?? "\(UUID().uuidString).js"
|
||||
let exploreLocalUrl = getDocumentsDirectory().appendingPathComponent(exploreFileName!)
|
||||
try exploreJsContent.write(to: exploreLocalUrl, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
let updatedModule = ScrapingModule(
|
||||
id: module.id,
|
||||
metadata: newMetadata,
|
||||
localPath: module.localPath,
|
||||
exploreLocalPath: exploreFileName,
|
||||
metadataUrl: module.metadataUrl,
|
||||
isActive: module.isActive
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ struct ModuleMetadata: Codable, Hashable {
|
|||
let quality: String
|
||||
let searchBaseUrl: String
|
||||
let scriptUrl: String
|
||||
let exploreBaseUrl: String?
|
||||
let exploreScriptUrl: String?
|
||||
let asyncJS: Bool?
|
||||
let streamAsyncJS: Bool?
|
||||
let softsub: Bool?
|
||||
|
|
@ -35,13 +37,22 @@ struct ScrapingModule: Codable, Identifiable, Hashable {
|
|||
let id: UUID
|
||||
let metadata: ModuleMetadata
|
||||
let localPath: String
|
||||
let exploreLocalPath: String?
|
||||
let metadataUrl: String
|
||||
var isActive: Bool
|
||||
|
||||
init(id: UUID = UUID(), metadata: ModuleMetadata, localPath: String, metadataUrl: String, isActive: Bool = false) {
|
||||
init(
|
||||
id: UUID = UUID(),
|
||||
metadata: ModuleMetadata,
|
||||
localPath: String,
|
||||
exploreLocalPath: String?,
|
||||
metadataUrl: String,
|
||||
isActive: Bool = false
|
||||
) {
|
||||
self.id = id
|
||||
self.metadata = metadata
|
||||
self.localPath = localPath
|
||||
self.exploreLocalPath = exploreLocalPath
|
||||
self.metadataUrl = metadataUrl
|
||||
self.isActive = isActive
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,7 +284,12 @@ struct ExploreView: View {
|
|||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
Task {
|
||||
do {
|
||||
let jsContent = try moduleManager.getModuleContent(module)
|
||||
guard let jsContent = try moduleManager.getModuleExploreContent(module) else {
|
||||
isLoading = false
|
||||
hasNoResults = true
|
||||
return
|
||||
}
|
||||
|
||||
jsController.loadScript(jsContent)
|
||||
if module.metadata.asyncJS == true {
|
||||
jsController.fetchJsExploreResults(module: module) { items in
|
||||
|
|
|
|||
Loading…
Reference in a new issue