Files
MatchLiveTv/native/ios/MatchLiveTv/Domain/Models.swift
T
eminuxandCursor 41d4235258 Aggiunge copertina sponsor custom solo Premium Full, con override in wizard e slate sui nodi di streaming.
Permette upload da portale e app con ereditarietà partita→squadra→società, generazione MP4 via ffmpeg e distribuzione su home lab e nodi CPX per pause e assenza segnale.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 23:47:17 +02:00

192 lines
5.7 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?
let customCoverEnabled: Bool
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 L10n.t("youtube.channel.platform") }
let name = youtubeTeamChannelTitle?.trimmingCharacters(in: .whitespacesAndNewlines).nilIfEmpty
?? clubName?.trimmingCharacters(in: .whitespacesAndNewlines).nilIfEmpty
?? L10n.t("youtube.channel.club.fallback")
return L10n.t("youtube.channel.club", 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?
let effectiveCoverUrl: String?
let coverSource: String
let customCoverEnabled: Bool
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 minQualityPreset: String
let startedAt: String?
let score: ScoreState?
let audioMuted: Bool
var isLive: Bool { status == "live" || status == "reconnecting" }
var isPaused: Bool { status == "paused" }
var isEnded: Bool { status == "ended" || status == "error" }
func with(minQualityPreset: String) -> StreamSession {
StreamSession(
id: id,
matchId: matchId,
status: status,
platform: platform,
rtmpIngestUrl: rtmpIngestUrl,
hlsPlaybackUrl: hlsPlaybackUrl,
watchPageUrl: watchPageUrl,
shareUrl: shareUrl,
youtubeWatchUrl: youtubeWatchUrl,
youtubeReady: youtubeReady,
privacyStatus: privacyStatus,
targetBitrate: targetBitrate,
targetFps: targetFps,
qualityPreset: qualityPreset,
minQualityPreset: minQualityPreset,
startedAt: startedAt,
score: score,
audioMuted: audioMuted
)
}
func withAudioMuted(_ muted: Bool) -> StreamSession {
StreamSession(
id: id,
matchId: matchId,
status: status,
platform: platform,
rtmpIngestUrl: rtmpIngestUrl,
hlsPlaybackUrl: hlsPlaybackUrl,
watchPageUrl: watchPageUrl,
shareUrl: shareUrl,
youtubeWatchUrl: youtubeWatchUrl,
youtubeReady: youtubeReady,
privacyStatus: privacyStatus,
targetBitrate: targetBitrate,
targetFps: targetFps,
qualityPreset: qualityPreset,
minQualityPreset: minQualityPreset,
startedAt: startedAt,
score: score,
audioMuted: muted
)
}
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 }
}