2021-09-25 13:48:22 +05:30
|
|
|
import Defaults
|
2022-06-18 18:09:49 +05:30
|
|
|
import MediaPlayer
|
|
|
|
import PINCache
|
|
|
|
import SDWebImage
|
|
|
|
import SDWebImageWebPCoder
|
|
|
|
import Siesta
|
2021-06-10 02:21:23 +05:30
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
@main
|
2021-11-07 19:02:01 +05:30
|
|
|
struct YatteeApp: App {
|
2022-01-06 20:32:53 +05:30
|
|
|
static var version: String {
|
|
|
|
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown"
|
|
|
|
}
|
|
|
|
|
|
|
|
static var build: String {
|
|
|
|
Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
|
|
|
|
}
|
|
|
|
|
2022-06-18 18:09:49 +05:30
|
|
|
static var isForPreviews: Bool {
|
|
|
|
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
|
|
|
|
}
|
|
|
|
|
2022-07-07 03:38:38 +05:30
|
|
|
static var logsDirectory: URL {
|
|
|
|
URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
|
|
|
|
}
|
|
|
|
|
2021-10-24 14:46:04 +05:30
|
|
|
#if os(macOS)
|
|
|
|
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
2022-01-03 01:11:04 +05:30
|
|
|
#elseif os(iOS)
|
|
|
|
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
2021-10-24 14:46:04 +05:30
|
|
|
#endif
|
|
|
|
|
2022-06-18 18:09:49 +05:30
|
|
|
@State private var configured = false
|
|
|
|
|
2021-12-19 22:47:04 +05:30
|
|
|
@StateObject private var accounts = AccountsModel()
|
|
|
|
@StateObject private var comments = CommentsModel()
|
|
|
|
@StateObject private var instances = InstancesModel()
|
2021-11-09 04:44:28 +05:30
|
|
|
@StateObject private var menu = MenuModel()
|
2021-12-19 22:47:04 +05:30
|
|
|
@StateObject private var navigation = NavigationModel()
|
2022-06-18 18:09:49 +05:30
|
|
|
@StateObject private var networkState = NetworkStateModel()
|
2021-12-19 22:47:04 +05:30
|
|
|
@StateObject private var player = PlayerModel()
|
|
|
|
@StateObject private var playlists = PlaylistsModel()
|
|
|
|
@StateObject private var recents = RecentsModel()
|
|
|
|
@StateObject private var search = SearchModel()
|
2022-07-02 02:58:32 +05:30
|
|
|
@StateObject private var settings = SettingsModel()
|
2021-12-19 22:47:04 +05:30
|
|
|
@StateObject private var subscriptions = SubscriptionsModel()
|
|
|
|
@StateObject private var thumbnails = ThumbnailsModel()
|
2021-11-09 04:44:28 +05:30
|
|
|
|
2021-12-27 02:44:46 +05:30
|
|
|
let persistenceController = PersistenceController.shared
|
|
|
|
|
2022-09-01 23:31:01 +05:30
|
|
|
var playerControls: PlayerControlsModel { .shared }
|
|
|
|
|
2021-06-10 02:21:23 +05:30
|
|
|
var body: some Scene {
|
|
|
|
WindowGroup {
|
|
|
|
ContentView()
|
2022-06-18 18:09:49 +05:30
|
|
|
.onAppear(perform: configure)
|
2021-12-27 02:44:46 +05:30
|
|
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(accounts)
|
|
|
|
.environmentObject(comments)
|
|
|
|
.environmentObject(instances)
|
|
|
|
.environmentObject(navigation)
|
2022-06-18 18:09:49 +05:30
|
|
|
.environmentObject(networkState)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(player)
|
2022-02-17 01:53:11 +05:30
|
|
|
.environmentObject(playerControls)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(playlists)
|
|
|
|
.environmentObject(recents)
|
2022-07-02 02:58:32 +05:30
|
|
|
.environmentObject(settings)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(subscriptions)
|
|
|
|
.environmentObject(thumbnails)
|
2021-11-09 04:44:28 +05:30
|
|
|
.environmentObject(menu)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(search)
|
2022-01-06 21:05:45 +05:30
|
|
|
#if os(macOS)
|
|
|
|
.background(
|
|
|
|
HostingWindowFinder { window in
|
|
|
|
Windows.mainWindow = window
|
|
|
|
}
|
|
|
|
)
|
|
|
|
#else
|
|
|
|
.onReceive(
|
|
|
|
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
|
|
|
|
) { _ in
|
|
|
|
player.handleEnterForeground()
|
|
|
|
}
|
2022-06-05 22:42:00 +05:30
|
|
|
.onReceive(
|
|
|
|
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
|
|
|
|
) { _ in
|
|
|
|
player.handleEnterBackground()
|
|
|
|
}
|
2021-12-19 22:47:04 +05:30
|
|
|
#endif
|
2021-12-25 00:50:05 +05:30
|
|
|
#if os(iOS)
|
|
|
|
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
|
2021-12-19 22:47:04 +05:30
|
|
|
#endif
|
2021-06-10 02:21:23 +05:30
|
|
|
}
|
2021-12-25 00:50:05 +05:30
|
|
|
#if os(iOS)
|
|
|
|
.handlesExternalEvents(matching: Set(["*"]))
|
|
|
|
#endif
|
2021-07-28 04:10:04 +05:30
|
|
|
#if !os(tvOS)
|
2021-11-08 21:59:35 +05:30
|
|
|
.commands {
|
|
|
|
SidebarCommands()
|
2021-12-08 04:39:49 +05:30
|
|
|
|
2021-11-08 21:59:35 +05:30
|
|
|
CommandGroup(replacing: .newItem, addition: {})
|
2021-12-08 04:39:49 +05:30
|
|
|
|
2021-11-09 04:44:28 +05:30
|
|
|
MenuCommands(model: Binding<MenuModel>(get: { menu }, set: { _ in }))
|
2021-11-08 21:59:35 +05:30
|
|
|
}
|
2021-07-28 04:10:04 +05:30
|
|
|
#endif
|
2021-09-25 13:48:22 +05:30
|
|
|
|
|
|
|
#if os(macOS)
|
2021-12-19 22:47:04 +05:30
|
|
|
WindowGroup(player.windowTitle) {
|
|
|
|
VideoPlayerView()
|
2022-06-18 18:09:49 +05:30
|
|
|
.onAppear(perform: configure)
|
2022-01-06 21:05:45 +05:30
|
|
|
.background(
|
|
|
|
HostingWindowFinder { window in
|
|
|
|
Windows.playerWindow = window
|
2022-04-03 17:53:42 +05:30
|
|
|
|
|
|
|
NotificationCenter.default.addObserver(
|
|
|
|
forName: NSWindow.willExitFullScreenNotification,
|
|
|
|
object: window,
|
|
|
|
queue: OperationQueue.main
|
|
|
|
) { _ in
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
2022-06-18 18:09:49 +05:30
|
|
|
self.player.playingFullScreen = false
|
2022-04-03 17:53:42 +05:30
|
|
|
}
|
|
|
|
}
|
2022-01-06 21:05:45 +05:30
|
|
|
}
|
|
|
|
)
|
2021-12-19 22:47:04 +05:30
|
|
|
.onAppear { player.presentingPlayer = true }
|
|
|
|
.onDisappear { player.presentingPlayer = false }
|
2021-12-27 02:44:46 +05:30
|
|
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environment(\.navigationStyle, .sidebar)
|
|
|
|
.environmentObject(accounts)
|
|
|
|
.environmentObject(comments)
|
|
|
|
.environmentObject(instances)
|
|
|
|
.environmentObject(navigation)
|
2022-06-18 18:09:49 +05:30
|
|
|
.environmentObject(networkState)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(player)
|
2022-02-17 01:53:11 +05:30
|
|
|
.environmentObject(playerControls)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(playlists)
|
|
|
|
.environmentObject(recents)
|
2022-06-25 04:18:57 +05:30
|
|
|
.environmentObject(search)
|
2021-12-19 22:47:04 +05:30
|
|
|
.environmentObject(subscriptions)
|
|
|
|
.environmentObject(thumbnails)
|
2021-12-25 00:50:05 +05:30
|
|
|
.handlesExternalEvents(preferring: Set(["player", "*"]), allowing: Set(["player", "*"]))
|
2021-12-19 22:47:04 +05:30
|
|
|
}
|
2021-12-25 00:50:05 +05:30
|
|
|
.handlesExternalEvents(matching: Set(["player", "*"]))
|
2021-12-19 22:47:04 +05:30
|
|
|
|
2021-09-25 13:48:22 +05:30
|
|
|
Settings {
|
|
|
|
SettingsView()
|
2021-12-27 02:44:46 +05:30
|
|
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
2021-12-25 00:50:05 +05:30
|
|
|
.environmentObject(accounts)
|
|
|
|
.environmentObject(instances)
|
2022-07-02 02:58:32 +05:30
|
|
|
.environmentObject(navigation)
|
2021-12-27 02:44:46 +05:30
|
|
|
.environmentObject(player)
|
2022-02-17 01:53:11 +05:30
|
|
|
.environmentObject(playerControls)
|
2022-07-02 02:58:32 +05:30
|
|
|
.environmentObject(settings)
|
2021-09-25 13:48:22 +05:30
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2022-06-18 18:09:49 +05:30
|
|
|
|
|
|
|
func configure() {
|
|
|
|
guard !Self.isForPreviews, !configured else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
configured = true
|
|
|
|
|
2022-08-08 22:56:04 +05:30
|
|
|
#if DEBUG
|
|
|
|
SiestaLog.Category.enabled = .common
|
|
|
|
#endif
|
2022-06-18 18:09:49 +05:30
|
|
|
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
|
|
|
|
SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app")
|
|
|
|
|
2022-08-26 05:06:46 +05:30
|
|
|
migrateAccounts()
|
|
|
|
|
2022-07-04 15:05:27 +05:30
|
|
|
if !Defaults[.lastAccountIsPublic] {
|
2022-07-04 02:09:10 +05:30
|
|
|
accounts.configureAccount()
|
2022-06-18 18:09:49 +05:30
|
|
|
}
|
|
|
|
|
2022-07-02 02:58:32 +05:30
|
|
|
let countryOfPublicInstances = Defaults[.countryOfPublicInstances]
|
|
|
|
if accounts.current.isNil, countryOfPublicInstances.isNil {
|
2022-06-18 18:09:49 +05:30
|
|
|
navigation.presentingWelcomeScreen = true
|
|
|
|
}
|
|
|
|
|
2022-07-02 02:58:32 +05:30
|
|
|
if !countryOfPublicInstances.isNil {
|
|
|
|
InstancesManifest.shared.setPublicAccount(countryOfPublicInstances!, accounts: accounts, asCurrent: accounts.current.isNil)
|
|
|
|
}
|
|
|
|
|
2022-06-18 18:09:49 +05:30
|
|
|
playlists.accounts = accounts
|
|
|
|
search.accounts = accounts
|
|
|
|
subscriptions.accounts = accounts
|
|
|
|
|
|
|
|
comments.player = player
|
|
|
|
|
|
|
|
menu.accounts = accounts
|
|
|
|
menu.navigation = navigation
|
|
|
|
menu.player = player
|
|
|
|
|
|
|
|
player.accounts = accounts
|
|
|
|
player.comments = comments
|
2022-06-30 04:14:32 +05:30
|
|
|
player.navigation = navigation
|
2022-06-18 18:09:49 +05:30
|
|
|
|
2022-09-02 04:35:31 +05:30
|
|
|
PlayerModel.shared = player
|
2022-09-01 00:54:46 +05:30
|
|
|
PlayerTimeModel.shared.player = player
|
|
|
|
|
2022-06-18 18:09:49 +05:30
|
|
|
if !accounts.current.isNil {
|
|
|
|
player.restoreQueue()
|
|
|
|
}
|
|
|
|
|
|
|
|
if !Defaults[.saveRecents] {
|
|
|
|
recents.clear()
|
|
|
|
}
|
|
|
|
|
|
|
|
var section = Defaults[.visibleSections].min()?.tabSelection
|
|
|
|
|
|
|
|
#if os(macOS)
|
|
|
|
if section == .playlists {
|
|
|
|
section = .search
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
navigation.tabSelection = section ?? .search
|
|
|
|
|
2022-08-15 18:19:12 +05:30
|
|
|
NavigationModel.shared = navigation
|
|
|
|
|
2022-06-18 18:09:49 +05:30
|
|
|
subscriptions.load()
|
|
|
|
playlists.load()
|
|
|
|
|
2022-08-29 19:01:36 +05:30
|
|
|
#if !os(macOS)
|
2022-07-11 21:40:51 +05:30
|
|
|
player.updateRemoteCommandCenter()
|
2022-06-18 18:09:49 +05:30
|
|
|
#endif
|
2022-08-08 23:32:46 +05:30
|
|
|
|
2022-08-14 22:29:04 +05:30
|
|
|
if player.presentingPlayer {
|
|
|
|
player.presentingPlayer = false
|
|
|
|
}
|
2022-08-21 20:23:46 +05:30
|
|
|
|
|
|
|
#if os(iOS)
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
|
|
|
if Defaults[.lockPortraitWhenBrowsing] {
|
|
|
|
Orientation.lockOrientation(.portrait, andRotateTo: .portrait)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-08-27 02:14:02 +05:30
|
|
|
|
|
|
|
#if !os(macOS)
|
|
|
|
try? AVAudioSession.sharedInstance().setCategory(.playback)
|
|
|
|
try? AVAudioSession.sharedInstance().setActive(true)
|
|
|
|
#endif
|
2022-06-18 18:09:49 +05:30
|
|
|
}
|
2022-08-26 05:06:46 +05:30
|
|
|
|
|
|
|
func migrateAccounts() {
|
|
|
|
Defaults[.accounts].forEach { account in
|
|
|
|
if !account.username.isEmpty || !(account.password?.isEmpty ?? true) || !(account.name?.isEmpty ?? true) {
|
|
|
|
print("Account needs migration: \(account.description)")
|
|
|
|
if account.app == .invidious {
|
|
|
|
if let name = account.name, !name.isEmpty {
|
|
|
|
AccountsModel.setCredentials(account, username: name, password: "")
|
|
|
|
}
|
|
|
|
if !account.username.isEmpty {
|
|
|
|
AccountsModel.setToken(account, account.username)
|
|
|
|
}
|
|
|
|
} else if account.app == .piped,
|
|
|
|
!account.username.isEmpty,
|
|
|
|
let password = account.password,
|
|
|
|
!password.isEmpty
|
|
|
|
{
|
|
|
|
AccountsModel.setCredentials(account, username: account.username, password: password)
|
|
|
|
}
|
|
|
|
|
|
|
|
AccountsModel.removeDefaultsCredentials(account)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-10 02:21:23 +05:30
|
|
|
}
|