9103ff1fb7
- MVVM architecture (Models, ViewModels, Views, Services, Helpers) - Models: Scene, Source, StreamConfig, StreamHealth, YouTubeChannel, ChatMessage - Services: YouTubeAuthService (OAuth2), YouTubeStreamService (broadcasts/stream health), YouTubeChatService (live chat polling) - ViewModels: MainViewModel with scene management, stream controls, chat - MainWindow with dark theme: scene/source panel, preview area, chat panel, status bar - Version roadmap: v0.1 (scenes, RTMP, OAuth2, chat, health) -> 1.0
144 lines
4.2 KiB
C#
144 lines
4.2 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Windows.Input;
|
|
using ytLive.Helpers;
|
|
using ytLive.Models;
|
|
using ytLive.Services;
|
|
|
|
namespace ytLive.ViewModels;
|
|
|
|
public class MainViewModel : ViewModelBase
|
|
{
|
|
private readonly YouTubeAuthService _youtubeAuth;
|
|
private readonly YouTubeStreamService _youtubeStream;
|
|
private readonly YouTubeChatService _youtubeChat;
|
|
|
|
private Scene? _activeScene;
|
|
private StreamStatus _streamStatus = StreamStatus.Offline;
|
|
private StreamHealth _currentHealth = new();
|
|
private string _streamTitle = string.Empty;
|
|
private string _streamKey = string.Empty;
|
|
private bool _isYouTubeConnected;
|
|
|
|
public ObservableCollection<Scene> Scenes { get; } = new();
|
|
public ObservableCollection<ChatMessage> ChatMessages { get; } = new();
|
|
|
|
public Scene? ActiveScene
|
|
{
|
|
get => _activeScene;
|
|
set => SetProperty(ref _activeScene, value);
|
|
}
|
|
|
|
public StreamStatus StreamStatus
|
|
{
|
|
get => _streamStatus;
|
|
set => SetProperty(ref _streamStatus, value);
|
|
}
|
|
|
|
public StreamHealth CurrentHealth
|
|
{
|
|
get => _currentHealth;
|
|
set => SetProperty(ref _currentHealth, value);
|
|
}
|
|
|
|
public string StreamTitle
|
|
{
|
|
get => _streamTitle;
|
|
set => SetProperty(ref _streamTitle, value);
|
|
}
|
|
|
|
public string StreamKey
|
|
{
|
|
get => _streamKey;
|
|
set => SetProperty(ref _streamKey, value);
|
|
}
|
|
|
|
public bool IsYouTubeConnected
|
|
{
|
|
get => _isYouTubeConnected;
|
|
set => SetProperty(ref _isYouTubeConnected, value);
|
|
}
|
|
|
|
public string StatusDisplay => StreamStatus switch
|
|
{
|
|
StreamStatus.Offline => "OFFLINE",
|
|
StreamStatus.Connecting => "CONNECTING...",
|
|
StreamStatus.Streaming => "LIVE",
|
|
StreamStatus.Error => "ERROR",
|
|
_ => "UNKNOWN"
|
|
};
|
|
|
|
// Commands
|
|
public ICommand AddSceneCommand { get; }
|
|
public ICommand RemoveSceneCommand { get; }
|
|
public ICommand StartStreamCommand { get; }
|
|
public ICommand StopStreamCommand { get; }
|
|
public ICommand ConnectYouTubeCommand { get; }
|
|
|
|
public MainViewModel()
|
|
{
|
|
_youtubeAuth = new YouTubeAuthService("", ""); // TODO: load from config
|
|
_youtubeStream = new YouTubeStreamService(_youtubeAuth);
|
|
_youtubeChat = new YouTubeChatService(_youtubeAuth);
|
|
|
|
_youtubeChat.MessageReceived += OnChatMessageReceived;
|
|
|
|
AddSceneCommand = new RelayCommand(_ => AddScene());
|
|
RemoveSceneCommand = new RelayCommand(scene => RemoveScene(scene as Scene));
|
|
StartStreamCommand = new RelayCommand(_ => StartStream(), _ => StreamStatus == StreamStatus.Offline);
|
|
StopStreamCommand = new RelayCommand(_ => StopStream(), _ => StreamStatus == StreamStatus.Streaming);
|
|
ConnectYouTubeCommand = new RelayCommand(_ => ConnectYouTube());
|
|
|
|
// Start with a default scene
|
|
AddScene("Scene 1");
|
|
}
|
|
|
|
private void AddScene(string? name = null)
|
|
{
|
|
var scene = new Scene { Name = name ?? $"Scene {Scenes.Count + 1}" };
|
|
Scenes.Add(scene);
|
|
ActiveScene = scene;
|
|
}
|
|
|
|
private void RemoveScene(Scene? scene)
|
|
{
|
|
if (scene == null) return;
|
|
Scenes.Remove(scene);
|
|
if (ActiveScene == scene)
|
|
ActiveScene = Scenes.FirstOrDefault();
|
|
}
|
|
|
|
private void OnChatMessageReceived(ChatMessage message)
|
|
{
|
|
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
ChatMessages.Add(message);
|
|
if (ChatMessages.Count > 500)
|
|
ChatMessages.RemoveAt(0);
|
|
});
|
|
}
|
|
|
|
private async void StartStream()
|
|
{
|
|
StreamStatus = StreamStatus.Connecting;
|
|
OnPropertyChanged(nameof(StatusDisplay));
|
|
|
|
// TODO: Initialize capture pipeline, encode, and push to RTMP
|
|
// For now, simulate connection
|
|
StreamStatus = StreamStatus.Streaming;
|
|
OnPropertyChanged(nameof(StatusDisplay));
|
|
}
|
|
|
|
private void StopStream()
|
|
{
|
|
StreamStatus = StreamStatus.Offline;
|
|
OnPropertyChanged(nameof(StatusDisplay));
|
|
}
|
|
|
|
private void ConnectYouTube()
|
|
{
|
|
// TODO: Launch OAuth2 flow in browser
|
|
// For now, this is a stub
|
|
IsYouTubeConnected = false;
|
|
}
|
|
}
|