NuvioStreaming/MPVKit/Sources/DesktopMPVBridge/NuvioPlayerState.swift

219 lines
7.3 KiB
Swift

import Foundation
import AppKit
enum GestureFeedbackIcon {
case speed
case volume
case volumeMuted
case seekForward
case seekBackward
}
struct GestureFeedbackState {
let message: String
let icon: GestureFeedbackIcon
let isDanger: Bool
init(message: String, icon: GestureFeedbackIcon = .speed, isDanger: Bool = false) {
self.message = message
self.icon = icon
self.isDanger = isDanger
}
}
struct NuvioTrackInfo {
let index: Int
let id: Int
let type: String
let title: String
let lang: String
var selected: Bool
}
struct NuvioStreamInfo: Identifiable {
let id: String
let label: String
let subtitle: String?
let addonName: String
let addonId: String
let url: String
let isCurrent: Bool
}
struct NuvioAddonGroupInfo: Identifiable {
let id: String
let addonName: String
let addonId: String
let isLoading: Bool
let hasError: Bool
}
struct NuvioEpisodeInfo: Identifiable {
let id: String
let title: String
let overview: String?
let thumbnail: String?
let season: Int?
let episode: Int?
}
final class NuvioPlayerState: ObservableObject {
@Published var isLoading: Bool = true
@Published var isPlaying: Bool = false
@Published var isEnded: Bool = false
@Published var positionMs: Int64 = 0
@Published var durationMs: Int64 = 0
@Published var bufferedMs: Int64 = 0
@Published var currentSpeed: Float = 1.0
@Published var resizeMode: Int = 0
@Published var controlsVisible: Bool = true
@Published var cursorHidden: Bool = false
@Published var controlsLocked: Bool = false
@Published var lockedOverlayVisible: Bool = false
@Published var title: String = ""
@Published var streamTitle: String = ""
@Published var providerName: String = ""
@Published var seasonNumber: Int? = nil
@Published var episodeNumber: Int? = nil
@Published var episodeTitle: String? = nil
@Published var artwork: String? = nil
@Published var logo: String? = nil
@Published var initialLoadCompleted: Bool = false
@Published var audioTracks: [NuvioTrackInfo] = []
@Published var subtitleTracks: [NuvioTrackInfo] = []
@Published var errorMessage: String? = nil
@Published var showSubtitlePanel: Bool = false
@Published var showAudioPanel: Bool = false
@Published var skipButtonType: String? = nil
var skipEndTimeMs: Int64 = 0
@Published var nextEpisodeSeason: Int? = nil
@Published var nextEpisodeEpisode: Int? = nil
@Published var nextEpisodeTitle: String? = nil
@Published var nextEpisodeThumbnail: String? = nil
@Published var nextEpisodeHasAired: Bool = true
@Published var showNextEpisode: Bool = false
var isClosed: Bool = false
var nextEpisodePressed: Bool = false
@Published var gestureFeedback: GestureFeedbackState? = nil
@Published var subtitleStyleTextColor: Int = 0
@Published var subtitleStyleFontSize: Int = 18
@Published var subtitleStyleOutlineEnabled: Bool = false
@Published var subtitleStyleBottomOffset: Int = 20
@Published var addonSubtitles: [AddonSubtitleInfo] = []
@Published var addonSubtitlesLoading: Bool = false
@Published var selectedAddonSubtitleId: String? = nil
@Published var subtitleTab: Int = 0
var addonSubtitlesFetchRequested: Bool = false
var subtitleStyleDirty: Bool = false
@Published var showSourcesPanel: Bool = false
@Published var showEpisodesPanel: Bool = false
@Published var hasVideoId: Bool = false
@Published var isSeries: Bool = false
@Published var canSubmitIntro: Bool = false
@Published var showSubmitIntroPanel: Bool = false
@Published var sourceStreams: [NuvioStreamInfo] = []
@Published var sourceAddonGroups: [NuvioAddonGroupInfo] = []
@Published var sourceSelectedFilter: String? = nil
@Published var sourcesLoading: Bool = false
@Published var episodes: [NuvioEpisodeInfo] = []
@Published var episodeStreams: [NuvioStreamInfo] = []
@Published var episodeAddonGroups: [NuvioAddonGroupInfo] = []
@Published var episodeSelectedFilter: String? = nil
@Published var episodeStreamsLoading: Bool = false
@Published var showEpisodeStreams: Bool = false
@Published var selectedEpisodeSeason: Int? = nil
@Published var selectedEpisodeNumber: Int? = nil
@Published var selectedEpisodeTitle: String? = nil
var sourcesOpenRequested: Bool = false
var episodesOpenRequested: Bool = false
var sourceStreamSelectedUrl: String? = nil
var sourceFilterSelectedValue: String? = nil
var sourceFilterChanged: Bool = false
var sourceReloadRequested: Bool = false
var episodeSelectedId: String? = nil
var episodeStreamSelectedUrl: String? = nil
var episodeFilterSelectedValue: String? = nil
var episodeFilterChanged: Bool = false
var episodeReloadRequested: Bool = false
var episodeBackRequested: Bool = false
var submitIntroRequested: Bool = false
var submitIntroSegmentType: String = "intro"
var submitIntroStartSec: Double = 0
var submitIntroEndSec: Double = 0
var resizeModeLabel: String {
switch resizeMode {
case 1: return "Fill"
case 2: return "Zoom"
default: return "Fit"
}
}
var speedLabel: String {
let s = currentSpeed
if s == Float(Int(s)) {
return "\(Int(s))x"
}
let str = String(format: "%.2f", s)
let trimmed = str.replacingOccurrences(of: "0+$", with: "", options: .regularExpression)
.replacingOccurrences(of: "\\.$", with: "", options: .regularExpression)
return "\(trimmed)x"
}
func formattedTime(_ ms: Int64) -> String {
let totalSeconds = max(ms / 1000, 0)
let seconds = totalSeconds % 60
let minutes = (totalSeconds / 60) % 60
let hours = totalSeconds / 3600
if hours > 0 {
return "\(hours):\(String(format: "%02d", minutes)):\(String(format: "%02d", seconds))"
}
return "\(String(format: "%02d", minutes)):\(String(format: "%02d", seconds))"
}
var filteredSourceStreams: [NuvioStreamInfo] {
guard let filter = sourceSelectedFilter else { return sourceStreams }
return sourceStreams.filter { $0.addonId == filter }
}
var filteredEpisodeStreams: [NuvioStreamInfo] {
guard let filter = episodeSelectedFilter else { return episodeStreams }
return episodeStreams.filter { $0.addonId == filter }
}
}
struct AddonSubtitleInfo: Identifiable {
let id: String
let url: String
let language: String
let display: String
}
let subtitleColorSwatches: [(String, NSColor)] = [
("#FFFFFF", NSColor.white),
("#FFD700", NSColor(red: 1.0, green: 0.843, blue: 0.0, alpha: 1.0)),
("#00E5FF", NSColor(red: 0.0, green: 0.898, blue: 1.0, alpha: 1.0)),
("#FF5C5C", NSColor(red: 1.0, green: 0.361, blue: 0.361, alpha: 1.0)),
("#00FF88", NSColor(red: 0.0, green: 1.0, blue: 0.533, alpha: 1.0)),
("#9B59B6", NSColor(red: 0.608, green: 0.349, blue: 0.714, alpha: 1.0)),
("#F97316", NSColor(red: 0.976, green: 0.451, blue: 0.086, alpha: 1.0)),
("#22C55E", NSColor(red: 0.133, green: 0.773, blue: 0.369, alpha: 1.0)),
("#3B82F6", NSColor(red: 0.231, green: 0.510, blue: 0.965, alpha: 1.0)),
("#000000", NSColor.black),
]