mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
episodes range + critical bug
the critical bug was an issue of the episodes response being cached in the userdefaults causing more than 120mb to be saved for 1k episodes
This commit is contained in:
parent
a75ca179ce
commit
e2252e13d0
5 changed files with 124 additions and 57 deletions
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
131845F92D47C62D00CA7A54 /* SettingsViewUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 131845F82D47C62D00CA7A54 /* SettingsViewUI.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 */; };
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
131845F82D47C62D00CA7A54 /* SettingsViewUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewUI.swift; sourceTree = "<group>"; };
|
||||
133D7C6A2D2BE2500075467E /* Sora.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sora.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
133D7C6D2D2BE2500075467E /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = "<group>"; };
|
||||
133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -152,6 +154,7 @@
|
|||
1E9FF1D22D403E42008AC100 /* SettingsViewLoggerFilter.swift */,
|
||||
1399FAD32D3AB38C00E97C31 /* SettingsViewLogger.swift */,
|
||||
133D7C842D2BE2630075467E /* SettingsViewModule.swift */,
|
||||
131845F82D47C62D00CA7A54 /* SettingsViewUI.swift */,
|
||||
);
|
||||
path = SettingsSubViews;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -368,6 +371,7 @@
|
|||
133D7C702D2BE2500075467E /* ContentView.swift in Sources */,
|
||||
13EA2BD62D32D97400C1EBD7 /* Double+Extension.swift in Sources */,
|
||||
133D7C8F2D2BE2640075467E /* MediaInfoView.swift in Sources */,
|
||||
131845F92D47C62D00CA7A54 /* SettingsViewUI.swift in Sources */,
|
||||
133D7C8D2D2BE2640075467E /* HomeView.swift in Sources */,
|
||||
13EA2BDC2D32D9FF00C1EBD7 /* MiruDataStruct.swift in Sources */,
|
||||
13D842552D45267500EBBFA6 /* DropManager.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -89,13 +89,6 @@ struct EpisodeCell: View {
|
|||
}
|
||||
|
||||
func fetchEpisodeDetails() {
|
||||
let cacheKey = "episodeDetails_\(itemID)_\(episodeID)"
|
||||
|
||||
if let cachedData = UserDefaults.standard.data(forKey: cacheKey) {
|
||||
parseEpisodeDetails(data: cachedData)
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = URL(string: "https://api.ani.zip/mappings?anilist_id=\(itemID)") else {
|
||||
isLoading = false
|
||||
return
|
||||
|
|
@ -117,39 +110,30 @@ struct EpisodeCell: View {
|
|||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.parseEpisodeDetails(data: data)
|
||||
UserDefaults.standard.set(data, forKey: cacheKey)
|
||||
self.isLoading = false
|
||||
do {
|
||||
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
|
||||
guard let json = jsonObject as? [String: Any],
|
||||
let episodes = json["episodes"] as? [String: Any],
|
||||
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")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.episodeTitle = title["en"] ?? ""
|
||||
self.episodeImageUrl = image
|
||||
self.isLoading = false
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
func parseEpisodeDetails(data: Data) {
|
||||
do {
|
||||
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
|
||||
guard let json = jsonObject as? [String: Any],
|
||||
let episodes = json["episodes"] as? [String: Any],
|
||||
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")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.episodeTitle = title["en"] ?? ""
|
||||
self.episodeImageUrl = image
|
||||
self.isLoading = false
|
||||
}
|
||||
} catch {
|
||||
Logger.shared.log("Failed to parse JSON: \(error)", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
self.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,11 +34,14 @@ struct MediaInfoView: View {
|
|||
@State var isRefetching: Bool = true
|
||||
|
||||
@AppStorage("externalPlayer") private var externalPlayer: String = "Default"
|
||||
@AppStorage("episodeChunkSize") private var episodeChunkSize: Int = 100
|
||||
|
||||
@StateObject private var jsController = JSController()
|
||||
@EnvironmentObject var moduleManager: ModuleManager
|
||||
@EnvironmentObject private var libraryManager: LibraryManager
|
||||
|
||||
@State private var selectedRange: Range<Int> = 0..<100
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if isLoading {
|
||||
|
|
@ -164,11 +167,31 @@ struct MediaInfoView: View {
|
|||
|
||||
if !episodeLinks.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
Text("Episodes")
|
||||
.font(.system(size: 18))
|
||||
.fontWeight(.bold)
|
||||
HStack {
|
||||
Text("Episodes")
|
||||
.font(.system(size: 18))
|
||||
.fontWeight(.bold)
|
||||
|
||||
Spacer()
|
||||
|
||||
if episodeLinks.count > episodeChunkSize {
|
||||
Menu {
|
||||
ForEach(generateRanges(), id: \.self) { range in
|
||||
Button(action: {
|
||||
selectedRange = range
|
||||
}) {
|
||||
Text("\(range.lowerBound + 1)-\(range.upperBound)")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Text("\(selectedRange.lowerBound + 1)-\(selectedRange.upperBound)")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ForEach(episodeLinks.indices, id: \.self) { i in
|
||||
ForEach(episodeLinks.indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||
let ep = episodeLinks[i]
|
||||
let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(ep.href)")
|
||||
let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(ep.href)")
|
||||
|
|
@ -233,9 +256,23 @@ struct MediaInfoView: View {
|
|||
}
|
||||
hasFetched = true
|
||||
}
|
||||
selectedRange = 0..<episodeChunkSize
|
||||
}
|
||||
}
|
||||
|
||||
private func generateRanges() -> [Range<Int>] {
|
||||
let chunkSize = episodeChunkSize
|
||||
let totalEpisodes = episodeLinks.count
|
||||
var ranges: [Range<Int>] = []
|
||||
|
||||
for i in stride(from: 0, to: totalEpisodes, by: chunkSize) {
|
||||
let end = min(i + chunkSize, totalEpisodes)
|
||||
ranges.append(i..<end)
|
||||
}
|
||||
|
||||
return ranges
|
||||
}
|
||||
|
||||
func fetchDetails() {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
Task {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// SettingsViewUI.swift
|
||||
// Sora
|
||||
//
|
||||
// Created by Francesco on 27/01/25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SettingsViewUI: View {
|
||||
@AppStorage("episodeChunkSize") private var episodeChunkSize: Int = 100
|
||||
@EnvironmentObject var settings: Settings
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Interface")) {
|
||||
ColorPicker("Accent Color", selection: $settings.accentColor)
|
||||
HStack() {
|
||||
Text("Appearance")
|
||||
Picker("Appearance", selection: $settings.selectedAppearance) {
|
||||
Text("System").tag(Appearance.system)
|
||||
Text("Light").tag(Appearance.light)
|
||||
Text("Dark").tag(Appearance.dark)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Episode Chunk Size")) {
|
||||
Menu {
|
||||
Button(action: { episodeChunkSize = 25 }) {
|
||||
Text("25")
|
||||
}
|
||||
Button(action: { episodeChunkSize = 50 }) {
|
||||
Text("50")
|
||||
}
|
||||
Button(action: { episodeChunkSize = 75 }) {
|
||||
Text("75")
|
||||
}
|
||||
Button(action: { episodeChunkSize = 100 }) {
|
||||
Text("100")
|
||||
}
|
||||
} label: {
|
||||
Text("Chunk Size: \(episodeChunkSize)")
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("UI Settings")
|
||||
}
|
||||
}
|
||||
|
|
@ -8,28 +8,20 @@
|
|||
import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
@EnvironmentObject var settings: Settings
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
Form {
|
||||
Section(header: Text("Interface")) {
|
||||
ColorPicker("Accent Color", selection: $settings.accentColor)
|
||||
HStack() {
|
||||
Text("Appearance")
|
||||
Picker("Appearance", selection: $settings.selectedAppearance) {
|
||||
Text("System").tag(Appearance.system)
|
||||
Text("Light").tag(Appearance.light)
|
||||
Text("Dark").tag(Appearance.dark)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
Section(header: Text("Main Settings")) {
|
||||
NavigationLink(destination: SettingsViewUI()) {
|
||||
Text("UI Settings")
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("External Features")) {
|
||||
NavigationLink(destination: SettingsViewModule()) {
|
||||
Text("Modules")
|
||||
}
|
||||
NavigationLink(destination: SettingsViewModule()) {
|
||||
Text("Media Player")
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Debug")) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue