Non propone più il link MLTV per sessioni YouTube; la pagina /live reindirizza a YouTube; il relay verso YouTube si riavvia al connect. Co-authored-by: Cursor <cursoragent@cursor.com>
194 lines
5.5 KiB
Dart
194 lines
5.5 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../shared/models/device_state.dart';
|
|
import '../shared/models/match.dart';
|
|
import '../shared/models/stream_session.dart';
|
|
|
|
class SessionState {
|
|
const SessionState({
|
|
this.session,
|
|
this.match,
|
|
this.elapsed = Duration.zero,
|
|
this.connected = false,
|
|
this.cameraDevice,
|
|
this.viewerCount = 0,
|
|
});
|
|
|
|
final StreamSession? session;
|
|
final MatchModel? match;
|
|
final Duration elapsed;
|
|
final bool connected;
|
|
final DeviceStateModel? cameraDevice;
|
|
final int viewerCount;
|
|
|
|
SessionState copyWith({
|
|
StreamSession? session,
|
|
MatchModel? match,
|
|
Duration? elapsed,
|
|
bool? connected,
|
|
DeviceStateModel? cameraDevice,
|
|
int? viewerCount,
|
|
}) {
|
|
return SessionState(
|
|
session: session ?? this.session,
|
|
match: match ?? this.match,
|
|
elapsed: elapsed ?? this.elapsed,
|
|
connected: connected ?? this.connected,
|
|
cameraDevice: cameraDevice ?? this.cameraDevice,
|
|
viewerCount: viewerCount ?? this.viewerCount,
|
|
);
|
|
}
|
|
}
|
|
|
|
class SessionNotifier extends StateNotifier<SessionState> {
|
|
SessionNotifier() : super(const SessionState());
|
|
|
|
void setSession(StreamSession session, {MatchModel? match}) {
|
|
state = state.copyWith(session: session, match: match);
|
|
}
|
|
|
|
void updateYoutubeLinks({
|
|
required String? youtubeWatchUrl,
|
|
required String? shareUrl,
|
|
String? youtubeBroadcastId,
|
|
bool youtubeReady = true,
|
|
}) {
|
|
final s = state.session;
|
|
if (s == null || s.platform != 'youtube') return;
|
|
state = state.copyWith(
|
|
session: StreamSession(
|
|
id: s.id,
|
|
matchId: s.matchId,
|
|
status: s.status,
|
|
platform: s.platform,
|
|
rtmpIngestUrl: s.rtmpIngestUrl,
|
|
hlsPlaybackUrl: s.hlsPlaybackUrl,
|
|
watchPageUrl: s.watchPageUrl,
|
|
shareUrl: shareUrl,
|
|
youtubeWatchUrl: youtubeWatchUrl,
|
|
youtubeBroadcastId: youtubeBroadcastId ?? s.youtubeBroadcastId,
|
|
youtubeReady: youtubeReady,
|
|
privacyStatus: s.privacyStatus,
|
|
qualityPreset: s.qualityPreset,
|
|
targetBitrate: s.targetBitrate,
|
|
startedAt: s.startedAt,
|
|
disconnectionCount: s.disconnectionCount,
|
|
score: s.score,
|
|
devices: s.devices,
|
|
),
|
|
);
|
|
}
|
|
|
|
void setMatch(MatchModel match) {
|
|
state = state.copyWith(match: match);
|
|
}
|
|
|
|
void setElapsed(Duration elapsed) {
|
|
state = state.copyWith(elapsed: elapsed);
|
|
}
|
|
|
|
void setConnected(bool connected) {
|
|
state = state.copyWith(connected: connected);
|
|
}
|
|
|
|
void setCameraDevice(DeviceStateModel? device) {
|
|
state = state.copyWith(cameraDevice: device);
|
|
}
|
|
|
|
void setViewerCount(int count) {
|
|
state = state.copyWith(viewerCount: count);
|
|
}
|
|
|
|
void updateDeviceState(DeviceStateModel device) {
|
|
if (device.deviceRole == 'camera') {
|
|
state = state.copyWith(cameraDevice: device);
|
|
}
|
|
if (device.status != null && state.session != null) {
|
|
final s = state.session!;
|
|
final incoming = device.status!;
|
|
// Non sovrascrivere una pausa intenzionale con stati transitori (live/connecting).
|
|
if (s.status == 'paused' && incoming != 'paused' && incoming != 'ended') {
|
|
state = state.copyWith(cameraDevice: device);
|
|
return;
|
|
}
|
|
state = state.copyWith(
|
|
session: StreamSession(
|
|
id: s.id,
|
|
matchId: s.matchId,
|
|
status: incoming,
|
|
platform: s.platform,
|
|
rtmpIngestUrl: s.rtmpIngestUrl,
|
|
hlsPlaybackUrl: s.hlsPlaybackUrl,
|
|
watchPageUrl: s.watchPageUrl,
|
|
shareUrl: s.shareUrl,
|
|
youtubeWatchUrl: s.youtubeWatchUrl,
|
|
youtubeBroadcastId: s.youtubeBroadcastId,
|
|
youtubeReady: s.youtubeReady,
|
|
privacyStatus: s.privacyStatus,
|
|
qualityPreset: s.qualityPreset,
|
|
targetBitrate: s.targetBitrate,
|
|
startedAt: s.startedAt,
|
|
disconnectionCount: s.disconnectionCount,
|
|
score: s.score,
|
|
devices: s.devices,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void applyCommand(String action) {
|
|
final session = state.session;
|
|
if (session == null) return;
|
|
|
|
String newStatus = session.status;
|
|
switch (action) {
|
|
case 'start_stream':
|
|
newStatus = 'live';
|
|
break;
|
|
case 'pause_stream':
|
|
newStatus = 'paused';
|
|
break;
|
|
case 'resume_stream':
|
|
newStatus = 'connecting';
|
|
break;
|
|
case 'stop_stream':
|
|
newStatus = 'ended';
|
|
break;
|
|
}
|
|
|
|
if (newStatus != session.status) {
|
|
state = state.copyWith(
|
|
session: StreamSession(
|
|
id: session.id,
|
|
matchId: session.matchId,
|
|
status: newStatus,
|
|
platform: session.platform,
|
|
rtmpIngestUrl: session.rtmpIngestUrl,
|
|
hlsPlaybackUrl: session.hlsPlaybackUrl,
|
|
watchPageUrl: session.watchPageUrl,
|
|
shareUrl: session.shareUrl,
|
|
youtubeWatchUrl: session.youtubeWatchUrl,
|
|
youtubeBroadcastId: session.youtubeBroadcastId,
|
|
youtubeReady: session.youtubeReady,
|
|
privacyStatus: session.privacyStatus,
|
|
qualityPreset: session.qualityPreset,
|
|
targetBitrate: session.targetBitrate,
|
|
startedAt: session.startedAt,
|
|
disconnectionCount: session.disconnectionCount,
|
|
score: session.score,
|
|
devices: session.devices,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void clear() {
|
|
state = const SessionState();
|
|
}
|
|
}
|
|
|
|
final sessionProvider =
|
|
StateNotifierProvider<SessionNotifier, SessionState>((ref) {
|
|
return SessionNotifier();
|
|
});
|