268 lines
7.9 KiB
Dart
268 lines
7.9 KiB
Dart
import 'dart:io';
|
|
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');
|
|
|
|
try {
|
|
final results = parser.parse(arguments);
|
|
|
|
if (results['help'] == true) {
|
|
print('Mumble Music Bot - A Dart-based music bot for Mumble servers');
|
|
print('');
|
|
print('Usage:');
|
|
print('dart bin/mumbullet.dart [options]');
|
|
print('');
|
|
print('Options:');
|
|
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();
|
|
logger.info('Configuration loaded successfully');
|
|
} catch (e) {
|
|
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 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) {
|
|
logger.info('Connected to Mumble server');
|
|
} else {
|
|
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':
|
|
final song = data['song'] as Song;
|
|
logger.info('Now playing: ${song.title}');
|
|
break;
|
|
case 'songFinished':
|
|
final song = data['song'] as Song;
|
|
logger.info('Finished playing: ${song.title}');
|
|
break;
|
|
case 'queueEmpty':
|
|
logger.info('Music queue is now empty');
|
|
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.',
|
|
);
|
|
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();
|
|
musicQueue.dispose();
|
|
} catch (e) {
|
|
logger.warning('Error stopping audio services: $e');
|
|
}
|
|
|
|
// Disconnect from Mumble server
|
|
if (mumbleConnection.isConnected) {
|
|
try {
|
|
await mumbleConnection.sendChannelMessage('MumBullet Music Bot is shutting down...');
|
|
await mumbleConnection.disconnect();
|
|
} catch (e) {
|
|
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();
|
|
musicQueue.dispose();
|
|
} catch (e) {
|
|
logger.warning('Error stopping audio services: $e');
|
|
}
|
|
|
|
// Disconnect from Mumble server
|
|
if (mumbleConnection.isConnected) {
|
|
try {
|
|
await mumbleConnection.sendChannelMessage('MumBullet Music Bot is shutting down...');
|
|
await mumbleConnection.disconnect();
|
|
} catch (e) {
|
|
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');
|
|
print('');
|
|
print('Usage:');
|
|
print(parser.usage);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
Level _parseLogLevel(String level) {
|
|
switch (level.toLowerCase()) {
|
|
case 'debug':
|
|
return Level.FINE;
|
|
case 'info':
|
|
return Level.INFO;
|
|
case 'warning':
|
|
return Level.WARNING;
|
|
case 'error':
|
|
return Level.SEVERE;
|
|
default:
|
|
return Level.INFO;
|
|
}
|
|
}
|