mirror of
https://github.com/cranci1/Sora.git
synced 2026-04-19 15:42:09 +00:00
added TMDB support
This commit is contained in:
parent
5dfacc8db4
commit
c256388497
2 changed files with 152 additions and 9 deletions
|
|
@ -20,6 +20,8 @@ struct EpisodeCell: View {
|
|||
let episodeID: Int
|
||||
let progress: Double
|
||||
let itemID: Int
|
||||
let isAnime: Bool
|
||||
let tmdbID: Int?
|
||||
|
||||
let onTap: (String) -> Void
|
||||
let onMarkAllPrevious: () -> Void
|
||||
|
|
@ -29,6 +31,20 @@ struct EpisodeCell: View {
|
|||
@State private var isLoading: Bool = true
|
||||
@State private var currentProgress: Double = 0.0
|
||||
|
||||
init(episodeIndex: Int, episode: String, episodeID: Int, progress: Double,
|
||||
itemID: Int, isAnime: Bool = true, tmdbID: Int? = nil,
|
||||
onTap: @escaping (String) -> Void, onMarkAllPrevious: @escaping () -> Void) {
|
||||
self.episodeIndex = episodeIndex
|
||||
self.episode = episode
|
||||
self.episodeID = episodeID
|
||||
self.progress = progress
|
||||
self.itemID = itemID
|
||||
self.isAnime = isAnime
|
||||
self.tmdbID = tmdbID
|
||||
self.onTap = onTap
|
||||
self.onMarkAllPrevious = onMarkAllPrevious
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ZStack {
|
||||
|
|
@ -124,6 +140,14 @@ struct EpisodeCell: View {
|
|||
}
|
||||
|
||||
private func fetchEpisodeDetails() {
|
||||
if isAnime {
|
||||
fetchAnimeEpisodeDetails()
|
||||
} else {
|
||||
fetchTMDBEpisodeDetails()
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchAnimeEpisodeDetails() {
|
||||
guard let url = URL(string: "https://api.ani.zip/mappings?anilist_id=\(itemID)") else {
|
||||
isLoading = false
|
||||
return
|
||||
|
|
@ -131,7 +155,7 @@ struct EpisodeCell: View {
|
|||
|
||||
URLSession.custom.dataTask(with: url) { data, _, error in
|
||||
if let error = error {
|
||||
Logger.shared.log("Failed to fetch episode details: \(error)", type: "Error")
|
||||
Logger.shared.log("Failed to fetch anime episode details: \(error)", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
|
|
@ -152,7 +176,7 @@ struct EpisodeCell: View {
|
|||
let episodeDetails = episodes["\(episodeID + 1)"] as? [String: Any],
|
||||
let title = episodeDetails["title"] as? [String: String],
|
||||
let image = episodeDetails["image"] as? String else {
|
||||
Logger.shared.log("Invalid response format", type: "Error")
|
||||
Logger.shared.log("Invalid anime response format", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
|
|
@ -171,4 +195,66 @@ struct EpisodeCell: View {
|
|||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
private func fetchTMDBEpisodeDetails() {
|
||||
guard let tmdbID = tmdbID else {
|
||||
isLoading = false
|
||||
return
|
||||
}
|
||||
|
||||
let seasonNumber = 1
|
||||
let apiKey = "738b4edd0a156cc126dc4a4b8aea4aca"
|
||||
let urlString = "https://api.themoviedb.org/3/tv/\(tmdbID)/season/\(seasonNumber)/episode/\(episodeID + 1)?api_key=\(apiKey)"
|
||||
|
||||
guard let url = URL(string: urlString) else {
|
||||
isLoading = false
|
||||
return
|
||||
}
|
||||
|
||||
URLSession.custom.dataTask(with: url) { data, response, error in
|
||||
if let error = error {
|
||||
Logger.shared.log("Failed to fetch TMDB episode details: \(error)", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
|
||||
guard let episodeDetails = jsonObject as? [String: Any],
|
||||
let name = episodeDetails["name"] as? String else {
|
||||
Logger.shared.log("Invalid TMDB response format", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let imageBasePath = "https://image.tmdb.org/t/p/w300"
|
||||
var imageUrl = ""
|
||||
if let stillPath = episodeDetails["still_path"] as? String {
|
||||
imageUrl = imageBasePath + stillPath
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.episodeTitle = name
|
||||
self.episodeImageUrl = imageUrl
|
||||
self.isLoading = false
|
||||
}
|
||||
} catch {
|
||||
Logger.shared.log("Error parsing TMDB data: \(error)", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ struct MediaInfoView: View {
|
|||
@State var airdate: String = ""
|
||||
@State var episodeLinks: [EpisodeLink] = []
|
||||
@State var itemID: Int?
|
||||
@State var tmdbID: Int?
|
||||
|
||||
@State var isLoading: Bool = true
|
||||
@State var showFullSynopsis: Bool = false
|
||||
|
|
@ -240,6 +241,8 @@ struct MediaInfoView: View {
|
|||
episodeID: ep.number - 1,
|
||||
progress: progress,
|
||||
itemID: itemID ?? 0,
|
||||
isAnime: module.metadata.type?.lowercased() == "anime",
|
||||
tmdbID: tmdbID,
|
||||
onTap: { imageUrl in
|
||||
if !isFetchingEpisode {
|
||||
selectedEpisodeNumber = ep.number
|
||||
|
|
@ -290,6 +293,8 @@ struct MediaInfoView: View {
|
|||
episodeID: ep.number - 1,
|
||||
progress: progress,
|
||||
itemID: itemID ?? 0,
|
||||
isAnime: module.metadata.type?.lowercased() == "anime",
|
||||
tmdbID: tmdbID,
|
||||
onTap: { imageUrl in
|
||||
if !isFetchingEpisode {
|
||||
selectedEpisodeNumber = ep.number
|
||||
|
|
@ -370,15 +375,29 @@ struct MediaInfoView: View {
|
|||
if !hasFetched {
|
||||
DropManager.shared.showDrop(title: "Fetching Data", subtitle: "Please wait while fetching.", duration: 0.5, icon: UIImage(systemName: "arrow.triangle.2.circlepath"))
|
||||
fetchDetails()
|
||||
fetchItemID(byTitle: cleanTitle(title)) { result in
|
||||
switch result {
|
||||
case .success(let id):
|
||||
itemID = id
|
||||
case .failure(let error):
|
||||
Logger.shared.log("Failed to fetch Item ID: \(error)")
|
||||
AnalyticsManager.shared.sendEvent(event: "error", additionalData: ["error": error, "message": "Failed to fetch Item ID"])
|
||||
|
||||
if module.metadata.type == "anime" {
|
||||
fetchItemID(byTitle: cleanTitle(title)) { result in
|
||||
switch result {
|
||||
case .success(let id):
|
||||
itemID = id
|
||||
case .failure(let error):
|
||||
Logger.shared.log("Failed to fetch AniList ID: \(error)")
|
||||
AnalyticsManager.shared.sendEvent(event: "error", additionalData: ["error": error, "message": "Failed to fetch AniList ID"])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fetchTMDBID(byTitle: cleanTitle(title)) { result in
|
||||
switch result {
|
||||
case .success(let id):
|
||||
tmdbID = id
|
||||
case .failure(let error):
|
||||
Logger.shared.log("Failed to fetch TMDB ID: \(error)")
|
||||
AnalyticsManager.shared.sendEvent(event: "error", additionalData: ["error": error, "message": "Failed to fetch TMDB ID"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasFetched = true
|
||||
AnalyticsManager.shared.sendEvent(event: "search", additionalData: ["title": title])
|
||||
}
|
||||
|
|
@ -831,4 +850,42 @@ struct MediaInfoView: View {
|
|||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
private func fetchTMDBID(byTitle title: String, completion: @escaping (Result<Int, Error>) -> Void) {
|
||||
let encodedTitle = title.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
|
||||
let apiKey = "738b4edd0a156cc126dc4a4b8aea4aca"
|
||||
|
||||
let urlString = "https://api.themoviedb.org/3/search/multi?api_key=\(apiKey)&query=\(encodedTitle)"
|
||||
|
||||
guard let url = URL(string: urlString) else {
|
||||
completion(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])))
|
||||
return
|
||||
}
|
||||
|
||||
URLSession.custom.dataTask(with: url) { 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) as? [String: Any],
|
||||
let results = json["results"] as? [[String: Any]],
|
||||
let firstResult = results.first,
|
||||
let id = firstResult["id"] as? Int {
|
||||
completion(.success(id))
|
||||
} else {
|
||||
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "No matching TMDB content found"])
|
||||
completion(.failure(error))
|
||||
}
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue