diff --git a/Sora/Tracking Services/TMDB/TMDBEpisodeMetadata.swift b/Sora/Tracking Services/TMDB/TMDBEpisodeMetadata.swift deleted file mode 100644 index 00922aa..0000000 --- a/Sora/Tracking Services/TMDB/TMDBEpisodeMetadata.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// TMDBEpisodeMetadata.swift -// Sora -// -// Created by Francesco on 05/01/25. -// - -import Foundation - -struct TMDBEpisodeMetadata: Codable { - let title: String - let imageUrl: String - let tmdbId: Int - let seasonNumber: Int - let episodeNumber: Int - let cacheDate: Date - - var cacheKey: String { - return "tmdb_\(tmdbId)_s\(seasonNumber)_e\(episodeNumber)" - } - - init(title: String, imageUrl: String, tmdbId: Int, seasonNumber: Int, episodeNumber: Int) { - self.title = title - self.imageUrl = imageUrl - self.tmdbId = tmdbId - self.seasonNumber = seasonNumber - self.episodeNumber = episodeNumber - self.cacheDate = Date() - } - - func toData() -> Data? { - return try? JSONEncoder().encode(self) - } - - static func fromData(_ data: Data) -> TMDBEpisodeMetadata? { - return try? JSONDecoder().decode(TMDBEpisodeMetadata.self, from: data) - } -} diff --git a/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift b/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift index e6bb1e3..f87051f 100644 --- a/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift +++ b/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift @@ -26,7 +26,6 @@ struct EpisodeCell: View { var module: ScrapingModule var parentTitle: String var showPosterURL: String? - var tmdbID: Int? var isMultiSelectMode: Bool = false var isSelected: Bool = false @@ -75,7 +74,6 @@ struct EpisodeCell: View { init(episodeIndex: Int, episode: String, episodeID: Int, progress: Double, itemID: Int, totalEpisodes: Int? = nil, defaultBannerImage: String = "", module: ScrapingModule, parentTitle: String, showPosterURL: String? = nil, - tmdbID: Int? = nil, isMultiSelectMode: Bool = false, isSelected: Bool = false, onSelectionChanged: ((Bool) -> Void)? = nil, onTap: @escaping (String) -> Void, onMarkAllPrevious: @escaping () -> Void) { @@ -85,7 +83,6 @@ struct EpisodeCell: View { self.progress = progress self.itemID = itemID self.totalEpisodes = totalEpisodes - self.tmdbID = tmdbID let isLightMode = (UserDefaults.standard.string(forKey: "selectedAppearance") == "light") || ((UserDefaults.standard.string(forKey: "selectedAppearance") == "system") && @@ -129,10 +126,6 @@ struct EpisodeCell: View { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { fetchAnimeEpisodeDetails() } - } else if tmdbID != nil { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - fetchTMDBEpisodeDetails() - } } else { isLoading = false } @@ -532,28 +525,6 @@ struct EpisodeCell: View { } private func fetchEpisodeDetails() { - if let tmdbID = tmdbID, - MetadataCacheManager.shared.isCachingEnabled && - (UserDefaults.standard.object(forKey: "fetchEpisodeMetadata") == nil || - UserDefaults.standard.bool(forKey: "fetchEpisodeMetadata")) { - - let seasonNumber = 1 - let episodeNumber = episodeID + 1 - let cacheKey = "tmdb_\(tmdbID)_s\(seasonNumber)_e\(episodeNumber)" - - if let cachedData = MetadataCacheManager.shared.getMetadata(forKey: cacheKey), - let metadata = TMDBEpisodeMetadata.fromData(cachedData) { - - DispatchQueue.main.async { - self.episodeTitle = metadata.title - self.episodeImageUrl = metadata.imageUrl - self.isLoading = false - self.loadedFromCache = true - } - return - } - } - if MetadataCacheManager.shared.isCachingEnabled && (UserDefaults.standard.object(forKey: "fetchEpisodeMetadata") == nil || UserDefaults.standard.bool(forKey: "fetchEpisodeMetadata")) { @@ -573,13 +544,7 @@ struct EpisodeCell: View { } } - if let type = module.metadata.type?.lowercased(), type == "anime" { - fetchAnimeEpisodeDetails() - } else if tmdbID != nil { - fetchTMDBEpisodeDetails() - } else { - isLoading = false - } + fetchAnimeEpisodeDetails() } private func fetchAnimeEpisodeDetails() { @@ -694,103 +659,6 @@ struct EpisodeCell: View { }.resume() } - private func fetchTMDBEpisodeDetails() { - guard let tmdbID = tmdbID else { - isLoading = false - return - } - let seasonNumber = 1 - let episodeNumber = episodeID + 1 - - guard let url = URL(string: "https://api.themoviedb.org/3/tv/\(tmdbID)/season/\(seasonNumber)/episode/\(episodeNumber)?api_key=eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI3MzhiNGVkZDBhMTU2Y2MxMjZkYzRhNGI4YWVhNGFjYSIsIm5iZiI6MTc0MTE3MzcwMi43ODcwMDAyLCJzdWIiOiI2N2M4MzNjNmQ3NDE5Y2RmZDg2ZTJkZGYiLCJzY29wZXMiOlsiYXBpX3JlYWQiXSwidmVyc2lvbiI6MX0.Gfe7F-8CWJXgONv34mg3jHXfL6Bxbj-hAYf9fYi9CkE") else { - isLoading = false - Logger.shared.log("Invalid TMDB URL for show ID: \(tmdbID)", type: "Error") - return - } - - if retryAttempts > 0 { - Logger.shared.log("Retrying TMDB episode details fetch (attempt \(retryAttempts)/\(maxRetryAttempts))", type: "Debug") - } - - 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") - self.handleFetchFailure(error: error) - return - } - - guard let data = data else { - self.handleFetchFailure(error: NSError(domain: "com.sora.episode", code: 1, userInfo: [NSLocalizedDescriptionKey: "No data received"])) - return - } - - do { - guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { - self.handleFetchFailure(error: NSError(domain: "com.sora.episode", code: 2, userInfo: [NSLocalizedDescriptionKey: "Invalid JSON format"])) - return - } - - var title = "" - var image = "" - var missingFields: [String] = [] - - if let episodeTitle = json["name"] as? String, !episodeTitle.isEmpty { - title = episodeTitle - } else { - missingFields.append("name") - } - - if let stillPath = json["still_path"] as? String, !stillPath.isEmpty { - image = "https://image.tmdb.org/t/p/w500\(stillPath)" - } else { - missingFields.append("still_path") - } - - if !missingFields.isEmpty { - Logger.shared.log("TMDB Episode \(episodeNumber) missing fields: \(missingFields.joined(separator: ", "))", type: "Warning") - } - - // Cache TMDB episode metadata - if MetadataCacheManager.shared.isCachingEnabled && (!title.isEmpty || !image.isEmpty) { - let metadata = TMDBEpisodeMetadata( - title: title, - imageUrl: image, - tmdbId: tmdbID, - seasonNumber: seasonNumber, - episodeNumber: episodeNumber - ) - - if let metadataData = metadata.toData() { - MetadataCacheManager.shared.storeMetadata( - metadataData, - forKey: metadata.cacheKey - ) - } - } - - DispatchQueue.main.async { - self.isLoading = false - self.retryAttempts = 0 - - if UserDefaults.standard.object(forKey: "fetchEpisodeMetadata") == nil - || UserDefaults.standard.bool(forKey: "fetchEpisodeMetadata") { - self.episodeTitle = title - - if !image.isEmpty { - self.episodeImageUrl = image - } - } - } - } catch { - Logger.shared.log("TMDB JSON parsing error: \(error.localizedDescription)", type: "Error") - DispatchQueue.main.async { - self.isLoading = false - self.retryAttempts = 0 - } - } - }.resume() - } - private func handleFetchFailure(error: Error) { Logger.shared.log("Episode details fetch error: \(error.localizedDescription)", type: "Error") diff --git a/Sora/Views/MediaInfoView/MediaInfoView.swift b/Sora/Views/MediaInfoView/MediaInfoView.swift index b6bdeb8..6535427 100644 --- a/Sora/Views/MediaInfoView/MediaInfoView.swift +++ b/Sora/Views/MediaInfoView/MediaInfoView.swift @@ -122,7 +122,6 @@ struct MediaInfoView: View { itemID = savedID Logger.shared.log("Using custom AniList ID: \(savedID)", type: "Debug") } else { - // Try AniList first for anime fetchItemID(byTitle: cleanTitle(title)) { result in switch result { case .success(let id): @@ -132,16 +131,6 @@ struct MediaInfoView: View { AnalyticsManager.shared.sendEvent(event: "error", additionalData: ["error": error, "message": "Failed to fetch AniList ID"]) } } - - // Also try TMDB for series/movies - 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)") - } - } } selectedRange = 0..) -> Void) { - guard let encodedTitle = title.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), - let url = URL(string: "https://api.themoviedb.org/3/search/tv?api_key=eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI3MzhiNGVkZDBhMTU2Y2MxMjZkYzRhNGI4YWVhNGFjYSIsIm5iZiI6MTc0MTE3MzcwMi43ODcwMDAyLCJzdWIiOiI2N2M4MzNjNmQ3NDE5Y2RmZDg2ZTJkZGYiLCJzY29wZXMiOlsiYXBpX3JlYWQiXSwidmVyc2lvbiI6MX0.Gfe7F-8CWJXgONv34mg3jHXfL6Bxbj-hAYf9fYi9CkE&query=\(encodedTitle)") 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, options: []) 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 TMDB results found"]) - completion(.failure(error)) - } - } catch { - completion(.failure(error)) - } - }.resume() - } - private func showCustomIDAlert() { let alert = UIAlertController(title: "Set Custom AniList ID", message: "Enter the AniList ID for this media", preferredStyle: .alert) @@ -1186,34 +1123,6 @@ struct MediaInfoView: View { } } - private func showCustomTMDBIDAlert() { - let alert = UIAlertController(title: "Set Custom TMDB ID", message: "Enter the TMDB ID for this TV show", preferredStyle: .alert) - - alert.addTextField { textField in - textField.placeholder = "TMDB ID" - textField.keyboardType = .numberPad - if let tmdbID = tmdbID { - textField.text = "\(tmdbID)" - } - } - - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) - alert.addAction(UIAlertAction(title: "Save", style: .default) { _ in - if let text = alert.textFields?.first?.text, - let id = Int(text) { - tmdbID = id - UserDefaults.standard.set(id, forKey: "custom_tmdb_id_\(href)") - Logger.shared.log("Set custom TMDB ID: \(id)", type: "General") - } - }) - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let window = windowScene.windows.first, - let rootVC = window.rootViewController { - findTopViewController.findViewController(rootVC).present(alert, animated: true) - } - } - private func selectEpisodeRange(start: Int, end: Int) { selectedEpisodes.removeAll() for episodeNumber in start...end { diff --git a/Sulfur.xcodeproj/project.pbxproj b/Sulfur.xcodeproj/project.pbxproj index 4da8b48..b250456 100644 --- a/Sulfur.xcodeproj/project.pbxproj +++ b/Sulfur.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 132AF1232D9995C300A0140B /* JSController-Details.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132AF1222D9995C300A0140B /* JSController-Details.swift */; }; 132AF1252D9995F900A0140B /* JSController-Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132AF1242D9995F900A0140B /* JSController-Search.swift */; }; 132FC5B32DE31DAE009A80F7 /* SettingsViewAlternateAppIconPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132FC5B22DE31DAD009A80F7 /* SettingsViewAlternateAppIconPicker.swift */; }; - 132FC5B82DE33051009A80F7 /* TMDBEpisodeMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132FC5B72DE33051009A80F7 /* TMDBEpisodeMetadata.swift */; }; 133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6D2D2BE2500075467E /* SoraApp.swift */; }; 133D7C702D2BE2500075467E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6F2D2BE2500075467E /* ContentView.swift */; }; 133D7C722D2BE2520075467E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 133D7C712D2BE2520075467E /* Assets.xcassets */; }; @@ -99,7 +98,6 @@ 132AF1222D9995C300A0140B /* JSController-Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Details.swift"; sourceTree = ""; }; 132AF1242D9995F900A0140B /* JSController-Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Search.swift"; sourceTree = ""; }; 132FC5B22DE31DAD009A80F7 /* SettingsViewAlternateAppIconPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewAlternateAppIconPicker.swift; sourceTree = ""; }; - 132FC5B72DE33051009A80F7 /* TMDBEpisodeMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDBEpisodeMetadata.swift; sourceTree = ""; }; 133D7C6A2D2BE2500075467E /* Sulfur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sulfur.app; sourceTree = BUILT_PRODUCTS_DIR; }; 133D7C6D2D2BE2500075467E /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = ""; }; 133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -183,7 +181,6 @@ 13103E802D589D6C000F0673 /* Tracking Services */ = { isa = PBXGroup; children = ( - 132FC5B42DE33042009A80F7 /* TMDB */, 13E62FBF2DABC3A20007E259 /* Trakt */, 13103E812D589D77000F0673 /* AniList */, ); @@ -216,14 +213,6 @@ path = Analytics; sourceTree = ""; }; - 132FC5B42DE33042009A80F7 /* TMDB */ = { - isa = PBXGroup; - children = ( - 132FC5B72DE33051009A80F7 /* TMDBEpisodeMetadata.swift */, - ); - path = TMDB; - sourceTree = ""; - }; 133D7C612D2BE2500075467E = { isa = PBXGroup; children = ( @@ -627,7 +616,6 @@ 130C6BFA2D53AB1F00DC1432 /* SettingsViewData.swift in Sources */, 1E9FF1D32D403E49008AC100 /* SettingsViewLoggerFilter.swift in Sources */, 13EA2BD92D32D98400C1EBD7 /* NormalPlayer.swift in Sources */, - 132FC5B82DE33051009A80F7 /* TMDBEpisodeMetadata.swift in Sources */, 133D7C932D2BE2640075467E /* Modules.swift in Sources */, 13DB7CC32D7D99C0004371D3 /* SubtitleSettingsManager.swift in Sources */, 133D7C702D2BE2500075467E /* ContentView.swift in Sources */,