diff --git a/Sora/Managers/EpisodeMetadataManager.swift b/Sora/Managers/EpisodeMetadataManager.swift index f7e79ca..05dc58d 100644 --- a/Sora/Managers/EpisodeMetadataManager.swift +++ b/Sora/Managers/EpisodeMetadataManager.swift @@ -280,6 +280,22 @@ class EpisodeMetadataManager: ObservableObject { ) // Cache the metadata + if MetadataCacheManager.shared.isCachingEnabled { + let metadata = EpisodeMetadata( + title: title, + imageUrl: image, + anilistId: anilistId, + episodeNumber: episodeNumber + ) + + if let metadataData = metadata.toData() { + MetadataCacheManager.shared.storeMetadata( + metadataData, + forKey: cacheKey + ) + Logger.shared.log("Cached metadata for episode \(episodeNumber)", type: "Debug") + } + } // Reset retry count on success (even with missing fields) self.currentRetryAttempts.removeValue(forKey: cacheKey) @@ -457,6 +473,22 @@ class EpisodeMetadataManager: ObservableObject { results[episodeNumber] = metadataInfo // Cache the metadata + if MetadataCacheManager.shared.isCachingEnabled { + let metadata = EpisodeMetadata( + title: title, + imageUrl: image, + anilistId: anilistId, + episodeNumber: episodeNumber + ) + + let cacheKey = "anilist_\(anilistId)_episode_\(episodeNumber)" + if let metadataData = metadata.toData() { + MetadataCacheManager.shared.storeMetadata( + metadataData, + forKey: cacheKey + ) + } + } } else { missingEpisodes.append(episodeNumber) } diff --git a/Sora/SoraApp.swift b/Sora/SoraApp.swift index 3c62d01..327720e 100644 --- a/Sora/SoraApp.swift +++ b/Sora/SoraApp.swift @@ -58,6 +58,7 @@ struct SoraApp: App { @StateObject private var jsController = JSController.shared init() { + _ = MetadataCacheManager.shared _ = KingfisherCacheManager.shared if let userAccentColor = UserDefaults.standard.color(forKey: "accentColor") { diff --git a/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift b/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift index a5dcc30..75a36cf 100644 --- a/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift +++ b/Sora/Views/MediaInfoView/EpisodeCell/EpisodeCell.swift @@ -732,6 +732,25 @@ struct EpisodeCell: View { } private func fetchEpisodeDetails() { + if MetadataCacheManager.shared.isCachingEnabled && + (UserDefaults.standard.object(forKey: "fetchEpisodeMetadata") == nil || + UserDefaults.standard.bool(forKey: "fetchEpisodeMetadata")) { + + let cacheKey = "anilist_\(itemID)_episode_\(episodeID + 1)" + + if let cachedData = MetadataCacheManager.shared.getMetadata(forKey: cacheKey), + let metadata = EpisodeMetadata.fromData(cachedData) { + + DispatchQueue.main.async { + self.episodeTitle = metadata.title["en"] ?? "" + self.episodeImageUrl = metadata.imageUrl + self.isLoading = false + self.loadedFromCache = true + } + return + } + } + fetchAnimeEpisodeDetails() } @@ -808,6 +827,21 @@ struct EpisodeCell: View { Logger.shared.log("Episode \(episodeKey) missing fields: \(missingFields.joined(separator: ", "))", type: "Warning") } + if MetadataCacheManager.shared.isCachingEnabled && (!title.isEmpty || !image.isEmpty) { + let metadata = EpisodeMetadata( + title: title, + imageUrl: image, + anilistId: self.itemID, + episodeNumber: self.episodeID + 1 + ) + + if let metadataData = metadata.toData() { + MetadataCacheManager.shared.storeMetadata( + metadataData, + forKey: metadata.cacheKey + ) + } + } DispatchQueue.main.async { self.isLoading = false diff --git a/Sora/Views/MediaInfoView/MediaInfoView.swift b/Sora/Views/MediaInfoView/MediaInfoView.swift index 707c94b..cab346c 100644 --- a/Sora/Views/MediaInfoView/MediaInfoView.swift +++ b/Sora/Views/MediaInfoView/MediaInfoView.swift @@ -1891,6 +1891,24 @@ struct MediaInfoView: View { return } + if MetadataCacheManager.shared.isCachingEnabled { + let cacheKey = "anilist_\(anilistId)_episode_\(episode.number)" + + if let cachedData = MetadataCacheManager.shared.getMetadata(forKey: cacheKey), + let metadata = EpisodeMetadata.fromData(cachedData) { + + print("[Bulk Download] Using cached metadata for episode \(episode.number)") + let metadataInfo = EpisodeMetadataInfo( + title: metadata.title, + imageUrl: metadata.imageUrl, + anilistId: metadata.anilistId, + episodeNumber: metadata.episodeNumber + ) + completion(metadataInfo) + return + } + } + fetchEpisodeMetadataFromNetwork(anilistId: anilistId, episodeNumber: episode.number, completion: completion) } @@ -1949,6 +1967,22 @@ struct MediaInfoView: View { if let imageUrl = episodeDetails["image"] as? String, !imageUrl.isEmpty { image = imageUrl } + if MetadataCacheManager.shared.isCachingEnabled { + let metadata = EpisodeMetadata( + title: title, + imageUrl: image, + anilistId: anilistId, + episodeNumber: episodeNumber + ) + + let cacheKey = "anilist_\(anilistId)_episode_\(episodeNumber)" + if let metadataData = metadata.toData() { + MetadataCacheManager.shared.storeMetadata( + metadataData, + forKey: cacheKey + ) + } + } let metadataInfo = EpisodeMetadataInfo( title: title, diff --git a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewData.swift b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewData.swift index 6008bb7..53b155f 100644 --- a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewData.swift +++ b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewData.swift @@ -169,7 +169,7 @@ struct SettingsViewData: View { isOn: $isMetadataCachingEnabled ) .onChange(of: isMetadataCachingEnabled) { newValue in - // MetadataCacheManager removed + MetadataCacheManager.shared.isCachingEnabled = newValue if !newValue { calculateCacheSize() } @@ -194,8 +194,9 @@ struct SettingsViewData: View { isOn: $isMemoryOnlyMode ) .onChange(of: isMemoryOnlyMode) { newValue in - // MetadataCacheManager removed + MetadataCacheManager.shared.isMemoryOnlyMode = newValue if newValue { + MetadataCacheManager.shared.clearAllCache() calculateCacheSize() } } @@ -273,7 +274,9 @@ struct SettingsViewData: View { .scrollViewBottomPadding() .navigationTitle("App Data") .onAppear { + isMetadataCachingEnabled = MetadataCacheManager.shared.isCachingEnabled isImageCachingEnabled = KingfisherCacheManager.shared.isCachingEnabled + isMemoryOnlyMode = MetadataCacheManager.shared.isMemoryOnlyMode calculateCacheSize() updateSizes() } @@ -316,6 +319,9 @@ struct SettingsViewData: View { cacheSizeText = "Calculating..." DispatchQueue.global(qos: .background).async { var totalSize: Int64 = 0 + let metadataSize = MetadataCacheManager.shared.getCacheSize() + totalSize += metadataSize + KingfisherCacheManager.shared.calculateCacheSize { imageSize in totalSize += Int64(imageSize) DispatchQueue.main.async { @@ -327,7 +333,7 @@ struct SettingsViewData: View { } func clearAllCaches() { - // MetadataCacheManager removed + MetadataCacheManager.shared.clearAllCache() KingfisherCacheManager.shared.clearCache { calculateCacheSize() }