Files
AudioBotProject/MainWindow.xaml.cs
tkrmagid-notbook 9d14827e83 1차 제작
기능은 다 만들었는데 테스트를 못해봄
그래서 잘 작동하는지 모름
집가서 테스트해봐야지
2026-04-14 14:45:41 +09:00

315 lines
13 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Windows;
using System.Windows.Controls;
namespace AudioBotProject
{
public class AppConfig
{
public string BotToken { get; set; } = "";
public string[] SelectedApps { get; set; } = Array.Empty<string>();
public ulong LastServerId { get; set; } = 0; // 글자 대신 고유 ID로 저장!
public ulong LastChannelId { get; set; } = 0;
}
public partial class MainWindow : Window
{
// 💡 API 통신 매니저 생성
private DiscordBotManager _botManager = new DiscordBotManager();
private bool _isBotRunning = false;
private bool _isInChannel = false;
private bool _isRoutingStarted = false;
private ObservableCollection<string> _selectedApps = new ObservableCollection<string>();
private readonly string _configFilePath = "config.json";
public MainWindow()
{
InitializeComponent();
SelectedAppsListBox.ItemsSource = _selectedApps;
// 💡 디스코드 매니저에서 오는 신호(로그, 준비완료)를 화면(UI)에 연결
// (주의: 디스코드 신호는 백그라운드 스레드에서 오므로 Dispatcher.Invoke를 써야 화면 수정이 가능합니다.)
_botManager.OnLog += msg => Dispatcher.Invoke(() => LogToMain(msg));
_botManager.OnReady += () => Dispatcher.Invoke(BotReadyHandler);
LogToMain("프로그램이 시작되었습니다.");
LoadConfig();
}
// 봇이 완전히 로그인되었을 때 실행될 UI 업데이트
private void BotReadyHandler()
{
BotToggleBtn.Content = "봇 중지";
BotToggleBtn.IsEnabled = true; // 로그인 중에는 버튼 잠갔다가 완료되면 풀기
BotResultText.Text = "✅ 봇이 정상적으로 실행되었습니다.";
CurrentBotNameText.Text = $"현재 실행중인 봇: {_botManager.GetBotName()}";
NavChannelSettingsBtn.IsEnabled = true;
}
#region [ & ]
private void SaveConfig()
{
var config = new AppConfig
{
BotToken = TokenTextBox.Text,
SelectedApps = _selectedApps.ToArray(),
// 콤보박스에서 선택된 서버/채널의 고유 ID 값을 저장합니다.
LastServerId = ServerComboBox.SelectedValue is ulong sId ? sId : 0,
LastChannelId = ChannelComboBox.SelectedValue is ulong cId ? cId : 0
};
var options = new JsonSerializerOptions { WriteIndented = true };
string jsonString = JsonSerializer.Serialize(config, options);
File.WriteAllText(_configFilePath, jsonString);
}
private void LoadConfig()
{
if (File.Exists(_configFilePath))
{
try
{
string jsonString = File.ReadAllText(_configFilePath);
var config = JsonSerializer.Deserialize<AppConfig>(jsonString);
if (config != null)
{
TokenTextBox.Text = config.BotToken;
_selectedApps.Clear();
foreach (var app in config.SelectedApps) _selectedApps.Add(app);
LogToMain("✅ 이전 설정을 성공적으로 불러왔습니다.");
}
}
catch (Exception ex)
{
LogToMain($"❌ 설정 불러오기 실패: {ex.Message}");
}
}
}
#endregion
#region [ (Navigation) ]
private void HideAllViews()
{
MainView.Visibility = Visibility.Collapsed;
BotSettingsView.Visibility = Visibility.Collapsed;
ChannelSettingsView.Visibility = Visibility.Collapsed;
OutputSettingsView.Visibility = Visibility.Collapsed;
}
private void Nav_BackToMain_Click(object sender, RoutedEventArgs e) { HideAllViews(); MainView.Visibility = Visibility.Visible; }
private void Nav_BotSettings_Click(object sender, RoutedEventArgs e) { HideAllViews(); BotSettingsView.Visibility = Visibility.Visible; }
private void Nav_ChannelSettings_Click(object sender, RoutedEventArgs e) { HideAllViews(); ChannelSettingsView.Visibility = Visibility.Visible; }
private void Nav_OutputSettings_Click(object sender, RoutedEventArgs e) { HideAllViews(); OutputSettingsView.Visibility = Visibility.Visible; }
#endregion
#region [ ( ) ]
private async void BotToggleBtn_Click(object sender, RoutedEventArgs e)
{
if (!_isBotRunning)
{
string token = TokenTextBox.Text;
if (string.IsNullOrWhiteSpace(token))
{
BotResultText.Text = "❌ 토큰을 입력해주세요.";
return;
}
SaveConfig();
_isBotRunning = true;
BotToggleBtn.IsEnabled = false; // 로그인 완료 전까지 연타 방지
BotResultText.Text = "⏳ 디스코드 서버에 연결 중...";
// 💡 API 연결 시작!
await _botManager.StartBotAsync(token);
}
else
{
if (_isRoutingStarted)
{
_isRoutingStarted = false;
MainStartRoutingBtn.Content = "🚀 시작";
MainStartRoutingBtn.Background = (System.Windows.Media.Brush)new System.Windows.Media.BrushConverter().ConvertFrom("#FF5865F2")!;
}
if (_isInChannel)
{
_isInChannel = false;
ChannelToggleBtn.Content = "채널 접속";
ChannelResultText.Text = "봇이 중지되어 채널에서 나왔습니다.";
}
// 💡 API 연결 종료!
await _botManager.StopBotAsync();
_isBotRunning = false;
BotToggleBtn.Content = "봇 실행";
BotResultText.Text = "봇이 안전하게 중지되었습니다.";
CurrentBotNameText.Text = "현재 실행중인 봇: 없음";
NavChannelSettingsBtn.IsEnabled = false;
}
}
#endregion
#region [ ( ) ]
private void ServerComboBox_DropDownOpened(object sender, EventArgs e)
{
// 💡 봇 매니저에게 실제 서버 목록을 달라고 요청합니다.
var servers = _botManager.GetServers()
.Select(g => new { Id = g.Id, Name = g.Name })
.ToList();
ServerComboBox.ItemsSource = servers;
ServerComboBox.DisplayMemberPath = "Name"; // 화면에 보여줄 글자
ServerComboBox.SelectedValuePath = "Id"; // 뒤에 숨겨둘 고유 ID
}
private void ServerComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ChannelComboBox.IsEnabled = ServerComboBox.SelectedItem != null;
ChannelComboBox.ItemsSource = null; // 서버가 바뀌면 채널 목록 초기화
}
private void ChannelComboBox_DropDownOpened(object sender, EventArgs e)
{
if (ServerComboBox.SelectedValue is ulong guildId)
{
// 💡 선택한 서버의 고유 ID를 넘겨주고, 실제 음성 채널 목록을 받아옵니다.
var channels = _botManager.GetVoiceChannels(guildId)
.Select(c => new { Id = c.Id, Name = c.Name })
.ToList();
ChannelComboBox.ItemsSource = channels;
ChannelComboBox.DisplayMemberPath = "Name";
ChannelComboBox.SelectedValuePath = "Id";
}
}
private async void ChannelToggleBtn_Click(object sender, RoutedEventArgs e)
{
if (ServerComboBox.SelectedValue == null || ChannelComboBox.SelectedValue == null)
{
ChannelResultText.Text = "❌ 서버와 채널을 모두 선택해주세요.";
return;
}
// 숨겨둔 고유 ID 추출
ulong channelId = (ulong)ChannelComboBox.SelectedValue;
if (!_isInChannel)
{
ChannelToggleBtn.IsEnabled = false;
ChannelResultText.Text = "⏳ 접속 중...";
// 💡 음성 채널 접속 API 호출
await _botManager.JoinChannelAsync(channelId);
_isInChannel = true;
ChannelToggleBtn.IsEnabled = true;
ChannelToggleBtn.Content = "채널 나가기";
ChannelResultText.Text = "✅ 음성 채널에 정상적으로 접속했습니다.";
SaveConfig(); // 접속 성공 시 저장
}
else
{
ChannelToggleBtn.IsEnabled = false;
// 💡 음성 채널 퇴장 API 호출
await _botManager.LeaveChannelAsync();
_isInChannel = false;
ChannelToggleBtn.IsEnabled = true;
ChannelToggleBtn.Content = "채널 접속";
ChannelResultText.Text = "채널에서 나왔습니다.";
}
}
#endregion
#region [ ]
private void ProcessComboBox_DropDownOpened(object sender, EventArgs e)
{
ProcessComboBox.Items.Clear();
var processes = Process.GetProcesses()
.Where(p => p.MainWindowHandle != IntPtr.Zero && !string.IsNullOrEmpty(p.MainWindowTitle))
.Select(p => p.ProcessName)
.Distinct()
.OrderBy(n => n);
foreach (var pName in processes) ProcessComboBox.Items.Add(pName);
}
private void AddOutputAppBtn_Click(object sender, RoutedEventArgs e)
{
if (ProcessComboBox.SelectedItem != null)
{
string? appName = ProcessComboBox.SelectedItem.ToString();
if (!string.IsNullOrEmpty(appName) && !_selectedApps.Contains(appName))
_selectedApps.Add(appName);
}
}
private void RemoveAppBtn_Click(object sender, RoutedEventArgs e)
{
Button? btn = sender as Button;
if (btn != null && btn.Tag != null)
{
string? appName = btn.Tag.ToString();
if (!string.IsNullOrEmpty(appName)) _selectedApps.Remove(appName);
}
}
private void SaveOutputSettingsBtn_Click(object sender, RoutedEventArgs e)
{
SaveConfig();
LogToMain($"출력 설정이 저장되었습니다. (대상 앱: {_selectedApps.Count}개)");
MessageBox.Show("설정이 성공적으로 저장되었습니다.", "알림", MessageBoxButton.OK, MessageBoxImage.Information);
}
#endregion
#region [ / ]
private void MainStartRoutingBtn_Click(object sender, RoutedEventArgs e)
{
if (!_isBotRunning) { MessageBox.Show("먼저 봇을 실행해주세요!", "경고", MessageBoxButton.OK, MessageBoxImage.Warning); return; }
if (!_isInChannel) { MessageBox.Show("먼저 채널에 접속해주세요!", "경고", MessageBoxButton.OK, MessageBoxImage.Warning); return; }
if (!_isRoutingStarted)
{
_isRoutingStarted = true;
MainStartRoutingBtn.Content = "⏹️ 종료";
MainStartRoutingBtn.Background = System.Windows.Media.Brushes.DarkRed;
LogToMain("오디오 라우팅을 시작했습니다!");
}
else
{
_isRoutingStarted = false;
MainStartRoutingBtn.Content = "🚀 시작";
MainStartRoutingBtn.Background = (System.Windows.Media.Brush)new System.Windows.Media.BrushConverter().ConvertFrom("#FF5865F2")!;
LogToMain("오디오 라우팅을 종료했습니다.");
}
}
private void LogToMain(string message)
{
MainLogBox.AppendText($"[{DateTime.Now:HH:mm:ss}] {message}\n");
MainLogBox.ScrollToEnd();
}
#endregion
#region [ ]
private async void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 프로그램 종료 시 봇도 확실하게 로그아웃 시키기
if (_isBotRunning)
{
await _botManager.StopBotAsync();
}
}
#endregion
}
}