mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
instead of matched id being an int now its the actual name of the series (#190)
* removed double bs for id telling
* improved anilist logic, single episode anilist sync, anilist sync also avaiaiable with tmdb as provider, tmdb posters avaiabale with anilist as provider
* instead of telling the id of the match now it tells the name
* gotta release a testflight 🙏
This commit is contained in:
parent
c42d53f8f5
commit
ffeddb37e6
3 changed files with 67 additions and 82 deletions
|
|
@ -3,14 +3,13 @@
|
|||
// Sulfur
|
||||
//
|
||||
// Created by seiike on 01/06/2025.
|
||||
//
|
||||
|
||||
import NukeUI
|
||||
import SwiftUI
|
||||
|
||||
struct AnilistMatchPopupView: View {
|
||||
let seriesTitle: String
|
||||
let onSelect: (Int) -> Void
|
||||
let onSelect: (Int, String) -> Void
|
||||
|
||||
@State private var results: [[String: Any]] = []
|
||||
@State private var isLoading = true
|
||||
|
|
@ -52,10 +51,11 @@ struct AnilistMatchPopupView: View {
|
|||
LazyVStack(spacing: 15) {
|
||||
ForEach(results.indices, id: \.self) { index in
|
||||
let result = results[index]
|
||||
|
||||
Button(action: {
|
||||
if let id = result["id"] as? Int {
|
||||
onSelect(id)
|
||||
let title = result["title"] as? String ?? seriesTitle
|
||||
onSelect(id, title)
|
||||
dismiss()
|
||||
}
|
||||
}) {
|
||||
HStack(spacing: 12) {
|
||||
|
|
@ -81,7 +81,6 @@ struct AnilistMatchPopupView: View {
|
|||
Text(result["title"] as? String ?? "Unknown")
|
||||
.font(.body)
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
if let english = result["title_english"] as? String {
|
||||
Text(english)
|
||||
.font(.caption)
|
||||
|
|
@ -135,34 +134,32 @@ struct AnilistMatchPopupView: View {
|
|||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
Button("Cancel") { dismiss() }
|
||||
.foregroundColor(isLightMode ? .black : .white)
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button(action: {
|
||||
Button {
|
||||
manualIDText = ""
|
||||
showingManualIDAlert = true
|
||||
}) {
|
||||
} label: {
|
||||
Image(systemName: "number")
|
||||
.foregroundColor(isLightMode ? .black : .white)
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert("Set Custom AniList ID", isPresented: $showingManualIDAlert, actions: {
|
||||
.alert("Set Custom AniList ID", isPresented: $showingManualIDAlert) {
|
||||
TextField("AniList ID", text: $manualIDText)
|
||||
.keyboardType(.numberPad)
|
||||
Button("Cancel", role: .cancel) { }
|
||||
Button("Save", action: {
|
||||
Button("Save") {
|
||||
if let idInt = Int(manualIDText.trimmingCharacters(in: .whitespaces)) {
|
||||
onSelect(idInt)
|
||||
onSelect(idInt, seriesTitle)
|
||||
dismiss()
|
||||
}
|
||||
})
|
||||
}, message: {
|
||||
}
|
||||
} message: {
|
||||
Text("Enter the AniList ID for this series")
|
||||
})
|
||||
}
|
||||
}
|
||||
.onAppear(perform: fetchMatches)
|
||||
}
|
||||
|
|
@ -186,7 +183,6 @@ struct AnilistMatchPopupView: View {
|
|||
"""
|
||||
|
||||
guard let url = URL(string: "https://graphql.anilist.co") else { return }
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
|
|
@ -194,25 +190,23 @@ struct AnilistMatchPopupView: View {
|
|||
|
||||
URLSession.shared.dataTask(with: request) { data, _, _ in
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
|
||||
guard let data = data,
|
||||
isLoading = false
|
||||
guard
|
||||
let data = data,
|
||||
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||||
let dataDict = json["data"] as? [String: Any],
|
||||
let page = dataDict["Page"] as? [String: Any],
|
||||
let mediaList = page["media"] as? [[String: Any]] else {
|
||||
return
|
||||
}
|
||||
let mediaList = page["media"] as? [[String: Any]]
|
||||
else { return }
|
||||
|
||||
self.results = mediaList.map { media in
|
||||
results = mediaList.map { media in
|
||||
let titleInfo = media["title"] as? [String: Any]
|
||||
let cover = (media["coverImage"] as? [String: Any])?["large"] as? String
|
||||
|
||||
return [
|
||||
"id": media["id"] ?? 0,
|
||||
"title": titleInfo?["romaji"] ?? "Unknown",
|
||||
"title_english": titleInfo?["english"],
|
||||
"cover": cover
|
||||
"title_english": titleInfo?["english"] as Any,
|
||||
"cover": cover as Any
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
// Sulfur
|
||||
//
|
||||
// Created by seiike on 12/06/2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NukeUI
|
||||
|
||||
struct TMDBMatchPopupView: View {
|
||||
let seriesTitle: String
|
||||
let onSelect: (Int, TMDBFetcher.MediaType) -> Void
|
||||
let onSelect: (Int, TMDBFetcher.MediaType, String) -> Void
|
||||
|
||||
@State private var results: [ResultItem] = []
|
||||
@State private var isLoading = true
|
||||
|
|
@ -54,10 +53,10 @@ struct TMDBMatchPopupView: View {
|
|||
} else {
|
||||
LazyVStack(spacing: 15) {
|
||||
ForEach(results) { item in
|
||||
Button(action: {
|
||||
onSelect(item.id, item.mediaType)
|
||||
Button {
|
||||
onSelect(item.id, item.mediaType, item.title)
|
||||
dismiss()
|
||||
}) {
|
||||
} label: {
|
||||
HStack(spacing: 12) {
|
||||
if let poster = item.posterURL, let url = URL(string: poster) {
|
||||
LazyImage(url: url) { state in
|
||||
|
|
@ -112,9 +111,7 @@ struct TMDBMatchPopupView: View {
|
|||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
Button("Cancel") { dismiss() }
|
||||
}
|
||||
}
|
||||
.alert("Error Fetching Results", isPresented: $showingError) {
|
||||
|
|
@ -129,7 +126,6 @@ struct TMDBMatchPopupView: View {
|
|||
private func fetchMatches() {
|
||||
isLoading = true
|
||||
results = []
|
||||
|
||||
let fetcher = TMDBFetcher()
|
||||
let apiKey = fetcher.apiKey
|
||||
let dispatchGroup = DispatchGroup()
|
||||
|
|
@ -148,9 +144,10 @@ struct TMDBMatchPopupView: View {
|
|||
|
||||
URLSession.shared.dataTask(with: url) { data, _, error in
|
||||
defer { dispatchGroup.leave() }
|
||||
|
||||
guard error == nil, let data = data,
|
||||
let response = try? JSONDecoder().decode(TMDBSearchResponse.self, from: data) else {
|
||||
guard error == nil,
|
||||
let data = data,
|
||||
let response = try? JSONDecoder().decode(TMDBSearchResponse.self, from: data)
|
||||
else {
|
||||
encounteredError = true
|
||||
return
|
||||
}
|
||||
|
|
@ -165,10 +162,7 @@ struct TMDBMatchPopupView: View {
|
|||
}
|
||||
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
if encounteredError {
|
||||
showingError = true
|
||||
}
|
||||
// Keep API order (by popularity), limit to top 6 overall
|
||||
if encounteredError { showingError = true }
|
||||
results = Array(temp.prefix(6))
|
||||
isLoading = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -655,14 +655,17 @@ struct MediaInfoView: View {
|
|||
.circularGradientOutline()
|
||||
}
|
||||
.sheet(isPresented: $isMatchingPresented) {
|
||||
AnilistMatchPopupView(seriesTitle: title) { selectedID in
|
||||
handleAniListMatch(selectedID: selectedID)
|
||||
AnilistMatchPopupView(seriesTitle: title) { id, matched in
|
||||
handleAniListMatch(selectedID: id)
|
||||
matchedTitle = matched // ← now in scope
|
||||
fetchMetadataIDIfNeeded()
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $isTMDBMatchingPresented) {
|
||||
TMDBMatchPopupView(seriesTitle: title) { id, type in
|
||||
tmdbID = id; tmdbType = type
|
||||
TMDBMatchPopupView(seriesTitle: title) { id, type, matched in
|
||||
tmdbID = id
|
||||
tmdbType = type
|
||||
matchedTitle = matched // ← now in scope
|
||||
fetchMetadataIDIfNeeded()
|
||||
}
|
||||
}
|
||||
|
|
@ -671,17 +674,11 @@ struct MediaInfoView: View {
|
|||
@ViewBuilder
|
||||
private var menuContent: some View {
|
||||
Group {
|
||||
if let active = activeProvider {
|
||||
Text("Provider: \(active)")
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
.padding(.vertical, 4)
|
||||
Divider()
|
||||
}
|
||||
|
||||
Text("Matched ID: \(itemID ?? 0)")
|
||||
if let provider = activeProvider {
|
||||
Text("Matched \(provider): \(matchedTitle ?? title)")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
if activeProvider == "AniList" {
|
||||
Button("Match with AniList") {
|
||||
|
|
|
|||
Loading…
Reference in a new issue