Evita patch recording ripetute che distruggevano i muxer HLS (500 ops) e fa encoderare 1080p/720p con codec e bitrate coerenti al wizard. Co-authored-by: Cursor <cursoragent@cursor.com>
139 lines
3.9 KiB
Swift
139 lines
3.9 KiB
Swift
import Foundation
|
|
|
|
struct User: Codable, Equatable, Sendable {
|
|
let id: String
|
|
let email: String
|
|
let name: String
|
|
let role: String
|
|
}
|
|
|
|
struct AuthTokens: Sendable {
|
|
let accessToken: String
|
|
let refreshToken: String
|
|
}
|
|
|
|
struct SportOption: Identifiable, Equatable, Sendable {
|
|
var id: String { key }
|
|
let key: String
|
|
let label: String
|
|
let board: String
|
|
let overlay: String
|
|
let allowedOverlays: [String]
|
|
let defaultRules: [String: Int]
|
|
}
|
|
|
|
struct Team: Identifiable, Equatable, Sendable {
|
|
let id: String
|
|
let name: String
|
|
let sport: String
|
|
let sportKey: String
|
|
let boardType: String
|
|
let clubName: String?
|
|
let logoUrl: String?
|
|
let primaryColor: String?
|
|
let secondaryColor: String?
|
|
let canStream: Bool
|
|
let youtubeEnabled: Bool
|
|
let youtubeConnected: Bool
|
|
let youtubeSelectable: Bool
|
|
let youtubeChannelTitle: String?
|
|
let youtubeUsesPlatformChannel: Bool
|
|
let youtubeTeamChannelTitle: String?
|
|
let planName: String?
|
|
let recordingsEnabled: Bool
|
|
let phoneDownloadEnabled: Bool
|
|
let billingUrl: String?
|
|
let staffManageUrl: String?
|
|
|
|
var canUseYoutube: Bool { youtubeEnabled }
|
|
var isYoutubeReady: Bool { youtubeSelectable }
|
|
|
|
var effectiveYoutubeChannel: String? {
|
|
guard isYoutubeReady else { return nil }
|
|
return youtubeUsesPlatformChannel ? "platform" : "team"
|
|
}
|
|
|
|
var youtubeDestinationLabel: String {
|
|
if youtubeUsesPlatformChannel { return "Canale Match Live TV" }
|
|
let name = youtubeTeamChannelTitle?.trimmingCharacters(in: .whitespacesAndNewlines).nilIfEmpty
|
|
?? clubName?.trimmingCharacters(in: .whitespacesAndNewlines).nilIfEmpty
|
|
?? "società"
|
|
return "Canale società · \(name)"
|
|
}
|
|
}
|
|
|
|
struct ScoringRules: Equatable, Sendable {
|
|
var pointsPerSet: Int = 25
|
|
var pointsDecidingSet: Int = 15
|
|
var minPointLead: Int = 2
|
|
var periods: Int = 4
|
|
var periodDurationSecs: Int = 600
|
|
var overtimeDurationSecs: Int = 300
|
|
}
|
|
|
|
struct Match: Identifiable, Equatable, Sendable {
|
|
let id: String
|
|
let teamId: String
|
|
let teamName: String
|
|
let opponentName: String
|
|
let location: String?
|
|
let scheduledAt: String?
|
|
let sportKey: String
|
|
let sportLabel: String?
|
|
let boardType: String
|
|
let overlayKind: String?
|
|
let effectiveOverlayKind: String
|
|
let setsToWin: Int
|
|
let category: String?
|
|
let scoringRules: ScoringRules?
|
|
let activeSessionId: String?
|
|
let activeSessionStatus: String?
|
|
let streamCompleted: Bool
|
|
let coachHubVisible: Bool?
|
|
let homePrimaryColor: String?
|
|
let homeSecondaryColor: String?
|
|
let homeLogoUrl: String?
|
|
let opponentPrimaryColor: String?
|
|
let opponentLogoUrl: String?
|
|
|
|
var hasActiveSession: Bool { activeSessionId != nil }
|
|
|
|
var canResumeCamera: Bool {
|
|
guard let status = activeSessionStatus, activeSessionId != nil else { return false }
|
|
return ["connecting", "live", "reconnecting", "paused"].contains(status)
|
|
}
|
|
}
|
|
|
|
struct StreamSession: Identifiable, Equatable, Sendable {
|
|
let id: String
|
|
let matchId: String
|
|
let status: String
|
|
let platform: String
|
|
let rtmpIngestUrl: String?
|
|
let hlsPlaybackUrl: String?
|
|
let watchPageUrl: String?
|
|
let shareUrl: String?
|
|
let youtubeWatchUrl: String?
|
|
let youtubeReady: Bool
|
|
let privacyStatus: String
|
|
let targetBitrate: Int
|
|
let targetFps: Int
|
|
let qualityPreset: String
|
|
let startedAt: String?
|
|
let score: ScoreState?
|
|
|
|
var isLive: Bool { status == "live" || status == "reconnecting" }
|
|
var isPaused: Bool { status == "paused" }
|
|
|
|
func watchShareUrl() -> String? {
|
|
if platform == "youtube", let url = youtubeWatchUrl, !url.isEmpty { return url }
|
|
if let url = shareUrl, !url.isEmpty { return url }
|
|
if let url = watchPageUrl, !url.isEmpty { return url }
|
|
return nil
|
|
}
|
|
}
|
|
|
|
private extension String {
|
|
var nilIfEmpty: String? { isEmpty ? nil : self }
|
|
}
|