From 0415df2cd9e9a7a95a3ffeda424b9842236d255c Mon Sep 17 00:00:00 2001 From: Francesco <100066266+cranci1@users.noreply.github.com> Date: Fri, 18 Apr 2025 14:18:22 +0200 Subject: [PATCH] module sync right? --- .../CustomPlayer/CustomPlayer.swift | 2 +- Sora/Utils/Modules/ModuleManager.swift | 18 ++++ .../iCloudSyncManager/iCloudSyncManager.swift | 83 +++++++++++++++++-- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift b/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift index 929b00b..c002aa0 100644 --- a/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift +++ b/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift @@ -215,7 +215,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele do { try audioSession.setActive(true) } catch { - print("Error activating audio session: \(error)") + Logger.shared.log("Error activating audio session: \(error)", type: "Debug") } volumeViewModel.value = Double(audioSession.outputVolume) diff --git a/Sora/Utils/Modules/ModuleManager.swift b/Sora/Utils/Modules/ModuleManager.swift index d13d8cf..b3526ba 100644 --- a/Sora/Utils/Modules/ModuleManager.swift +++ b/Sora/Utils/Modules/ModuleManager.swift @@ -29,6 +29,24 @@ class ModuleManager: ObservableObject { let url = getModulesFilePath() guard let data = try? Data(contentsOf: url) else { return } modules = (try? JSONDecoder().decode([ScrapingModule].self, from: data)) ?? [] + + Task { + for module in modules { + let localUrl = getDocumentsDirectory().appendingPathComponent(module.localPath) + if (!fileManager.fileExists(atPath: localUrl.path)) { + do { + let scriptUrl = URL(string: module.metadata.scriptUrl) + guard let scriptUrl = scriptUrl else { continue } + let (scriptData, _) = try await URLSession.custom.data(from: scriptUrl) + guard let jsContent = String(data: scriptData, encoding: .utf8) else { continue } + try jsContent.write(to: localUrl, atomically: true, encoding: .utf8) + Logger.shared.log("Recovered missing JS file for module: \(module.metadata.sourceName)") + } catch { + Logger.shared.log("Failed to recover JS file for module: \(module.metadata.sourceName) - \(error.localizedDescription)") + } + } + } + } } private func saveModules() { diff --git a/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift b/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift index 9a9c3a1..89c02eb 100644 --- a/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift +++ b/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift @@ -29,24 +29,30 @@ class iCloudSyncManager { "continueWatchingItems" ] + private let modulesFileName = "modules.json" + + private var ubiquityContainerURL: URL? { + FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents") + } + private init() { setupSync() NotificationCenter.default.addObserver(self, selector: #selector(willEnterBackground), name: UIApplication.willResignActiveNotification, object: nil) } + private func setupSync() { NSUbiquitousKeyValueStore.default.synchronize() - syncFromiCloud() - + syncModulesFromiCloud() NotificationCenter.default.addObserver(self, selector: #selector(iCloudDidChangeExternally), name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default) - NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange), name: UserDefaults.didChangeNotification, object: nil) } @objc private func willEnterBackground() { syncToiCloud() + syncModulesToiCloud() } private func syncFromiCloud() { @@ -79,16 +85,79 @@ class iCloudSyncManager { @objc private func iCloudDidChangeExternally(_ notification: Notification) { guard let userInfo = notification.userInfo, let reason = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey] as? Int else { - return - } - + return + } if reason == NSUbiquitousKeyValueStoreServerChange || - reason == NSUbiquitousKeyValueStoreInitialSyncChange { + reason == NSUbiquitousKeyValueStoreInitialSyncChange { syncFromiCloud() + syncModulesFromiCloud() } } @objc private func userDefaultsDidChange(_ notification: Notification) { syncToiCloud() } + + func syncModulesToiCloud() { + DispatchQueue.global(qos: .background).async { + guard let iCloudURL = self.ubiquityContainerURL else { return } + let localModulesURL = self.getLocalModulesFileURL() + let iCloudModulesURL = iCloudURL.appendingPathComponent(self.modulesFileName) + do { + guard FileManager.default.fileExists(atPath: localModulesURL.path) else { return } + + let shouldCopy: Bool + if FileManager.default.fileExists(atPath: iCloudModulesURL.path) { + let localData = try Data(contentsOf: localModulesURL) + let iCloudData = try Data(contentsOf: iCloudModulesURL) + shouldCopy = localData != iCloudData + } else { + shouldCopy = true + } + + if shouldCopy { + if FileManager.default.fileExists(atPath: iCloudModulesURL.path) { + try FileManager.default.removeItem(at: iCloudModulesURL) + } + try FileManager.default.copyItem(at: localModulesURL, to: iCloudModulesURL) + } + } catch { + Logger.shared.log("iCloud modules sync error: \(error)", type: "Error") + } + } + } + + func syncModulesFromiCloud() { + DispatchQueue.global(qos: .background).async { + guard let iCloudURL = self.ubiquityContainerURL else { return } + let localModulesURL = self.getLocalModulesFileURL() + let iCloudModulesURL = iCloudURL.appendingPathComponent(self.modulesFileName) + do { + guard FileManager.default.fileExists(atPath: iCloudModulesURL.path) else { return } + + let shouldCopy: Bool + if FileManager.default.fileExists(atPath: localModulesURL.path) { + let localData = try Data(contentsOf: localModulesURL) + let iCloudData = try Data(contentsOf: iCloudModulesURL) + shouldCopy = localData != iCloudData + } else { + shouldCopy = true + } + + if shouldCopy { + if FileManager.default.fileExists(atPath: localModulesURL.path) { + try FileManager.default.removeItem(at: localModulesURL) + } + try FileManager.default.copyItem(at: iCloudModulesURL, to: localModulesURL) + } + } catch { + Logger.shared.log("iCloud modules fetch error: \(error)", type: "Error") + } + } + } + + private func getLocalModulesFileURL() -> URL { + let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + return docs.appendingPathComponent(modulesFileName) + } }