mirror of
https://github.com/cranci1/Sora.git
synced 2026-01-11 20:10:24 +00:00
Merge branch 'main' into dev
This commit is contained in:
commit
0751a090d0
2 changed files with 151 additions and 48 deletions
|
|
@ -203,12 +203,6 @@ class ModuleManager: ObservableObject {
|
|||
return try String(contentsOf: localUrl, encoding: .utf8)
|
||||
}
|
||||
|
||||
func getModule(for episodeUrl: String) -> ScrapingModule {
|
||||
// For now, return the first active module
|
||||
// In the future, we might want to add logic to determine which module to use based on the URL
|
||||
return modules.first(where: { $0.isActive }) ?? modules.first!
|
||||
}
|
||||
|
||||
func refreshModules() async {
|
||||
for (index, module) in modules.enumerated() {
|
||||
do {
|
||||
|
|
@ -236,10 +230,8 @@ class ModuleManager: ObservableObject {
|
|||
isActive: module.isActive
|
||||
)
|
||||
|
||||
await MainActor.run {
|
||||
self.modules[index] = updatedModule
|
||||
self.saveModules()
|
||||
}
|
||||
self.modules[index] = updatedModule
|
||||
self.saveModules()
|
||||
|
||||
Logger.shared.log("Updated module: \(module.metadata.sourceName) to version \(newMetadata.version)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,9 +141,10 @@ struct SettingsViewData: View {
|
|||
@State private var isCalculatingSize: Bool = false
|
||||
@State private var cacheSize: Int64 = 0
|
||||
@State private var documentsSize: Int64 = 0
|
||||
@State private var downloadsSize: Int64 = 0
|
||||
|
||||
enum ActiveAlert {
|
||||
case eraseData, removeDocs
|
||||
case eraseData, removeDocs, removeDownloads, clearCache
|
||||
}
|
||||
|
||||
@State private var activeAlert: ActiveAlert = .eraseData
|
||||
|
|
@ -151,47 +152,66 @@ struct SettingsViewData: View {
|
|||
var body: some View {
|
||||
return ScrollView {
|
||||
VStack(spacing: 24) {
|
||||
SettingsSection(
|
||||
title: "Cache",
|
||||
footer: "Caching helps reduce network usage and load content faster. You can disable it to save storage space."
|
||||
) {
|
||||
HStack {
|
||||
Image(systemName: "folder.badge.gearshape")
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
Text("Current Cache Size")
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
Spacer()
|
||||
|
||||
if isCalculatingSize {
|
||||
ProgressView()
|
||||
.scaleEffect(0.7)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
|
||||
Text(cacheSizeText)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
|
||||
Divider().padding(.horizontal, 16)
|
||||
|
||||
Button(action: clearAllCaches) {
|
||||
Text("Clear All Caches")
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
}
|
||||
|
||||
SettingsSection(
|
||||
title: "App Storage",
|
||||
footer: "The App Data should never be erased if you don't know what that will cause.\nClearing the documents folder will remove all the modules and downloads\n "
|
||||
footer: "The app cache allow the app to sho immages faster.\n\nClearing the documents folder will remove all the modules.\n\nThe App Data should never be erased if you don't know what that will cause."
|
||||
) {
|
||||
VStack(spacing: 0) {
|
||||
HStack {
|
||||
Image(systemName: "folder.badge.gearshape")
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
Text("Current Cache Size")
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
Spacer()
|
||||
|
||||
if isCalculatingSize {
|
||||
ProgressView()
|
||||
.scaleEffect(0.7)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
|
||||
Text(cacheSizeText)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
|
||||
Button(action: {
|
||||
activeAlert = .clearCache
|
||||
showAlert = true
|
||||
}) {
|
||||
HStack {
|
||||
Image(systemName: "trash")
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundStyle(.red)
|
||||
|
||||
Text("Clear All Caches")
|
||||
.foregroundStyle(.red)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 12)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
|
||||
Divider().padding(.horizontal, 16)
|
||||
|
||||
SettingsButtonRow(
|
||||
icon: "film",
|
||||
title: "Remove Downloaded Media",
|
||||
subtitle: formatSize(downloadsSize),
|
||||
action: {
|
||||
activeAlert = .removeDownloads
|
||||
showAlert = true
|
||||
}
|
||||
)
|
||||
|
||||
Divider().padding(.horizontal, 16)
|
||||
|
||||
SettingsButtonRow(
|
||||
icon: "doc.text",
|
||||
title: "Remove All Files in Documents",
|
||||
|
|
@ -201,6 +221,7 @@ struct SettingsViewData: View {
|
|||
showAlert = true
|
||||
}
|
||||
)
|
||||
|
||||
Divider().padding(.horizontal, 16)
|
||||
|
||||
SettingsButtonRow(
|
||||
|
|
@ -219,6 +240,7 @@ struct SettingsViewData: View {
|
|||
.onAppear {
|
||||
calculateCacheSize()
|
||||
updateSizes()
|
||||
calculateDownloadsSize()
|
||||
}
|
||||
.alert(isPresented: $showAlert) {
|
||||
switch activeAlert {
|
||||
|
|
@ -240,6 +262,24 @@ struct SettingsViewData: View {
|
|||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
case .removeDownloads:
|
||||
return Alert(
|
||||
title: Text("Remove Downloaded Media"),
|
||||
message: Text("Are you sure you want to remove all downloaded media files (.mov, .mp4, .pkg)? This action cannot be undone."),
|
||||
primaryButton: .destructive(Text("Remove")) {
|
||||
removeDownloadedMedia()
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
case .clearCache:
|
||||
return Alert(
|
||||
title: Text("Clear Cache"),
|
||||
message: Text("Are you sure you want to clear all cached data? This will help free up storage space."),
|
||||
primaryButton: .destructive(Text("Clear")) {
|
||||
clearAllCaches()
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,6 +316,42 @@ struct SettingsViewData: View {
|
|||
}
|
||||
}
|
||||
|
||||
func calculateDownloadsSize() {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||
let size = calculateMediaFilesSize(in: documentsURL)
|
||||
DispatchQueue.main.async {
|
||||
self.downloadsSize = size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func calculateMediaFilesSize(in directory: URL) -> Int64 {
|
||||
let fileManager = FileManager.default
|
||||
var totalSize: Int64 = 0
|
||||
let mediaExtensions = [".mov", ".mp4", ".pkg"]
|
||||
|
||||
do {
|
||||
let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey])
|
||||
for url in contents {
|
||||
let resourceValues = try url.resourceValues(forKeys: [.fileSizeKey, .isDirectoryKey])
|
||||
if resourceValues.isDirectory == true {
|
||||
totalSize += calculateMediaFilesSize(in: url)
|
||||
} else {
|
||||
let fileExtension = url.pathExtension.lowercased()
|
||||
if mediaExtensions.contains(".\(fileExtension)") {
|
||||
totalSize += Int64(resourceValues.fileSize ?? 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.shared.log("Error calculating media files size: \(error)", type: "Error")
|
||||
}
|
||||
|
||||
return totalSize
|
||||
}
|
||||
|
||||
func clearAllCaches() {
|
||||
clearCache()
|
||||
}
|
||||
|
|
@ -291,12 +367,47 @@ struct SettingsViewData: View {
|
|||
Logger.shared.log("Cache cleared successfully!", type: "General")
|
||||
calculateCacheSize()
|
||||
updateSizes()
|
||||
calculateDownloadsSize()
|
||||
}
|
||||
} catch {
|
||||
Logger.shared.log("Failed to clear cache.", type: "Error")
|
||||
}
|
||||
}
|
||||
|
||||
func removeDownloadedMedia() {
|
||||
let fileManager = FileManager.default
|
||||
let mediaExtensions = [".mov", ".mp4", ".pkg"]
|
||||
|
||||
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||
removeMediaFiles(in: documentsURL, extensions: mediaExtensions)
|
||||
Logger.shared.log("Downloaded media files removed", type: "General")
|
||||
updateSizes()
|
||||
calculateDownloadsSize()
|
||||
}
|
||||
}
|
||||
|
||||
func removeMediaFiles(in directory: URL, extensions: [String]) {
|
||||
let fileManager = FileManager.default
|
||||
|
||||
do {
|
||||
let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.isDirectoryKey])
|
||||
for url in contents {
|
||||
let resourceValues = try url.resourceValues(forKeys: [.isDirectoryKey])
|
||||
if resourceValues.isDirectory == true {
|
||||
removeMediaFiles(in: url, extensions: extensions)
|
||||
} else {
|
||||
let fileExtension = ".\(url.pathExtension.lowercased())"
|
||||
if extensions.contains(fileExtension) {
|
||||
try fileManager.removeItem(at: url)
|
||||
Logger.shared.log("Removed media file: \(url.lastPathComponent)", type: "General")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.shared.log("Error removing media files in \(directory.path): \(error)", type: "Error")
|
||||
}
|
||||
}
|
||||
|
||||
func removeAllFilesInDocuments() {
|
||||
let fileManager = FileManager.default
|
||||
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||
|
|
|
|||
Loading…
Reference in a new issue