Features: - VOD library with movie grouping and version detection - TV show library with season/episode organization - TMDB integration for trending shows and recently aired episodes - Recent releases section with TMDB release date sorting - Watch history tracking with continue watching - Playlist caching (12-hour TTL) for offline support - M3U playlist parsing with XStream API support - Authentication with credential storage Technical: - SwiftUI for tvOS - Actor-based services for thread safety - Persistent caching for playlists, TMDB data, and watch history - KSPlayer integration for video playback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
226 lines
6.5 KiB
Swift
226 lines
6.5 KiB
Swift
//
|
|
// Defaults.swift
|
|
// TracyPlayer
|
|
//
|
|
// Created by kintan on 2023/7/21.
|
|
//
|
|
|
|
import Foundation
|
|
import KSPlayer
|
|
import SwiftUI
|
|
|
|
public class Defaults: ObservableObject {
|
|
@AppStorage("showRecentPlayList") public var showRecentPlayList = false
|
|
|
|
@AppStorage("hardwareDecode")
|
|
public var hardwareDecode = KSOptions.hardwareDecode {
|
|
didSet {
|
|
KSOptions.hardwareDecode = hardwareDecode
|
|
}
|
|
}
|
|
|
|
@AppStorage("asynchronousDecompression")
|
|
public var asynchronousDecompression = KSOptions.asynchronousDecompression {
|
|
didSet {
|
|
KSOptions.asynchronousDecompression = asynchronousDecompression
|
|
}
|
|
}
|
|
|
|
@AppStorage("isUseDisplayLayer")
|
|
public var isUseDisplayLayer = MEOptions.isUseDisplayLayer {
|
|
didSet {
|
|
MEOptions.isUseDisplayLayer = isUseDisplayLayer
|
|
}
|
|
}
|
|
|
|
@AppStorage("preferredForwardBufferDuration")
|
|
public var preferredForwardBufferDuration = KSOptions.preferredForwardBufferDuration {
|
|
didSet {
|
|
KSOptions.preferredForwardBufferDuration = preferredForwardBufferDuration
|
|
}
|
|
}
|
|
|
|
@AppStorage("maxBufferDuration")
|
|
public var maxBufferDuration = KSOptions.maxBufferDuration {
|
|
didSet {
|
|
KSOptions.maxBufferDuration = maxBufferDuration
|
|
}
|
|
}
|
|
|
|
@AppStorage("isLoopPlay")
|
|
public var isLoopPlay = KSOptions.isLoopPlay {
|
|
didSet {
|
|
KSOptions.isLoopPlay = isLoopPlay
|
|
}
|
|
}
|
|
|
|
@AppStorage("canBackgroundPlay")
|
|
public var canBackgroundPlay = true {
|
|
didSet {
|
|
KSOptions.canBackgroundPlay = canBackgroundPlay
|
|
}
|
|
}
|
|
|
|
@AppStorage("isAutoPlay")
|
|
public var isAutoPlay = true {
|
|
didSet {
|
|
KSOptions.isAutoPlay = isAutoPlay
|
|
}
|
|
}
|
|
|
|
@AppStorage("isSecondOpen")
|
|
public var isSecondOpen = true {
|
|
didSet {
|
|
KSOptions.isSecondOpen = isSecondOpen
|
|
}
|
|
}
|
|
|
|
@AppStorage("isAccurateSeek")
|
|
public var isAccurateSeek = true {
|
|
didSet {
|
|
KSOptions.isAccurateSeek = isAccurateSeek
|
|
}
|
|
}
|
|
|
|
@AppStorage("isPipPopViewController")
|
|
public var isPipPopViewController = true {
|
|
didSet {
|
|
KSOptions.isPipPopViewController = isPipPopViewController
|
|
}
|
|
}
|
|
|
|
@AppStorage("textFontSize")
|
|
public var textFontSize = SubtitleModel.textFontSize {
|
|
didSet {
|
|
SubtitleModel.textFontSize = textFontSize
|
|
}
|
|
}
|
|
|
|
@AppStorage("textBold")
|
|
public var textBold = SubtitleModel.textBold {
|
|
didSet {
|
|
SubtitleModel.textBold = textBold
|
|
}
|
|
}
|
|
|
|
@AppStorage("textItalic")
|
|
public var textItalic = SubtitleModel.textItalic {
|
|
didSet {
|
|
SubtitleModel.textItalic = textItalic
|
|
}
|
|
}
|
|
|
|
@AppStorage("textColor")
|
|
public var textColor = SubtitleModel.textColor {
|
|
didSet {
|
|
SubtitleModel.textColor = textColor
|
|
}
|
|
}
|
|
|
|
@AppStorage("textBackgroundColor")
|
|
public var textBackgroundColor = SubtitleModel.textBackgroundColor {
|
|
didSet {
|
|
SubtitleModel.textBackgroundColor = textBackgroundColor
|
|
}
|
|
}
|
|
|
|
@AppStorage("horizontalAlign")
|
|
public var horizontalAlign = SubtitleModel.textPosition.horizontalAlign {
|
|
didSet {
|
|
SubtitleModel.textPosition.horizontalAlign = horizontalAlign
|
|
}
|
|
}
|
|
|
|
@AppStorage("verticalAlign")
|
|
public var verticalAlign = SubtitleModel.textPosition.verticalAlign {
|
|
didSet {
|
|
SubtitleModel.textPosition.verticalAlign = verticalAlign
|
|
}
|
|
}
|
|
|
|
@AppStorage("leftMargin")
|
|
public var leftMargin = SubtitleModel.textPosition.leftMargin {
|
|
didSet {
|
|
SubtitleModel.textPosition.leftMargin = leftMargin
|
|
}
|
|
}
|
|
|
|
@AppStorage("rightMargin")
|
|
public var rightMargin = SubtitleModel.textPosition.rightMargin {
|
|
didSet {
|
|
SubtitleModel.textPosition.rightMargin = rightMargin
|
|
}
|
|
}
|
|
|
|
@AppStorage("verticalMargin")
|
|
public var verticalMargin = SubtitleModel.textPosition.verticalMargin {
|
|
didSet {
|
|
SubtitleModel.textPosition.verticalMargin = verticalMargin
|
|
}
|
|
}
|
|
|
|
@AppStorage("yadifMode")
|
|
public var yadifMode = MEOptions.yadifMode {
|
|
didSet {
|
|
MEOptions.yadifMode = yadifMode
|
|
}
|
|
}
|
|
|
|
@AppStorage("audioPlayerType")
|
|
public var audioPlayerType = NSStringFromClass(KSOptions.audioPlayerType) {
|
|
didSet {
|
|
KSOptions.audioPlayerType = NSClassFromString(audioPlayerType) as! any AudioOutput.Type
|
|
}
|
|
}
|
|
|
|
public static let shared = Defaults()
|
|
private init() {
|
|
KSOptions.hardwareDecode = hardwareDecode
|
|
MEOptions.isUseDisplayLayer = isUseDisplayLayer
|
|
SubtitleModel.textFontSize = textFontSize
|
|
SubtitleModel.textBold = textBold
|
|
SubtitleModel.textItalic = textItalic
|
|
SubtitleModel.textColor = textColor
|
|
SubtitleModel.textBackgroundColor = textBackgroundColor
|
|
SubtitleModel.textPosition.horizontalAlign = horizontalAlign
|
|
SubtitleModel.textPosition.verticalAlign = verticalAlign
|
|
SubtitleModel.textPosition.leftMargin = leftMargin
|
|
SubtitleModel.textPosition.rightMargin = rightMargin
|
|
SubtitleModel.textPosition.verticalMargin = verticalMargin
|
|
KSOptions.preferredForwardBufferDuration = preferredForwardBufferDuration
|
|
KSOptions.maxBufferDuration = maxBufferDuration
|
|
KSOptions.isLoopPlay = isLoopPlay
|
|
KSOptions.canBackgroundPlay = canBackgroundPlay
|
|
KSOptions.isAutoPlay = isAutoPlay
|
|
KSOptions.isSecondOpen = isSecondOpen
|
|
KSOptions.isAccurateSeek = isAccurateSeek
|
|
KSOptions.isPipPopViewController = isPipPopViewController
|
|
MEOptions.yadifMode = yadifMode
|
|
KSOptions.audioPlayerType = NSClassFromString(audioPlayerType) as! any AudioOutput.Type
|
|
}
|
|
}
|
|
|
|
@propertyWrapper
|
|
public struct Default<T>: DynamicProperty {
|
|
@ObservedObject private var defaults: Defaults
|
|
private let keyPath: ReferenceWritableKeyPath<Defaults, T>
|
|
public init(_ keyPath: ReferenceWritableKeyPath<Defaults, T>, defaults: Defaults = .shared) {
|
|
self.keyPath = keyPath
|
|
self.defaults = defaults
|
|
}
|
|
|
|
public var wrappedValue: T {
|
|
get { defaults[keyPath: keyPath] }
|
|
nonmutating set { defaults[keyPath: keyPath] = newValue }
|
|
}
|
|
|
|
public var projectedValue: Binding<T> {
|
|
Binding(
|
|
get: { defaults[keyPath: keyPath] },
|
|
set: { value in
|
|
defaults[keyPath: keyPath] = value
|
|
}
|
|
)
|
|
}
|
|
}
|