Premium Full può forzare il canale piattaforma; visibilità non in elenco o privato; share_url unificato per Match Live TV e YouTube. Co-authored-by: Cursor <cursoragent@cursor.com>
153 lines
4.3 KiB
Dart
153 lines
4.3 KiB
Dart
import 'device_state.dart';
|
|
import 'score_state.dart';
|
|
|
|
class StreamSession {
|
|
const StreamSession({
|
|
required this.id,
|
|
required this.matchId,
|
|
required this.status,
|
|
this.platform = 'matchlivetv',
|
|
this.rtmpIngestUrl,
|
|
this.hlsPlaybackUrl,
|
|
this.watchPageUrl,
|
|
this.shareUrl,
|
|
this.youtubeWatchUrl,
|
|
this.youtubeBroadcastId,
|
|
this.privacyStatus = 'unlisted',
|
|
this.qualityPreset = '720p_30_2.5mbps',
|
|
this.targetBitrate = 2500000,
|
|
this.startedAt,
|
|
this.disconnectionCount = 0,
|
|
this.score,
|
|
this.devices = const [],
|
|
});
|
|
|
|
final String id;
|
|
final String matchId;
|
|
final String status;
|
|
final String platform;
|
|
final String? rtmpIngestUrl;
|
|
final String? hlsPlaybackUrl;
|
|
final String? watchPageUrl;
|
|
final String? shareUrl;
|
|
final String? youtubeWatchUrl;
|
|
final String? youtubeBroadcastId;
|
|
final String privacyStatus;
|
|
final String qualityPreset;
|
|
final int targetBitrate;
|
|
final DateTime? startedAt;
|
|
final int disconnectionCount;
|
|
final ScoreState? score;
|
|
final List<DeviceStateModel> devices;
|
|
|
|
bool get isLive => status == 'live' || status == 'reconnecting';
|
|
|
|
bool get isTerminal => status == 'ended' || status == 'error';
|
|
|
|
bool get canResumeBroadcast =>
|
|
status == 'connecting' ||
|
|
status == 'live' ||
|
|
status == 'reconnecting' ||
|
|
status == 'paused';
|
|
|
|
factory StreamSession.fromJson(Map<String, dynamic> json) {
|
|
return StreamSession(
|
|
id: json['id'] as String,
|
|
matchId: json['match_id'] as String,
|
|
status: json['status'] as String? ?? 'idle',
|
|
platform: json['platform'] as String? ?? 'matchlivetv',
|
|
rtmpIngestUrl: json['rtmp_ingest_url'] as String?,
|
|
hlsPlaybackUrl: json['hls_playback_url'] as String?,
|
|
watchPageUrl: json['watch_page_url'] as String?,
|
|
shareUrl: json['share_url'] as String?,
|
|
youtubeWatchUrl: json['youtube_watch_url'] as String?,
|
|
youtubeBroadcastId: json['youtube_broadcast_id'] as String?,
|
|
privacyStatus: json['privacy_status'] as String? ?? 'unlisted',
|
|
qualityPreset: json['quality_preset'] as String? ?? '720p_30_2.5mbps',
|
|
targetBitrate: json['target_bitrate'] as int? ?? 2500000,
|
|
startedAt: json['started_at'] != null
|
|
? DateTime.tryParse(json['started_at'] as String)
|
|
: null,
|
|
disconnectionCount: json['disconnection_count'] as int? ?? 0,
|
|
score: json['score'] != null
|
|
? ScoreState.fromJson(json['score'] as Map<String, dynamic>)
|
|
: null,
|
|
devices: (json['devices'] as List<dynamic>?)
|
|
?.map((e) => DeviceStateModel.fromJson(e as Map<String, dynamic>))
|
|
.toList() ??
|
|
const [],
|
|
);
|
|
}
|
|
}
|
|
|
|
class RegiaLinkResponse {
|
|
const RegiaLinkResponse({
|
|
required this.regiaUrl,
|
|
required this.expiresAt,
|
|
});
|
|
|
|
final String regiaUrl;
|
|
final DateTime expiresAt;
|
|
|
|
factory RegiaLinkResponse.fromJson(Map<String, dynamic> json) {
|
|
return RegiaLinkResponse(
|
|
regiaUrl: json['regia_url'] as String,
|
|
expiresAt: DateTime.parse(json['expires_at'] as String),
|
|
);
|
|
}
|
|
}
|
|
|
|
class PairingTokenResponse {
|
|
const PairingTokenResponse({
|
|
required this.pairingToken,
|
|
required this.expiresAt,
|
|
required this.qrPayload,
|
|
});
|
|
|
|
final String pairingToken;
|
|
final DateTime expiresAt;
|
|
final Map<String, dynamic> qrPayload;
|
|
|
|
factory PairingTokenResponse.fromJson(Map<String, dynamic> json) {
|
|
return PairingTokenResponse(
|
|
pairingToken: json['pairing_token'] as String,
|
|
expiresAt: DateTime.parse(json['expires_at'] as String),
|
|
qrPayload: json['qr_payload'] as Map<String, dynamic>,
|
|
);
|
|
}
|
|
}
|
|
|
|
class NetworkTestResult {
|
|
const NetworkTestResult({
|
|
required this.ready,
|
|
required this.targetUploadMbps,
|
|
});
|
|
|
|
final bool ready;
|
|
final double targetUploadMbps;
|
|
|
|
factory NetworkTestResult.fromJson(Map<String, dynamic> json) {
|
|
return NetworkTestResult(
|
|
ready: json['ready'] as bool? ?? false,
|
|
targetUploadMbps: (json['target_upload_mbps'] as num?)?.toDouble() ?? 2.5,
|
|
);
|
|
}
|
|
}
|
|
|
|
class YoutubeStats {
|
|
const YoutubeStats({
|
|
required this.concurrentViewers,
|
|
required this.live,
|
|
});
|
|
|
|
final int concurrentViewers;
|
|
final bool live;
|
|
|
|
factory YoutubeStats.fromJson(Map<String, dynamic> json) {
|
|
return YoutubeStats(
|
|
concurrentViewers: json['concurrent_viewers'] as int? ?? 0,
|
|
live: json['live'] as bool? ?? false,
|
|
);
|
|
}
|
|
}
|