mirror of
https://github.com/cranci1/Sora.git
synced 2026-05-11 04:21:20 +00:00
thank god man thank god
Some checks are pending
Build and Release IPA / Build IPA (push) Waiting to run
Some checks are pending
Build and Release IPA / Build IPA (push) Waiting to run
This commit is contained in:
parent
3ebf986424
commit
ac66da899c
3 changed files with 107 additions and 18 deletions
|
|
@ -70,9 +70,9 @@ class JSController: ObservableObject {
|
||||||
}.resume()
|
}.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchDetails(url: String, completion: @escaping ([MediaItem]) -> Void) {
|
func fetchDetails(url: String, completion: @escaping ([MediaItem], [EpisodeLink]) -> Void) {
|
||||||
guard let url = URL(string: url) else {
|
guard let url = URL(string: url) else {
|
||||||
completion([])
|
completion([], [])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,31 +81,43 @@ class JSController: ObservableObject {
|
||||||
|
|
||||||
if let error = error {
|
if let error = error {
|
||||||
print("Network error: \(error)")
|
print("Network error: \(error)")
|
||||||
DispatchQueue.main.async { completion([]) }
|
DispatchQueue.main.async { completion([], []) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let data = data, let html = String(data: data, encoding: .utf8) else {
|
guard let data = data, let html = String(data: data, encoding: .utf8) else {
|
||||||
print("Failed to decode HTML")
|
print("Failed to decode HTML")
|
||||||
DispatchQueue.main.async { completion([]) }
|
DispatchQueue.main.async { completion([], []) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resultItems: [MediaItem] = []
|
||||||
|
var episodeLinks: [EpisodeLink] = []
|
||||||
|
|
||||||
if let parseFunction = self.context.objectForKeyedSubscript("extractDetails"),
|
if let parseFunction = self.context.objectForKeyedSubscript("extractDetails"),
|
||||||
let results = parseFunction.call(withArguments: [html]).toArray() as? [[String: String]] {
|
let results = parseFunction.call(withArguments: [html]).toArray() as? [[String: String]] {
|
||||||
let resultItems = results.map { item in
|
resultItems = results.map { item in
|
||||||
MediaItem(
|
MediaItem(
|
||||||
description: item["description"] ?? "",
|
description: item["description"] ?? "",
|
||||||
aliases: item["aliases"] ?? "",
|
aliases: item["aliases"] ?? "",
|
||||||
airdate: item["airdate"] ?? ""
|
airdate: item["airdate"] ?? ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DispatchQueue.main.async {
|
|
||||||
completion(resultItems)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
print("Failed to parse results")
|
print("Failed to parse results")
|
||||||
DispatchQueue.main.async { completion([]) }
|
}
|
||||||
|
|
||||||
|
if let fetchEpisodesFunction = self.context.objectForKeyedSubscript("extractEpisodes"),
|
||||||
|
let episodesResult = fetchEpisodesFunction.call(withArguments: [html]).toArray() as? [[String: String]] {
|
||||||
|
for episodeData in episodesResult {
|
||||||
|
if let num = episodeData["number"], let link = episodeData["href"], let number = Int(num) {
|
||||||
|
episodeLinks.append(EpisodeLink(number: number, href: link))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
completion(resultItems, episodeLinks)
|
||||||
}
|
}
|
||||||
}.resume()
|
}.resume()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,15 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
|
|
||||||
|
struct EpisodeLink: Identifiable {
|
||||||
|
let id = UUID()
|
||||||
|
let number: Int
|
||||||
|
let href: String
|
||||||
|
}
|
||||||
|
|
||||||
struct EpisodeCell: View {
|
struct EpisodeCell: View {
|
||||||
let episode: String
|
let episode: String
|
||||||
let episodeID: Int
|
let episodeID: Int
|
||||||
let imageUrl: String
|
|
||||||
let progress: Double
|
let progress: Double
|
||||||
let itemID: Int
|
let itemID: Int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,8 @@ struct MediaInfoView: View {
|
||||||
@State var aliases: String = ""
|
@State var aliases: String = ""
|
||||||
@State var synopsis: String = ""
|
@State var synopsis: String = ""
|
||||||
@State var airdate: String = ""
|
@State var airdate: String = ""
|
||||||
@State var genres: [String] = []
|
@State var episodeLinks: [EpisodeLink] = []
|
||||||
@State var episodes: [String] = []
|
@State var itemID: Int?
|
||||||
|
|
||||||
@State var isLoading: Bool = true
|
@State var isLoading: Bool = true
|
||||||
@State var showFullSynopsis: Bool = false
|
@State var showFullSynopsis: Bool = false
|
||||||
|
|
||||||
|
|
@ -132,32 +131,57 @@ struct MediaInfoView: View {
|
||||||
.frame(width: 20, height: 27)
|
.frame(width: 20, height: 27)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !episodeLinks.isEmpty {
|
||||||
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
|
Text("Episodes")
|
||||||
|
.font(.system(size: 18))
|
||||||
|
.fontWeight(.bold)
|
||||||
|
|
||||||
|
ForEach(episodeLinks.indices, id: \.self) { i in
|
||||||
|
let ep = episodeLinks[i]
|
||||||
|
let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(ep.href)")
|
||||||
|
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(ep.href)")
|
||||||
|
let progress = totalTime > 0 ? lastPlayedTime / totalTime : 0
|
||||||
|
|
||||||
|
EpisodeCell(episode: ep.href, episodeID: ep.number - 1, progress: progress, itemID: itemID ?? 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationBarTitle(title)
|
.navigationBarTitle("")
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
.navigationViewStyle(StackNavigationViewStyle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
getDetails()
|
fetchDetails()
|
||||||
|
fetchItemID(byTitle: title) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let id):
|
||||||
|
itemID = id
|
||||||
|
case .failure(let error):
|
||||||
|
print("Failed to fetch Item ID: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDetails() {
|
func fetchDetails() {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
let jsContent = try moduleManager.getModuleContent(module)
|
let jsContent = try moduleManager.getModuleContent(module)
|
||||||
jsController.loadScript(jsContent)
|
jsController.loadScript(jsContent)
|
||||||
jsController.fetchDetails(url: href) { items in
|
jsController.fetchDetails(url: href) { items, episodes in
|
||||||
if let item = items.first {
|
if let item = items.first {
|
||||||
print("Fetched item: \(item)")
|
|
||||||
self.synopsis = item.description
|
self.synopsis = item.description
|
||||||
self.aliases = item.aliases
|
self.aliases = item.aliases
|
||||||
self.airdate = item.airdate
|
self.airdate = item.airdate
|
||||||
}
|
}
|
||||||
|
self.episodeLinks = episodes
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -167,4 +191,52 @@ struct MediaInfoView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func fetchItemID(byTitle title: String, completion: @escaping (Result<Int, Error>) -> Void) {
|
||||||
|
let query = """
|
||||||
|
query {
|
||||||
|
Media(search: "\(title)", type: ANIME) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
guard let url = URL(string: "https://graphql.anilist.co") else {
|
||||||
|
completion(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
|
let parameters: [String: Any] = ["query": query]
|
||||||
|
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
|
||||||
|
|
||||||
|
URLSession.custom.dataTask(with: request) { data, _, error in
|
||||||
|
if let error = error {
|
||||||
|
completion(.failure(error))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let data = data else {
|
||||||
|
completion(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data received"])))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
||||||
|
let data = json["data"] as? [String: Any],
|
||||||
|
let media = data["Media"] as? [String: Any],
|
||||||
|
let id = media["id"] as? Int {
|
||||||
|
completion(.success(id))
|
||||||
|
} else {
|
||||||
|
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}.resume()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue