Revert "yeah i dont even know what is this"

This reverts commit 3478a3f11e.
This commit is contained in:
cranci1 2025-06-09 16:30:44 +02:00
parent 3478a3f11e
commit d0a622c2b7

View file

@ -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<Int>] = []
@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<Task<Void, Never>> = []
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..<seasons.count, id: \.self) { index in
@ -739,6 +675,8 @@ struct MediaInfoView: View {
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(ep.href)")
let progress = totalTime > 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)