yattee/Shared/Settings/AdvancedSettings.swift
Toni Förster e44c7f84c8
MPV: speed up playback start
We initialize MPV with more options so it does not have to guess. This dramatically speeds up playback start.
2024-05-23 10:53:45 +02:00

302 lines
10 KiB
Swift

import Defaults
import SwiftUI
struct AdvancedSettings: View {
@Default(.showMPVPlaybackStats) private var showMPVPlaybackStats
@Default(.mpvCacheSecs) private var mpvCacheSecs
@Default(.mpvCachePauseWait) private var mpvCachePauseWait
@Default(.mpvCachePauseInital) private var mpvCachePauseInital
@Default(.mpvDeinterlace) private var mpvDeinterlace
@Default(.mpvEnableLogging) private var mpvEnableLogging
@Default(.mpvHWdec) private var mpvHWdec
@Default(.mpvDemuxerLavfProbeInfo) private var mpvDemuxerLavfProbeInfo
@Default(.showCacheStatus) private var showCacheStatus
@Default(.feedCacheSize) private var feedCacheSize
@Default(.showPlayNowInBackendContextMenu) private var showPlayNowInBackendContextMenu
@State private var filesToShare = [MPVClient.logFile]
@State private var presentingShareSheet = false
private var settings = SettingsModel.shared
var body: some View {
VStack(alignment: .leading) {
#if os(macOS)
advancedSettings
Spacer()
#else
List {
advancedSettings
}
#if os(iOS)
.sheet(isPresented: $presentingShareSheet) {
ShareSheet(activityItems: filesToShare)
.id("logs-\(filesToShare.count)")
}
.listStyle(.insetGrouped)
#endif
#endif
}
#if os(tvOS)
.frame(maxWidth: 1000)
#endif
.navigationTitle("Advanced")
}
var logButton: some View {
Button {
#if os(macOS)
NSWorkspace.shared.selectFile(MPVClient.logFile.path, inFileViewerRootedAtPath: YatteeApp.logsDirectory.path)
#else
presentingShareSheet = true
#endif
} label: {
#if os(macOS)
let labelText = "Open logs in Finder".localized()
#else
let labelText = "Share Logs...".localized()
#endif
Text(labelText)
}
}
@ViewBuilder var advancedSettings: some View {
Section(header: SettingsHeader(text: "Advanced")) {
showPlayNowInBackendButtonsToggle
}
Section(header: SettingsHeader(text: "MPV"), footer: mpvFooter) {
showMPVPlaybackStatsToggle
#if !os(tvOS)
mpvEnableLoggingToggle
#endif
Toggle(isOn: $mpvCachePauseInital) {
HStack {
Text("cache-pause-initial")
#if !os(tvOS)
Image(systemName: "link")
.accessibilityAddTraits([.isButton, .isLink])
.font(.footnote)
.onTapGesture {
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-pause-initial")!)
}
#if os(macOS)
.onHover(perform: onHover(_:))
#endif
#endif
}
}
HStack {
Text("cache-secs")
#if !os(tvOS)
Image(systemName: "link")
.accessibilityAddTraits([.isButton, .isLink])
.font(.footnote)
.onTapGesture {
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-secs")!)
}
#if os(macOS)
.onHover(perform: onHover(_:))
#endif
#endif
TextField("cache-secs", text: $mpvCacheSecs)
#if !os(macOS)
.keyboardType(.numberPad)
#endif
}
.multilineTextAlignment(.trailing)
HStack {
Group {
Text("cache-pause-wait")
#if !os(tvOS)
Image(systemName: "link")
.accessibilityAddTraits([.isButton, .isLink])
.font(.footnote)
.onTapGesture {
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-pause-wait")!)
}
#if os(macOS)
.onHover(perform: onHover(_:))
#endif
#endif
}.frame(minWidth: 140, alignment: .leading)
TextField("cache-pause-wait", text: $mpvCachePauseWait)
#if !os(macOS)
.keyboardType(.numberPad)
#endif
}
.multilineTextAlignment(.trailing)
Toggle(isOn: $mpvDeinterlace) {
HStack {
Text("deinterlace")
#if !os(tvOS)
Image(systemName: "link")
.accessibilityAddTraits([.isButton, .isLink])
.font(.footnote)
.onTapGesture {
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-deinterlace")!)
}
#if os(macOS)
.onHover(perform: onHover(_:))
#endif
#endif
}
}
HStack {
Text("hwdec")
#if !os(tvOS)
Image(systemName: "link")
.accessibilityAddTraits([.isButton, .isLink])
.font(.footnote)
.onTapGesture {
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-hwdec")!)
}
#if os(macOS)
.onHover( /* perform: onHover(_:) */ )
#endif
#endif
Picker("", selection: $mpvHWdec) {
ForEach(["auto", "auto-safe", "auto-copy"], id: \.self) {
Text($0)
}
}
.pickerStyle(MenuPickerStyle())
}
if mpvEnableLogging {
logButton
}
HStack {
Text("demuxer-lavf-probe-info")
#if !os(tvOS)
Image(systemName: "link")
.accessibilityAddTraits([.isButton, .isLink])
.font(.footnote)
.onTapGesture {
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-demuxer-lavf-probe-info")!)
}
#if os(macOS)
.onHover( /* perform: onHover(_:) */ )
#endif
#endif
Picker("", selection: $mpvDemuxerLavfProbeInfo) {
ForEach(["yes", "no", "auto", "nostreams"], id: \.self) {
Text($0)
}
}
.pickerStyle(MenuPickerStyle())
}
if mpvEnableLogging {
logButton
}
}
Section(header: SettingsHeader(text: "Cache"), footer: cacheSize) {
showCacheStatusToggle
feedCacheSizeTextField
clearCacheButton
}
}
@ViewBuilder var mpvFooter: some View {
let url = "https://mpv.io/manual/stable/"
VStack(alignment: .leading) {
Text("Restart the app to apply the settings above.")
.padding(.bottom, 1)
VStack(alignment: .leading, spacing: 2) {
#if os(tvOS)
Text("More info can be found in MPV reference manual:")
Text(url)
#else
Text("Further information can be found in the ")
+ Text("MPV reference manual").underline().bold()
+ Text(" by clicking on the link icon next to the option.")
#endif
}
}
.foregroundColor(.secondary)
}
var showPlayNowInBackendButtonsToggle: some View {
Toggle("Show video context menu options to force selected backend", isOn: $showPlayNowInBackendContextMenu)
}
var showMPVPlaybackStatsToggle: some View {
Toggle("Show playback statistics", isOn: $showMPVPlaybackStats)
}
var mpvEnableLoggingToggle: some View {
Toggle("Enable logging", isOn: $mpvEnableLogging)
}
#if os(macOS)
private func onHover(_ inside: Bool) {
if inside {
NSCursor.pointingHand.push()
} else {
NSCursor.pop()
}
}
#endif
private var feedCacheSizeTextField: some View {
HStack {
Text("Maximum feed items")
.frame(minWidth: 200, alignment: .leading)
.multilineTextAlignment(.leading)
TextField("Limit", text: $feedCacheSize)
.multilineTextAlignment(.trailing)
#if !os(macOS)
.keyboardType(.numberPad)
#endif
}
}
private var showCacheStatusToggle: some View {
Toggle("Show cache status", isOn: $showCacheStatus)
}
private var clearCacheButton: some View {
Button {
settings.presentAlert(
Alert(
title: Text(
"Are you sure you want to clear cache?"
),
primaryButton: .destructive(Text("Clear"), action: BaseCacheModel.shared.clear),
secondaryButton: .cancel()
)
)
} label: {
Text("Clear all")
.foregroundColor(.red)
}
}
var cacheSize: some View {
Text(String(format: "Total size: %@".localized(), BaseCacheModel.shared.totalSizeFormatted))
.foregroundColor(.secondary)
}
}
struct AdvancedSettings_Previews: PreviewProvider {
static var previews: some View {
AdvancedSettings()
.injectFixtureEnvironmentObjects()
}
}