// // TracyApp.swift // Shared // // Created by kintan on 2021/5/3. // import AVFoundation import AVKit import KSPlayer import SwiftUI import UserNotifications @main struct TracyApp: App { #if os(macOS) @NSApplicationDelegateAdaptor #else @UIApplicationDelegateAdaptor #endif private var appDelegate: AppDelegate private let appModel = APPModel() init() { let arguments = ProcessInfo.processInfo.arguments.dropFirst() var dropNextArg = false var playerArgs = [String]() var filenames = [String]() KSLog("launch arguments \(arguments)") for argument in arguments { if dropNextArg { dropNextArg = false continue } if argument.starts(with: "--") { playerArgs.append(argument) } else if argument.starts(with: "-") { dropNextArg = true } else { filenames.append(argument) } } if let urlString = filenames.first { appModel.open(url: URL(fileURLWithPath: urlString)) } } var body: some Scene { WindowGroup { ContentView() .environmentObject(appModel) .environment(\.managedObjectContext, PersistenceController.shared.viewContext) #if !os(tvOS) .handlesExternalEvents(preferring: Set(arrayLiteral: "pause"), allowing: Set(arrayLiteral: "*")) #endif } #if !os(tvOS) // .handlesExternalEvents(matching: Set(arrayLiteral: "*")) .commands { CommandGroup(before: .newItem) { Button("Open") { appModel.openFileImport = true } .keyboardShortcut("o") } CommandGroup(before: .newItem) { Button("Open URL") { appModel.openURLImport = true } .keyboardShortcut("o", modifiers: [.command, .shift]) } } #endif #if os(macOS) .defaultSize(width: 1120, height: 630) .defaultPosition(.center) #endif #if !os(tvOS) WindowGroup("player", for: URL.self) { $url in if let url { KSVideoPlayerView(url: url) } } #if os(macOS) .defaultPosition(.center) #endif #endif #if !os(tvOS) WindowGroup("player", for: MovieModel.self) { $model in if let model { KSVideoPlayerView(model: model) } } #if os(macOS) .defaultPosition(.center) #endif #endif #if os(macOS) Settings { TabBarItem.Setting.destination(appModel: appModel) } // MenuBarExtra { // MenuBar() // } label: { // Image(systemName: "film.fill") // } // .menuBarExtraStyle(.menu) #endif } } class AppDelegate: NSObject, UIApplicationDelegate { #if os(macOS) func applicationDidFinishLaunching(_: Notification) { // requestNotification() } #else func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { // requestNotification() true } #endif func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let tokenString = deviceToken.reduce("") { $0 + String(format: "%02x", $1) } print("Device push notification token - \(tokenString)") } func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("Failed to register for remote notification. Error \(error)") } private func requestNotification() { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { allowed, error in if allowed { // register for remote push notification DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } print("Push notification allowed by user") } else { print("Error while requesting push notification permission. Error \(String(describing: error))") } } } } class APPModel: ObservableObject { @Published var openURL: URL? @Published var openPlayModel: MovieModel? @Published var tabSelected: TabBarItem = .Home @Published var path = NavigationPath() @Published var openFileImport = false @Published var openURLImport = false @Published var hiddenTitleBar = false @AppStorage("activeM3UURL") private var activeM3UURL: URL? @Published var activeM3UModel: M3UModel? = nil { didSet { if let activeM3UModel, activeM3UModel != oldValue { activeM3UURL = activeM3UModel.m3uURL Task { @MainActor in _ = try? await activeM3UModel.parsePlaylist() // 为了解决第一次添加m3u。没有数据的问题,所以需要在查询结果出来之后,在设置下。 if activeM3UModel == self.activeM3UModel { self.activeM3UModel = activeM3UModel } } } } } init() { #if DEBUG // KSOptions.logLevel = .debug #else var fileHandle = FileHandle.standardOutput if let logURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("log.txt") { if !FileManager.default.fileExists(atPath: logURL.path) { FileManager.default.createFile(atPath: logURL.path, contents: nil) } if let handle = try? FileHandle(forWritingTo: logURL) { fileHandle = handle _ = try? fileHandle.seekToEnd() } } KSOptions.logger = FileLog(fileHandle: fileHandle) #endif // KSOptions.firstPlayerType = KSMEPlayer.self KSOptions.secondPlayerType = KSMEPlayer.self _ = Defaults.shared KSOptions.subtitleDataSouces = [DirectorySubtitleDataSouce(), ShooterSubtitleDataSouce(), AssrtSubtitleDataSouce(token: "5IzWrb2J099vmA96ECQXwdRSe9xdoBUv"), OpenSubtitleDataSouce(apiKey: "0D0gt8nV6SFHVVejdxAMpvOT0wByfKE5")] if let activeM3UURL { addM3U(url: activeM3UURL) } } func addM3U(url: URL, name: String? = nil) { let request = M3UModel.fetchRequest() request.predicate = NSPredicate(format: "m3uURL == %@", url.description) let context = PersistenceController.shared.viewContext context.perform { self.activeM3UModel = try? context.fetch(request).first ?? M3UModel(context: context, url: url, name: name) } } func open(url: URL) { if url.isPlaylist { addM3U(url: url) } else { #if os(macOS) openURL = url #else path.append(url) #endif } } func content(model: MovieModel) -> some View { #if os(macOS) Button { self.openPlayModel = model } label: { MoiveView(model: model) } .buttonStyle(.borderless) #else NavigationLink(value: model) { MoiveView(model: model) } #if targetEnvironment(macCatalyst) .buttonStyle(.borderless) #else .buttonStyle(.automatic) #endif #endif } } struct KSVideoPlayerView_Previews: PreviewProvider { static var previews: some View { ContentView() .environmentObject(APPModel()) .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } }