diff --git a/NineAnimator.xcodeproj/project.pbxproj b/NineAnimator.xcodeproj/project.pbxproj index e1e540e6d..880e63f31 100644 --- a/NineAnimator.xcodeproj/project.pbxproj +++ b/NineAnimator.xcodeproj/project.pbxproj @@ -55,6 +55,8 @@ 2C12EDE721BDFFFF0064D2BD /* CastController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C12EDE621BDFFFF0064D2BD /* CastController.swift */; }; 2C12EDE921BE13920064D2BD /* GoogleCastDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C12EDE821BE13920064D2BD /* GoogleCastDeviceTableViewCell.swift */; }; 2C17E08921D7D67000E3FD1F /* UnavailableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C17E08821D7D67000E3FD1F /* UnavailableTableViewCell.swift */; }; + 2C18FDED24AAD85400F021BE /* AppCenterCrashes in Frameworks */ = {isa = PBXBuildFile; productRef = 2C18FDEC24AAD85400F021BE /* AppCenterCrashes */; }; + 2C18FDEF24AAD85400F021BE /* AppCenterAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 2C18FDEE24AAD85400F021BE /* AppCenterAnalytics */; }; 2C1C716822183FA500760A69 /* AnimeListing.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C1C716622183FA500760A69 /* AnimeListing.storyboard */; }; 2C1C716C221845A800760A69 /* ContentListingLoadingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1C716B221845A800760A69 /* ContentListingLoadingTableViewCell.swift */; }; 2C1C716F221853AD00760A69 /* Anilist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1C716E221853AD00760A69 /* Anilist.swift */; }; @@ -254,6 +256,8 @@ 2C91297321BB61BE00284FD0 /* RapidVideoParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C91297221BB61BE00284FD0 /* RapidVideoParser.swift */; }; 2C91297521BB7A4200284FD0 /* StreamangoParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C91297421BB7A4200284FD0 /* StreamangoParser.swift */; }; 2C91297721BB867300284FD0 /* MyCloudParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C91297621BB867300284FD0 /* MyCloudParser.swift */; }; + 2C9325C224ACDDD3001E3708 /* SwordRPC in Frameworks */ = {isa = PBXBuildFile; platformFilter = maccatalyst; productRef = 2C9325C124ACDDD3001E3708 /* SwordRPC */; }; + 2C9325C424ACDE34001E3708 /* DiscordPresenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9325C324ACDE34001E3708 /* DiscordPresenceController.swift */; }; 2C9383CD21FBF442008C0D01 /* UIView+MakeThemable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9383CC21FBF442008C0D01 /* UIView+MakeThemable.swift */; }; 2C9383D421FCCC43008C0D01 /* UILabel+StyleAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9383D321FCCC43008C0D01 /* UILabel+StyleAttributes.swift */; }; 2C9383D821FCF1B9008C0D01 /* UITableViewCell+StyleAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9383D721FCF1B9008C0D01 /* UITableViewCell+StyleAttributes.swift */; }; @@ -706,6 +710,7 @@ 2C91297221BB61BE00284FD0 /* RapidVideoParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RapidVideoParser.swift; sourceTree = ""; }; 2C91297421BB7A4200284FD0 /* StreamangoParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamangoParser.swift; sourceTree = ""; }; 2C91297621BB867300284FD0 /* MyCloudParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCloudParser.swift; sourceTree = ""; }; + 2C9325C324ACDE34001E3708 /* DiscordPresenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordPresenceController.swift; sourceTree = ""; }; 2C9383CC21FBF442008C0D01 /* UIView+MakeThemable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+MakeThemable.swift"; sourceTree = ""; }; 2C9383D321FCCC43008C0D01 /* UILabel+StyleAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+StyleAttributes.swift"; sourceTree = ""; }; 2C9383D721FCF1B9008C0D01 /* UITableViewCell+StyleAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+StyleAttributes.swift"; sourceTree = ""; }; @@ -890,12 +895,15 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2C9325C224ACDDD3001E3708 /* SwordRPC in Frameworks */, 2CB6704F249FCB26006C11A9 /* HomeKit.framework in Frameworks */, 2CB67042249FC9E3006C11A9 /* Kingfisher in Frameworks */, 2CB6704E249FCA65006C11A9 /* ViewAnimator in Frameworks */, 2CB67045249FCA06006C11A9 /* Alamofire in Frameworks */, + 2C18FDEF24AAD85400F021BE /* AppCenterAnalytics in Frameworks */, 2CB67048249FCA24006C11A9 /* SwiftSoup in Frameworks */, 2CB6704B249FCA48006C11A9 /* OpenCastSwift in Frameworks */, + 2C18FDED24AAD85400F021BE /* AppCenterCrashes in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1269,6 +1277,7 @@ 2C12EDD621BDE66E0064D2BD /* Prototype */, 2CAA70CF21CFF10B00F0D082 /* RootViewController.swift */, 2CA1DD5B21E2B404009241CB /* HomeController.swift */, + 2C9325C324ACDE34001E3708 /* DiscordPresenceController.swift */, ); path = Controllers; sourceTree = ""; @@ -2015,6 +2024,9 @@ 2CB67047249FCA24006C11A9 /* SwiftSoup */, 2CB6704A249FCA48006C11A9 /* OpenCastSwift */, 2CB6704D249FCA65006C11A9 /* ViewAnimator */, + 2C18FDEC24AAD85400F021BE /* AppCenterCrashes */, + 2C18FDEE24AAD85400F021BE /* AppCenterAnalytics */, + 2C9325C124ACDDD3001E3708 /* SwordRPC */, ); productName = NineAnimator; productReference = 2C4ABC5021B5881E009B4D47 /* NineAnimator.app */; @@ -2096,6 +2108,8 @@ 2CB67046249FCA24006C11A9 /* XCRemoteSwiftPackageReference "SwiftSoup" */, 2CB67049249FCA48006C11A9 /* XCRemoteSwiftPackageReference "OpenCastSwift" */, 2CB6704C249FCA65006C11A9 /* XCRemoteSwiftPackageReference "ViewAnimator" */, + 2C18FDEB24AAD85400F021BE /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */, + 2C9325C024ACDDD3001E3708 /* XCRemoteSwiftPackageReference "SwordRPC" */, ); productRefGroup = 2C4ABC5121B5881E009B4D47 /* Products */; projectDirPath = ""; @@ -2180,7 +2194,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ \"${IS_MACCATALYST}\" = \"YES\" ]; then\n ENTITLEMENTS_FILE=\"${TARGET_TEMP_DIR}/${FULL_PRODUCT_NAME}.xcent\"\n \n echo \"Removing com.apple.developer.homekit entitlement on Mac Catalyst from ${ENTITLEMENTS_FILE}\"\n plutil -remove \"com\\.apple\\.developer\\.homekit\" \"${ENTITLEMENTS_FILE}\"\nfi\n"; + shellScript = "if [ \"${IS_MACCATALYST}\" = \"YES\" ]; then\n ENTITLEMENTS_FILE=\"${TARGET_TEMP_DIR}/${FULL_PRODUCT_NAME}.xcent\"\n \n echo \"Removing com.apple.developer.homekit entitlement on Mac Catalyst from ${ENTITLEMENTS_FILE}\"\n plutil -remove \"com\\.apple\\.developer\\.homekit\" \"${ENTITLEMENTS_FILE}\"\n \n echo \"Removing com.apple.security.app-sandbox on Mac Catalyst from ${ENTITLEMENTS_FILE}\"\n plutil -remove \"com\\.apple\\.security\\.app-sandbox\" \"${ENTITLEMENTS_FILE}\"\nfi\n"; }; 2CD7499C225B6409004C6C0C /* Generate Version Information */ = { isa = PBXShellScriptBuildPhase; @@ -2557,6 +2571,7 @@ 2C1C71832219975A00760A69 /* Promise+Hashable.swift in Sources */, 2C1C716C221845A800760A69 /* ContentListingLoadingTableViewCell.swift in Sources */, 6520A111246B6F4C001D9634 /* StreamTapeParser.swift in Sources */, + 2C9325C424ACDE34001E3708 /* DiscordPresenceController.swift in Sources */, 2C23AE3A2229912100512150 /* Promise+Success.swift in Sources */, C8E12D052422140D00B0AF6A /* AnimeUnity+Episode.swift in Sources */, 526A018821BD7DB900A90385 /* AVPlayerItem+ProviderParsers.swift in Sources */, @@ -3075,6 +3090,22 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 2C18FDEB24AAD85400F021BE /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/microsoft/appcenter-sdk-apple.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.3.0; + }; + }; + 2C9325C024ACDDD3001E3708 /* XCRemoteSwiftPackageReference "SwordRPC" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SuperMarcus/SwordRPC"; + requirement = { + branch = master; + kind = branch; + }; + }; 2CB67040249FC9E3006C11A9 /* XCRemoteSwiftPackageReference "Kingfisher" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/onevcat/Kingfisher"; @@ -3118,6 +3149,21 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 2C18FDEC24AAD85400F021BE /* AppCenterCrashes */ = { + isa = XCSwiftPackageProductDependency; + package = 2C18FDEB24AAD85400F021BE /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; + productName = AppCenterCrashes; + }; + 2C18FDEE24AAD85400F021BE /* AppCenterAnalytics */ = { + isa = XCSwiftPackageProductDependency; + package = 2C18FDEB24AAD85400F021BE /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; + productName = AppCenterAnalytics; + }; + 2C9325C124ACDDD3001E3708 /* SwordRPC */ = { + isa = XCSwiftPackageProductDependency; + package = 2C9325C024ACDDD3001E3708 /* XCRemoteSwiftPackageReference "SwordRPC" */; + productName = SwordRPC; + }; 2CB67041249FC9E3006C11A9 /* Kingfisher */ = { isa = XCSwiftPackageProductDependency; package = 2CB67040249FC9E3006C11A9 /* XCRemoteSwiftPackageReference "Kingfisher" */; diff --git a/NineAnimator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NineAnimator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fc70e5c64..ea7e5bdc7 100644 --- a/NineAnimator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NineAnimator.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -10,6 +10,24 @@ "version": "5.2.1" } }, + { + "package": "App Center", + "repositoryURL": "https://github.com/microsoft/appcenter-sdk-apple.git", + "state": { + "branch": null, + "revision": "2c1618a9bca76039aad49a5079b0f2879a643a7d", + "version": "3.3.1" + } + }, + { + "package": "Socket", + "repositoryURL": "https://github.com/IBM-Swift/BlueSocket.git", + "state": { + "branch": null, + "revision": "c46a3d41f5b2401d18bcb46d0101cdc5cd13e307", + "version": "1.0.52" + } + }, { "package": "Kingfisher", "repositoryURL": "https://github.com/onevcat/Kingfisher", @@ -24,17 +42,26 @@ "repositoryURL": "https://github.com/SuperMarcus/OpenCastSwift", "state": { "branch": "spm", - "revision": "fdbecac31b2d84e45898136a85ea937f0e683850", + "revision": "ab3aafae42b7719b08fbaa18dbb80c2b8995ddb1", "version": null } }, + { + "package": "PLCrashReporter", + "repositoryURL": "https://github.com/microsoft/plcrashreporter.git", + "state": { + "branch": null, + "revision": "5e013e00ad342d8ccaae767fef5a1ef117514ce8", + "version": "1.7.1" + } + }, { "package": "SwiftProtobuf", "repositoryURL": "https://github.com/apple/swift-protobuf", "state": { "branch": null, - "revision": "7f36441e3372665b1b414f8ac93b5905cc42a405", - "version": "1.9.0" + "revision": "05cb9347bb095d9a28234a593d45cb9fcdc9d196", + "version": "1.10.0" } }, { @@ -55,6 +82,15 @@ "version": "5.0.0" } }, + { + "package": "SwordRPC", + "repositoryURL": "https://github.com/SuperMarcus/SwordRPC", + "state": { + "branch": "master", + "revision": "04d6ac5ad1040a4ba6ebea696a2cc7b0b327f886", + "version": null + } + }, { "package": "ViewAnimator", "repositoryURL": "https://github.com/marcosgriselli/ViewAnimator", diff --git a/NineAnimator/AppDelegate+Environment.swift b/NineAnimator/AppDelegate+Environment.swift index 15ed8fc71..f84860ef8 100644 --- a/NineAnimator/AppDelegate+Environment.swift +++ b/NineAnimator/AppDelegate+Environment.swift @@ -22,6 +22,15 @@ import UIKit extension AppDelegate { /// Update NineAnimator settings based on environment variable values func configureEnvironment() { + // Update user runtime id + var rid = NineAnimator.applicationRuntimeUuid.uuid + let ridData = NSData(bytes: &rid, length: 10) as Data + let aidData = Bundle.main.infoDictionary!["UIApplicationRegistrationData", typedDefault: Data(repeating: 0, count: 6)] + let idData = ridData + aidData + NineAnimator.default.user.runtimeUuid = idData.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in + UUID(uuid: ptr.bindMemory(to: uuid_t.self).baseAddress!.pointee) + } + // NINEANIMATOR_NO_ANIMATIONS: Disable Animations if NineAnimator.runtime.isAnimationDisabled { Log.info("[AppDelegate.Environment] Disabling animations...") diff --git a/NineAnimator/AppDelegate.swift b/NineAnimator/AppDelegate.swift index 292539721..86bf2a586 100644 --- a/NineAnimator/AppDelegate.swift +++ b/NineAnimator/AppDelegate.swift @@ -17,6 +17,7 @@ // along with NineAnimator. If not, see . // +import AppCenterCrashes import Kingfisher import UIKit import UserNotifications @@ -49,6 +50,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.registerBackgroundUpdateTasks() self.configureEnvironment() + // Setup additional services + NineAnimator.default.cloud.setup() + NineAnimator.presenceController.setup() + return true } @@ -72,8 +77,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Recover any pending download tasks OfflineContentManager.shared.recoverPendingTasks() - // Setup Kingfisher + // Finish Setup setupImageCacher() + setupCrashHandler() return true } @@ -297,16 +303,17 @@ extension AppDelegate { // MARK: - Continuity extension AppDelegate { - func application(_ application: UIApplication, - continue userActivity: NSUserActivity, - restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void - ) -> Bool { + func application( + _ application: UIApplication, + continue userActivity: NSUserActivity, + restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void + ) -> Bool { switch userActivity.activityType { case Continuity.activityTypeViewAnime: // Browse anime guard let info = userActivity.userInfo, let linkData = info["link"] as? Data, let link = try? PropertyListDecoder().decode(AnimeLink.self, from: linkData) else { - Log.error("Cannot resume activity: invalid user info") - return false + Log.error("Cannot resume activity: invalid user info") + return false } RootViewController.open(whenReady: .anime(link)) return true @@ -321,8 +328,8 @@ extension AppDelegate { guard let info = userActivity.userInfo, let linkData = info["link"] as? Data, let progress = info["progress"] as? Float, let link = try? PropertyListDecoder().decode(EpisodeLink.self, from: linkData) else { - Log.error("Cannot resume activity: invalid user info") - return false + Log.error("Cannot resume activity: invalid user info") + return false } // Save progress so it will resume once we starts it NineAnimator.default.user.update(progress: progress, for: link) @@ -418,6 +425,34 @@ fileprivate extension AppDelegate { // Set loading failure image Kingfisher.KingfisherManager.shared.defaultOptions.append(.onFailureImage(#imageLiteral(resourceName: "Artwork Load Failure"))) } + + func setupCrashHandler() { + MSCrashes.setUserConfirmationHandler { + _ in + let alertController = UIAlertController( + title: "Oops, the app crashed.", + message: "Looks like NineAnimator just crashed due to an internal error. Do you want to send an anonymous crash report so we can fix the issue?", + preferredStyle: .alert + ) + + alertController.addAction(UIAlertAction(title: "Don't send", style: .cancel) { + _ in MSCrashes.notify(with: .dontSend) + }) + + alertController.addAction(UIAlertAction(title: "Send", style: .default) { + _ in MSCrashes.notify(with: .send) + }) + + alertController.addAction(UIAlertAction(title: "Always send", style: .default) { + _ in MSCrashes.notify(with: .always) + }) + + // Show the alert controller. + RootViewController.shared?.presentOnTop(alertController, animated: true) + + return true + } + } } // MARK: - Quick Actions @@ -433,7 +468,7 @@ fileprivate extension AppDelegate { localizedSubtitle: nil, icon: .init(templateImageName: "Library Icon"), userInfo: nil - )) + )) availableShortcutItems.append(.init( type: AppShortcutType.search.rawValue, @@ -441,7 +476,7 @@ fileprivate extension AppDelegate { localizedSubtitle: nil, icon: .init(type: .search), userInfo: nil - )) + )) if let lastWatchedEpisode = NineAnimator.default.user.lastEpisode { availableShortcutItems.append(.init( @@ -450,7 +485,7 @@ fileprivate extension AppDelegate { localizedSubtitle: "\(lastWatchedEpisode.name) - \(lastWatchedEpisode.parent.title)", icon: .init(type: .play), userInfo: nil - )) + )) } // Update the shortcut items diff --git a/NineAnimator/Base.lproj/Setup.storyboard b/NineAnimator/Base.lproj/Setup.storyboard index dd6ab847e..f600c4fef 100644 --- a/NineAnimator/Base.lproj/Setup.storyboard +++ b/NineAnimator/Base.lproj/Setup.storyboard @@ -1,5 +1,5 @@ - + @@ -102,8 +102,8 @@