From d0a622c2b78824aa07e624be13c8abd8e0b9c092 Mon Sep 17 00:00:00 2001 From: cranci1 <100066266+cranci1@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:30:44 +0200 Subject: [PATCH] Revert "yeah i dont even know what is this" This reverts commit 3478a3f11e3592df4fe99380a153bd3f63c8636c. --- Sora/Views/MediaInfoView/MediaInfoView.swift | 274 ++++--------------- 1 file changed, 60 insertions(+), 214 deletions(-) diff --git a/Sora/Views/MediaInfoView/MediaInfoView.swift b/Sora/Views/MediaInfoView/MediaInfoView.swift index ee6f38a..851ea18 100644 --- a/Sora/Views/MediaInfoView/MediaInfoView.swift +++ b/Sora/Views/MediaInfoView/MediaInfoView.swift @@ -18,12 +18,6 @@ struct MediaItem: Identifiable { let airdate: String } -extension EpisodeLink: Equatable { - static func == (lhs: EpisodeLink, rhs: EpisodeLink) -> Bool { - return lhs.href == rhs.href && lhs.number == rhs.number - } -} - struct MediaInfoView: View { let title: String @State var imageUrl: String @@ -92,24 +86,8 @@ struct MediaInfoView: View { @State private var bulkDownloadProgress: String = "" @State private var tmdbType: TMDBFetcher.MediaType? = nil - @State private var cachedGroupedEpisodes: [[EpisodeLink]] = [] - @State private var cachedRanges: [Range] = [] - @State private var cachedBannerImage: String = "" - @State private var lastEpisodeCount: Int = 0 - @State private var lastChunkSize: Int = 0 - - @State private var viewState: ViewState = .loading - - enum ViewState { - case loading - case loaded - case error - } - - @State private var currentTasks: Set> = [] - private var isGroupedBySeasons: Bool { - return cachedGroupedEpisodes.count > 1 + return groupedEpisodes().count > 1 } private var isCompactLayout: Bool { @@ -134,14 +112,11 @@ struct MediaInfoView: View { var body: some View { ZStack { Group { - switch viewState { - case .loading: + if isLoading { ProgressView() .padding() - case .loaded: + } else { mainScrollView - case .error: - errorView } } .navigationBarHidden(true) @@ -149,7 +124,6 @@ struct MediaInfoView: View { .onAppear { buttonRefreshTrigger.toggle() tabBarController.hideTabBar() - updateCachedBannerImage() } .onChange(of: selectedRange) { newValue in UserDefaults.standard.set(newValue.lowerBound, forKey: selectedRangeKey) @@ -157,15 +131,8 @@ struct MediaInfoView: View { .onChange(of: selectedSeason) { newValue in UserDefaults.standard.set(newValue, forKey: selectedSeasonKey) } - .onChange(of: episodeLinks.count) { _ in - updateCachedComputations() - } - .onChange(of: episodeChunkSize) { _ in - updateCachedComputations() - } .onDisappear(){ tabBarController.showTabBar() - cancelAllTasks() } .task { guard !hasFetched else { return } @@ -177,19 +144,13 @@ struct MediaInfoView: View { } DropManager.shared.showDrop(title: "Fetching Data", subtitle: "Please wait while fetching.", duration: 0.5, icon: UIImage(systemName: "arrow.triangle.2.circlepath")) - - let fetchTask = Task { - await fetchDetailsAsync() - - if !Task.isCancelled { - if savedCustomID != 0 { - itemID = savedCustomID - } else { - await fetchMetadataIDIfNeededAsync() - } - } + fetchDetails() + + if savedCustomID != 0 { + itemID = savedCustomID + } else { + fetchMetadataIDIfNeeded() } - currentTasks.insert(fetchTask) hasFetched = true AnalyticsManager.shared.sendEvent( @@ -214,7 +175,6 @@ struct MediaInfoView: View { activeFetchID = nil isFetchingEpisode = false showStreamLoadingView = false - cancelAllTasks() } VStack { @@ -240,29 +200,6 @@ struct MediaInfoView: View { } } - @ViewBuilder - private var errorView: some View { - VStack(spacing: 16) { - Image(systemName: "exclamationmark.triangle") - .font(.system(size: 48)) - .foregroundColor(.secondary) - - Text("Failed to Load") - .font(.title2) - .fontWeight(.semibold) - - Button("Retry") { - viewState = .loading - let retryTask = Task { - await fetchDetailsAsync() - } - currentTasks.insert(retryTask) - } - .buttonStyle(.borderedProminent) - } - .padding() - } - @ViewBuilder private var mainScrollView: some View { ScrollView { @@ -282,7 +219,6 @@ struct MediaInfoView: View { .clipped() } } - .id("hero-image-\(imageUrl)") VStack(spacing: 0) { Rectangle() @@ -701,7 +637,7 @@ struct MediaInfoView: View { .foregroundColor(.accentColor) } } else if isGroupedBySeasons { - let seasons = cachedGroupedEpisodes + let seasons = groupedEpisodes() if seasons.count > 1 { Menu { ForEach(0.. 0 ? lastPlayedTime / totalTime : 0 + let defaultBannerImageValue = getBannerImageBasedOnAppearance() + EpisodeCell( episodeIndex: i, episode: ep.href, @@ -746,7 +684,7 @@ struct MediaInfoView: View { progress: progress, itemID: itemID ?? 0, totalEpisodes: episodeLinks.count, - defaultBannerImage: cachedBannerImage, + defaultBannerImage: defaultBannerImageValue, module: module, parentTitle: title, showPosterURL: imageUrl, @@ -768,21 +706,23 @@ struct MediaInfoView: View { tmdbID: tmdbID, seasonNumber: 1 ) - .id("episode-\(ep.href)-\(isMultiSelectMode)") - .disabled(isFetchingEpisode) + .disabled(isFetchingEpisode) } } } @ViewBuilder private var seasonsEpisodeList: some View { - if !cachedGroupedEpisodes.isEmpty, selectedSeason < cachedGroupedEpisodes.count { + let seasons = groupedEpisodes() + if !seasons.isEmpty, selectedSeason < seasons.count { LazyVStack(spacing: 15) { - ForEach(cachedGroupedEpisodes[selectedSeason], id: \.href) { ep in + ForEach(seasons[selectedSeason]) { ep in 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 + let defaultBannerImageValue = getBannerImageBasedOnAppearance() + EpisodeCell( episodeIndex: selectedSeason, episode: ep.href, @@ -790,7 +730,7 @@ struct MediaInfoView: View { progress: progress, itemID: itemID ?? 0, totalEpisodes: episodeLinks.count, - defaultBannerImage: cachedBannerImage, + defaultBannerImage: defaultBannerImageValue, module: module, parentTitle: title, showPosterURL: imageUrl, @@ -812,8 +752,7 @@ struct MediaInfoView: View { tmdbID: tmdbID, seasonNumber: selectedSeason + 1 ) - .id("season-episode-\(ep.href)-\(isMultiSelectMode)") - .disabled(isFetchingEpisode) + .disabled(isFetchingEpisode) } } } else { @@ -821,132 +760,6 @@ struct MediaInfoView: View { } } - private func updateCachedComputations() { - let currentEpisodeCount = episodeLinks.count - let currentChunkSize = episodeChunkSize - - guard currentEpisodeCount != lastEpisodeCount || currentChunkSize != lastChunkSize else { - return - } - - lastEpisodeCount = currentEpisodeCount - lastChunkSize = currentChunkSize - - cachedGroupedEpisodes = groupedEpisodes() - cachedRanges = generateRanges() - updateCachedBannerImage() - } - - private func updateCachedBannerImage() { - cachedBannerImage = getBannerImageBasedOnAppearance() - } - - private func fetchDetailsAsync() async { - await MainActor.run { - viewState = .loading - } - - do { - try await Task.sleep(nanoseconds: 500_000_000) - - guard !Task.isCancelled else { return } - - let jsContent = try moduleManager.getModuleContent(module) - - await MainActor.run { - jsController.loadScript(jsContent) - } - - await withCheckedContinuation { continuation in - if module.metadata.asyncJS == true { - jsController.fetchDetailsJS(url: href) { items, episodes in - if let item = items.first { - self.synopsis = item.description - self.aliases = item.aliases - self.airdate = item.airdate - } - self.episodeLinks = episodes - self.updateCachedComputations() - self.restoreSelectionState() - self.viewState = .loaded - self.isRefetching = false - continuation.resume() - } - } else { - jsController.fetchDetails(url: href) { items, episodes in - if let item = items.first { - self.synopsis = item.description - self.aliases = item.aliases - self.airdate = item.airdate - } - self.episodeLinks = episodes - self.updateCachedComputations() - self.restoreSelectionState() - self.viewState = .loaded - self.isRefetching = false - continuation.resume() - } - } - } - } catch { - await MainActor.run { - Logger.shared.log("Error loading module: \(error)", type: "Error") - viewState = .error - isRefetching = false - } - } - } - - private func fetchMetadataIDIfNeededAsync() async { - let provider = UserDefaults.standard.string(forKey: "metadataProviders") ?? "TMDB" - let cleaned = cleanTitle(title) - - if provider == "TMDB" { - await MainActor.run { tmdbID = nil } - await withCheckedContinuation { continuation in - tmdbFetcher.fetchBestMatchID(for: cleaned) { id, type in - Task { @MainActor in - guard !Task.isCancelled else { - continuation.resume() - return - } - self.tmdbID = id - self.tmdbType = type - Logger.shared.log("Fetched TMDB ID: \(id ?? -1) (\(type?.rawValue ?? "unknown")) for title: \(cleaned)", type: "Debug") - continuation.resume() - } - } - } - } else if provider == "Anilist" { - await MainActor.run { itemID = nil } - await withCheckedContinuation { continuation in - fetchItemID(byTitle: cleaned) { result in - Task { @MainActor in - guard !Task.isCancelled else { - continuation.resume() - return - } - switch result { - case .success(let id): - self.itemID = id - Logger.shared.log("Fetched AniList ID: \(id) for title: \(cleaned)", type: "Debug") - case .failure(let error): - Logger.shared.log("Failed to fetch AniList ID: \(error)", type: "Error") - } - continuation.resume() - } - } - } - } - } - - private func cancelAllTasks() { - for task in currentTasks { - task.cancel() - } - currentTasks.removeAll() - } - private func restoreSelectionState() { if let savedStart = UserDefaults.standard.object(forKey: selectedRangeKey) as? Int, let savedRange = generateRanges().first(where: { $0.lowerBound == savedStart }) { @@ -956,7 +769,7 @@ struct MediaInfoView: View { } if let savedSeason = UserDefaults.standard.object(forKey: selectedSeasonKey) as? Int { - let maxIndex = max(0, cachedGroupedEpisodes.count - 1) + let maxIndex = max(0, groupedEpisodes().count - 1) selectedSeason = min(savedSeason, maxIndex) } } @@ -1044,7 +857,7 @@ struct MediaInfoView: View { var updates = [String: Double]() if inSeason { - let seasons = cachedGroupedEpisodes + let seasons = groupedEpisodes() for ep2 in seasons[selectedSeason] where ep2.number < ep.number { let href = ep2.href updates["lastPlayedTime_\(href)"] = 99999999.0 @@ -1229,10 +1042,43 @@ struct MediaInfoView: View { } func fetchDetails() { - let fetchTask = Task { - await fetchDetailsAsync() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + Task { + do { + let jsContent = try moduleManager.getModuleContent(module) + jsController.loadScript(jsContent) + if module.metadata.asyncJS == true { + jsController.fetchDetailsJS(url: href) { items, episodes in + if let item = items.first { + self.synopsis = item.description + self.aliases = item.aliases + self.airdate = item.airdate + } + self.episodeLinks = episodes + self.restoreSelectionState() + self.isLoading = false + self.isRefetching = false + } + } else { + jsController.fetchDetails(url: href) { items, episodes in + if let item = items.first { + self.synopsis = item.description + self.aliases = item.aliases + self.airdate = item.airdate + } + self.episodeLinks = episodes + self.restoreSelectionState() + self.isLoading = false + self.isRefetching = false + } + } + } catch { + Logger.shared.log("Error loading module: \(error)", type: "Error") + self.isLoading = false + self.isRefetching = false + } + } } - currentTasks.insert(fetchTask) } func fetchStream(href: String) { @@ -1625,7 +1471,7 @@ struct MediaInfoView: View { private func selectAllVisibleEpisodes() { if isGroupedBySeasons { - let seasons = cachedGroupedEpisodes + let seasons = groupedEpisodes() if !seasons.isEmpty, selectedSeason < seasons.count { for episode in seasons[selectedSeason] { selectedEpisodes.insert(episode.number)