Improved dashboard and music queue

This commit is contained in:
Nate Anderson
2025-06-21 11:47:06 -06:00
parent 0745a4eb75
commit 71f535be27
16 changed files with 1386 additions and 664 deletions
+62 -61
View File
@@ -3,35 +3,28 @@ import 'dart:async';
import 'package:args/args.dart';
import 'package:logging/logging.dart';
import 'package:mumbullet/mumbullet.dart';
import 'package:mumbullet/src/dashboard/server.dart';
import 'package:path/path.dart' as path;
Future<void> main(List<String> arguments) async {
// Parse command line arguments
final parser = ArgParser()
..addOption('config',
abbr: 'c',
defaultsTo: 'config.json',
help: 'Path to configuration file')
..addOption('log-level',
abbr: 'l',
defaultsTo: 'info',
allowed: ['debug', 'info', 'warning', 'error'],
help: 'Log level (debug, info, warning, error)')
..addFlag('console-log',
abbr: 'o',
defaultsTo: true,
help: 'Log to console')
..addOption('log-file',
abbr: 'f',
help: 'Path to log file')
..addFlag('help',
abbr: 'h',
negatable: false,
help: 'Display this help message');
final parser =
ArgParser()
..addOption('config', abbr: 'c', defaultsTo: 'config.json', help: 'Path to configuration file')
..addOption(
'log-level',
abbr: 'l',
defaultsTo: 'info',
allowed: ['debug', 'info', 'warning', 'error'],
help: 'Log level (debug, info, warning, error)',
)
..addFlag('console-log', abbr: 'o', defaultsTo: true, help: 'Log to console')
..addOption('log-file', abbr: 'f', help: 'Path to log file')
..addFlag('help', abbr: 'h', negatable: false, help: 'Display this help message');
try {
final results = parser.parse(arguments);
if (results['help'] == true) {
print('Mumble Music Bot - A Dart-based music bot for Mumble servers');
print('');
@@ -42,25 +35,25 @@ Future<void> main(List<String> arguments) async {
print(parser.usage);
exit(0);
}
// Set up logging
final logLevelString = results['log-level'] as String;
final Level logLevel = _parseLogLevel(logLevelString);
final logManager = LogManager.getInstance();
logManager.initialize(
level: logLevel,
logToConsole: results['console-log'] as bool,
logFilePath: results['log-file'] as String?,
);
// Load configuration
final configPath = results['config'] as String;
final logger = logManager.logger;
logger.info('Starting Mumble Music Bot');
logger.info('Loading configuration from $configPath');
final config = AppConfig.fromFile(configPath);
try {
config.validate();
@@ -69,46 +62,51 @@ Future<void> main(List<String> arguments) async {
logger.severe('Configuration validation error: $e');
exit(1);
}
// Initialize database
final dbPath = path.join(config.bot.cacheDirectory, 'mumbullet.db');
logger.info('Initializing database: $dbPath');
final database = DatabaseManager(dbPath);
// Initialize permission manager
final permissionManager = PermissionManager(database, config.bot);
// Create Mumble connection
logger.info('Connecting to Mumble server ${config.mumble.server}:${config.mumble.port}');
final mumbleConnection = MumbleConnection(config.mumble);
// Create message handler
final messageHandler = MumbleMessageHandler(mumbleConnection, config.bot);
// Initialize audio services
logger.info('Initializing audio services');
final audioConverter = AudioConverter();
final youtubeDownloader = YoutubeDownloader(config.bot, database);
final audioStreamer = MumbleAudioStreamer(mumbleConnection);
// Create music queue
final musicQueue = MusicQueue(config.bot, audioStreamer, audioConverter);
// Create command parser with permission callback
final commandParser = CommandParser(
messageHandler,
config.bot,
(user) => permissionManager.getPermissionLevel(user),
);
// Create command handler
// Create command handler with connection for private messaging
final commandHandler = CommandHandler(
commandParser,
musicQueue,
youtubeDownloader,
config.bot,
mumbleConnection,
);
final dashboardServer = DashboardServer(config.dashboard, musicQueue, youtubeDownloader, permissionManager);
dashboardServer.start();
// Set up event listeners
mumbleConnection.connectionState.listen((isConnected) {
if (isConnected) {
@@ -117,22 +115,22 @@ Future<void> main(List<String> arguments) async {
logger.info('Disconnected from Mumble server');
}
});
mumbleConnection.userJoined.listen((user) {
logger.info('User joined: ${user.name}');
});
mumbleConnection.userLeft.listen((user) {
logger.info('User left: ${user.name}');
});
// Listen to music queue events
musicQueue.events.listen((event) {
final eventType = event['event'] as String;
final data = event['data'] as Map<String, dynamic>;
logger.info('Music queue event: $eventType');
// Log important events
switch (eventType) {
case 'songStarted':
@@ -148,37 +146,39 @@ Future<void> main(List<String> arguments) async {
break;
}
});
// Connect to Mumble server
try {
await mumbleConnection.connect();
// Send a welcome message to the channel
if (mumbleConnection.isConnected) {
await mumbleConnection.sendChannelMessage('MumBullet Music Bot is online! Type ${config.bot.commandPrefix}help for a list of commands.');
await mumbleConnection.sendChannelMessage(
'MumBullet Music Bot is online! Type ${config.bot.commandPrefix}help for a list of commands.',
);
logger.info('Sent welcome message to channel');
}
} catch (e) {
logger.warning('Failed to connect to Mumble server: $e');
logger.info('The bot will automatically attempt to reconnect...');
}
logger.info('MumBullet is now running with the following features:');
logger.info('- Mumble server connection');
logger.info('- Command processing with permissions');
logger.info('- YouTube audio downloading and streaming');
logger.info('- Queue management');
logger.info('- Admin dashboard');
logger.info('Press Ctrl+C to exit');
// Wait for shutdown
final completer = Completer<void>();
// Set up signal handlers
ProcessSignal.sigint.watch().listen((_) async {
logger.info('Shutting down Mumble Music Bot');
// Stop music playback
try {
await audioStreamer.stopStreaming();
@@ -186,7 +186,7 @@ Future<void> main(List<String> arguments) async {
} catch (e) {
logger.warning('Error stopping audio services: $e');
}
// Disconnect from Mumble server
if (mumbleConnection.isConnected) {
try {
@@ -196,18 +196,19 @@ Future<void> main(List<String> arguments) async {
logger.warning('Error during shutdown: $e');
}
}
// Dispose resources
mumbleConnection.dispose();
messageHandler.dispose();
database.close();
await dashboardServer.stop();
completer.complete();
});
ProcessSignal.sigterm.watch().listen((_) async {
logger.info('Shutting down Mumble Music Bot');
// Stop music playback
try {
await audioStreamer.stopStreaming();
@@ -215,7 +216,7 @@ Future<void> main(List<String> arguments) async {
} catch (e) {
logger.warning('Error stopping audio services: $e');
}
// Disconnect from Mumble server
if (mumbleConnection.isConnected) {
try {
@@ -225,21 +226,21 @@ Future<void> main(List<String> arguments) async {
logger.warning('Error during shutdown: $e');
}
}
// Dispose resources
mumbleConnection.dispose();
messageHandler.dispose();
database.close();
await dashboardServer.stop();
completer.complete();
});
await completer.future;
// Close logger
logManager.close();
exit(0);
} catch (e, stackTrace) {
print('Error: $e');
print('Stack trace: $stackTrace');