mirror of
https://github.com/yattee/yattee.git
synced 2024-12-13 22:00:31 +05:30
2e9cceafa5
We generate a User-Agent for the platform we are running on and add it to the URLTester requests and also to MPV and AVPlayer
261 lines
9.0 KiB
Swift
261 lines
9.0 KiB
Swift
import Defaults
|
|
import MediaPlayer
|
|
import PINCache
|
|
import SDWebImage
|
|
import SDWebImageWebPCoder
|
|
import Siesta
|
|
import SwiftUI
|
|
|
|
@main
|
|
struct YatteeApp: App {
|
|
static var version: String {
|
|
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown"
|
|
}
|
|
|
|
static var build: String {
|
|
Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
|
|
}
|
|
|
|
static var isForPreviews: Bool {
|
|
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
|
|
}
|
|
|
|
static var logsDirectory: URL {
|
|
temporaryDirectory
|
|
}
|
|
|
|
static var settingsExportDirectory: URL {
|
|
temporaryDirectory
|
|
}
|
|
|
|
private static var temporaryDirectory: URL {
|
|
URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
|
|
}
|
|
|
|
#if os(macOS)
|
|
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
|
#elseif os(iOS)
|
|
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
|
#endif
|
|
|
|
@State private var configured = false
|
|
|
|
@StateObject private var accounts = AccountsModel.shared
|
|
@StateObject private var comments = CommentsModel.shared
|
|
@StateObject private var instances = InstancesModel.shared
|
|
@StateObject private var menu = MenuModel.shared
|
|
@StateObject private var navigation = NavigationModel.shared
|
|
@StateObject private var networkState = NetworkStateModel.shared
|
|
@StateObject private var player = PlayerModel.shared
|
|
@StateObject private var playlists = PlaylistsModel.shared
|
|
@StateObject private var recents = RecentsModel.shared
|
|
@StateObject private var settings = SettingsModel.shared
|
|
@StateObject private var subscriptions = SubscribedChannelsModel.shared
|
|
@StateObject private var thumbnails = ThumbnailsModel.shared
|
|
|
|
let persistenceController = PersistenceController.shared
|
|
|
|
var favorites: FavoritesModel { .shared }
|
|
var playerControls: PlayerControlsModel { .shared }
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
ContentView()
|
|
.onAppear(perform: configure)
|
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
|
.environment(\.navigationStyle, navigationStyle)
|
|
#if os(macOS)
|
|
.background(
|
|
HostingWindowFinder { window in
|
|
Windows.mainWindow = window
|
|
}
|
|
)
|
|
#else
|
|
.onReceive(
|
|
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
|
|
) { _ in
|
|
player.handleEnterForeground()
|
|
}
|
|
.onReceive(
|
|
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
|
|
) { _ in
|
|
player.handleEnterBackground()
|
|
}
|
|
#endif
|
|
#if os(iOS)
|
|
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
|
|
#endif
|
|
#if !os(tvOS)
|
|
.onOpenURL { url in
|
|
URLBookmarkModel.shared.saveBookmark(url)
|
|
OpenURLHandler(navigationStyle: navigationStyle).handle(url)
|
|
}
|
|
#endif
|
|
}
|
|
#if os(iOS)
|
|
.handlesExternalEvents(matching: Set(["*"]))
|
|
#endif
|
|
#if !os(tvOS)
|
|
.commands {
|
|
SidebarCommands()
|
|
|
|
CommandGroup(replacing: .newItem, addition: {})
|
|
|
|
MenuCommands(model: Binding<MenuModel>(get: { MenuModel.shared }, set: { _ in }))
|
|
}
|
|
#endif
|
|
|
|
#if os(macOS)
|
|
WindowGroup(player.windowTitle) {
|
|
VideoPlayerView()
|
|
.onAppear(perform: configure)
|
|
.background(
|
|
HostingWindowFinder { window in
|
|
Windows.playerWindow = window
|
|
|
|
NotificationCenter.default.addObserver( // swiftlint:disable:this discarded_notification_center_observer
|
|
forName: NSWindow.willExitFullScreenNotification,
|
|
object: window,
|
|
queue: OperationQueue.main
|
|
) { _ in
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
self.player.playingFullScreen = false
|
|
}
|
|
}
|
|
}
|
|
)
|
|
.onAppear { player.presentingPlayer = true }
|
|
.onDisappear { player.presentingPlayer = false }
|
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
|
.environment(\.navigationStyle, .sidebar)
|
|
.handlesExternalEvents(preferring: Set(["player", "*"]), allowing: Set(["player", "*"]))
|
|
.onOpenURL { url in
|
|
URLBookmarkModel.shared.saveBookmark(url)
|
|
OpenURLHandler(navigationStyle: navigationStyle).handle(url)
|
|
}
|
|
}
|
|
.handlesExternalEvents(matching: Set(["player", "*"]))
|
|
|
|
Settings {
|
|
SettingsView()
|
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
|
}
|
|
#endif
|
|
}
|
|
|
|
func configure() {
|
|
guard !Self.isForPreviews, !configured else {
|
|
return
|
|
}
|
|
configured = true
|
|
|
|
DispatchQueue.main.async {
|
|
#if DEBUG
|
|
SiestaLog.Category.enabled = .common
|
|
#endif
|
|
SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)
|
|
SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app")
|
|
|
|
if !Defaults[.lastAccountIsPublic] {
|
|
AccountsModel.shared.configureAccount()
|
|
}
|
|
|
|
if let countryOfPublicInstances = Defaults[.countryOfPublicInstances] {
|
|
InstancesManifest.shared.setPublicAccount(countryOfPublicInstances, asCurrent: AccountsModel.shared.current.isNil)
|
|
}
|
|
|
|
if !AccountsModel.shared.current.isNil {
|
|
player.restoreQueue()
|
|
}
|
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
if !Defaults[.saveRecents] {
|
|
recents.clear()
|
|
}
|
|
}
|
|
|
|
let startupSection = Defaults[.startupSection]
|
|
var section: TabSelection? = startupSection.tabSelection
|
|
|
|
#if os(macOS)
|
|
if section == .playlists {
|
|
section = .search
|
|
}
|
|
#endif
|
|
|
|
NavigationModel.shared.tabSelection = section ?? .search
|
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
playlists.load()
|
|
}
|
|
|
|
#if !os(macOS)
|
|
player.updateRemoteCommandCenter()
|
|
#endif
|
|
|
|
if player.presentingPlayer {
|
|
player.presentingPlayer = false
|
|
}
|
|
|
|
#if os(iOS)
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
|
if Defaults[.lockPortraitWhenBrowsing] {
|
|
Orientation.lockOrientation(.all, andRotateTo: .portrait)
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Initialize UserAgentManager
|
|
_ = UserAgentManager.shared
|
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
URLBookmarkModel.shared.refreshAll()
|
|
}
|
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
self.migrateHomeHistoryItems()
|
|
}
|
|
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
self.migrateQualityProfiles()
|
|
}
|
|
}
|
|
}
|
|
|
|
func migrateHomeHistoryItems() {
|
|
guard Defaults[.homeHistoryItems] > 0 else { return }
|
|
|
|
if favorites.addableItems().contains(where: { $0.section == .history }) {
|
|
let historyItem = FavoriteItem(section: .history)
|
|
favorites.add(historyItem)
|
|
favorites.setListingStyle(.list, historyItem)
|
|
favorites.setLimit(Defaults[.homeHistoryItems], historyItem)
|
|
|
|
print("migrated home history items: \(favorites.limit(historyItem))")
|
|
}
|
|
|
|
Defaults[.homeHistoryItems] = -1
|
|
}
|
|
|
|
@Default(.qualityProfiles) private var qualityProfilesData
|
|
|
|
func migrateQualityProfiles() {
|
|
for profile in qualityProfilesData where profile.order.isEmpty {
|
|
var updatedProfile = profile
|
|
updatedProfile.order = Array(QualityProfile.Format.allCases.indices)
|
|
QualityProfilesModel.shared.update(profile, updatedProfile)
|
|
}
|
|
}
|
|
|
|
var navigationStyle: NavigationStyle {
|
|
#if os(iOS)
|
|
return horizontalSizeClass == .compact ? .tab : .sidebar
|
|
#elseif os(tvOS)
|
|
return .tab
|
|
#else
|
|
return .sidebar
|
|
#endif
|
|
}
|
|
}
|