polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
752 lines (742 loc) • 37.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parsePageSize = parsePageSize;
exports.validateOutputFormat = validateOutputFormat;
exports.validateYn = validateYn;
exports.parsePositiveInteger = parsePositiveInteger;
exports.parseNonNegativeInteger = parseNonNegativeInteger;
exports.parseBooleanOption = parseBooleanOption;
exports.parseJoinHistoryList = parseJoinHistoryList;
exports.parseCommaList = parseCommaList;
exports.parseRobotList = parseRobotList;
exports.registerChatCommands = registerChatCommands;
const chat_handler_1 = require("../handlers/chat.handler");
const manager_1 = require("../config/manager");
const auth_adapter_1 = require("../config/auth-adapter");
const errors_1 = require("../utils/errors");
function parsePageSize(value) {
const parsed = parseInt(value, 10);
if (isNaN(parsed) || parsed < 1 || parsed > 100) {
throw new Error('Page size should be between 1 and 100');
}
return parsed;
}
function validateOutputFormat(value) {
if (!['table', 'json'].includes(value)) {
throw new Error('Output format must be either "table" or "json"');
}
return value;
}
function validateYn(value) {
if (value !== 'Y' && value !== 'N') {
throw new Error('Value must be Y or N');
}
return value;
}
function parsePositiveInteger(value) {
const parsed = parseInt(value, 10);
if (!Number.isInteger(parsed) || parsed < 1) {
throw new Error('Value must be a positive integer');
}
return parsed;
}
function parseNonNegativeInteger(value) {
const parsed = parseInt(value, 10);
if (!Number.isInteger(parsed) || parsed < 0) {
throw new Error('Value must be a non-negative integer');
}
return parsed;
}
function parseBooleanOption(value) {
if (value === 'true' || value === '1' || value === 'Y')
return true;
if (value === 'false' || value === '0' || value === 'N')
return false;
throw new Error('Value must be true/false, 1/0, or Y/N');
}
function parseJoinHistoryList(value) {
const parsed = parseInt(value, 10);
if (parsed !== 0 && parsed !== 1) {
throw new Error('joinHistoryList must be 0 or 1');
}
return parsed;
}
function parseCommaList(value) {
return value.split(',').map(item => item.trim()).filter(Boolean);
}
function parseRobotList(value) {
const parsed = JSON.parse(value);
if (!Array.isArray(parsed)) {
throw new Error('Robot list must be a JSON array');
}
return parsed;
}
function registerChatCommands(program) {
const chatCmd = program.command('chat');
chatCmd.description('Manage live streaming chat messages');
async function withChatHandler(action) {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await action(new chat_handler_1.ChatHandler(authConfig, serviceConfig));
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
}
const sendCmd = chatCmd
.command('send')
.description('Send an admin message to the channel chat')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-m, --msg <text>', 'text message content')
.option('-i, --img-url <url>', 'image URL')
.option('-p, --pic <url>', 'avatar URL')
.option('-n, --nickname <name>', 'sender nickname')
.option('-a, --actor <role>', 'actor/role')
.option('--admin-index <number>', 'admin index', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
await chatHandler.sendAdminMessage({
channelId: options.channelId,
msg: options.msg,
imgUrl: options.imgUrl,
pic: options.pic || 'https://live.polyv.net/assets/images/default-avatar.png',
nickName: options.nickname || '管理员',
actor: options.actor,
adminIndex: options.adminIndex,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
sendCmd.addHelpText('after', `
Examples:
# Send text message
$ polyv-live-cli chat send -c "3151318" -m "Hello World"
# Send image message
$ polyv-live-cli chat send -c "3151318" -i "https://example.com/image.png"
# Send message with custom nickname
$ polyv-live-cli chat send -c "3151318" -m "Hello" -n "Admin" -a "管理员"
Output Formats:
table - Formatted table output (default)
json - JSON format for programmatic use
`);
const listCmd = chatCmd
.command('list')
.description('List chat history with pagination')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--start-day <date>', 'start date filter (yyyy-MM-dd, default: today)')
.option('--end-day <date>', 'end date filter (yyyy-MM-dd, default: today)')
.option('--page <number>', 'page number (default 1)', parseInt)
.option('--size <number>', 'page size (1-100, default 20)', parsePageSize)
.option('--user-type <type>', 'user type filter')
.option('--status <status>', 'status filter')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
const today = new Date().toISOString().split('T')[0];
const startDay = options.startDay || today;
const endDay = options.endDay || today;
await chatHandler.listMessages({
channelId: options.channelId,
startDay,
endDay,
page: options.page,
size: options.size,
userType: options.userType,
status: options.status,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
listCmd.addHelpText('after', `
Examples:
# List recent chat messages
$ polyv-live-cli chat list -c "3151318"
# List with pagination
$ polyv-live-cli chat list -c "3151318" --page 2 --size 50
# List with date range
$ polyv-live-cli chat list -c "3151318" --start-day "2024-01-01" --end-day "2024-01-31"
# List in JSON format
$ polyv-live-cli chat list -c "3151318" -o json
Output Formats:
table - Formatted table output (default)
json - JSON format for programmatic use
`);
const deleteCmd = chatCmd
.command('delete')
.description('Delete a chat message or clear all messages')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-m, --message-id <id>', 'message ID to delete')
.option('--clear', 'clear all messages in the channel')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
await chatHandler.deleteMessage({
channelId: options.channelId,
messageId: options.messageId,
clear: options.clear,
force: options.force,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
deleteCmd.addHelpText('after', `
Examples:
# Delete a single message
$ polyv-live-cli chat delete -c "3151318" -m "abc123"
# Clear all messages
$ polyv-live-cli chat delete -c "3151318" --clear
# Skip confirmation
$ polyv-live-cli chat delete -c "3151318" -m "abc123" --force
Note:
Deletion is permanent and cannot be undone.
Use --force to skip confirmation prompt.
`);
chatCmd
.command('group-login-times')
.description('Get group login times for a channel')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await new chat_handler_1.ChatHandler(authConfig, serviceConfig).getGroupLoginTimes(options);
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
chatCmd
.command('ban')
.description('Ban users from chat (channel or global)')
.option('-c, --channel-id <id>', 'channel ID (required for channel-level ban)')
.requiredOption('-u, --user-ids <ids>', 'user IDs to ban (comma-separated)')
.option('--global', 'ban users globally (account level)')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
const userIds = options.userIds.split(',').map((id) => id.trim());
await chatHandler.banUser({
channelId: options.channelId,
userIds,
global: options.global,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
chatCmd
.command('unban')
.description('Unban users from chat (channel or global)')
.option('-c, --channel-id <id>', 'channel ID (required for channel-level unban)')
.requiredOption('-u, --user-ids <ids>', 'user IDs to unban (comma-separated)')
.option('--global', 'unban users globally (account level)')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
const userIds = options.userIds.split(',').map((id) => id.trim());
await chatHandler.unbanUser({
channelId: options.channelId,
userIds,
global: options.global,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
chatCmd
.command('kick')
.description('Kick users from channel or globally')
.option('-c, --channel-id <id>', 'channel ID (required for channel-level kick)')
.option('--viewer-ids <ids>', 'viewer IDs to kick (comma-separated)')
.option('-n, --nick-names <names>', 'nicknames to kick (comma-separated)')
.option('--global', 'kick users globally (platform level)')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
const viewerIds = options.viewerIds ? options.viewerIds.split(',').map((id) => id.trim()) : undefined;
const nickNames = options.nickNames ? options.nickNames.split(',').map((name) => name.trim()) : undefined;
await chatHandler.kickUser({
channelId: options.channelId,
viewerIds,
nickNames,
global: options.global,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
chatCmd
.command('unkick')
.description('Unkick users (cancel kick status)')
.option('-c, --channel-id <id>', 'channel ID (required for channel-level unkick)')
.option('--viewer-ids <ids>', 'viewer IDs to unkick (comma-separated)')
.option('-n, --nick-names <names>', 'nicknames to unkick (comma-separated)')
.option('--global', 'unkick users globally (platform level)')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
const viewerIds = options.viewerIds ? options.viewerIds.split(',').map((id) => id.trim()) : undefined;
const nickNames = options.nickNames ? options.nickNames.split(',').map((name) => name.trim()) : undefined;
await chatHandler.unkickUser({
channelId: options.channelId,
viewerIds,
nickNames,
global: options.global,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
const bannedCmd = chatCmd.command('banned');
bannedCmd.description('Manage banned items');
bannedCmd
.command('list')
.description('List banned users, IPs, or badwords')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('-t, --type <type>', 'banned list type (userId|ip|badword)')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
await chatHandler.listBanned({
channelId: options.channelId,
type: options.type,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
const kickedCmd = chatCmd.command('kicked');
kickedCmd.description('Manage kicked users');
kickedCmd
.command('list')
.description('List kicked users')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const chatHandler = new chat_handler_1.ChatHandler(authConfig, serviceConfig);
await chatHandler.listKicked({
channelId: options.channelId,
output: options.output,
});
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
const messageCmd = chatCmd.command('message');
messageCmd.description('Manage advanced chat messages');
messageCmd
.command('hidden-send')
.description('Send hidden text or image message as a user')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('-u, --user-id <id>', 'user ID')
.option('--content <text>', 'message content')
.option('--img-url <url>', 'image URL')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.sendHiddenMessage({
channelId: options.channelId,
userId: options.userId,
content: options.content,
imgUrl: options.imgUrl,
output: options.output,
})));
messageCmd
.command('admin-send')
.description('Send hidden message as an admin role')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--content <text>', 'message content')
.requiredOption('--role <role>', 'sender role')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.sendHiddenByAdmin(options)));
messageCmd
.command('online-count')
.description('Get current chat online user count')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.countOnlineUser(options)));
messageCmd
.command('remove-contents')
.description('Batch remove chat message records')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--ids <ids>', 'chat message IDs, comma-separated', parseCommaList)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.removeChatContents(options)));
messageCmd
.command('speak-list')
.description('List account chat speak records')
.option('--start-time <timestamp>', 'start time timestamp', parsePositiveInteger)
.option('--end-time <timestamp>', 'end time timestamp', parsePositiveInteger)
.option('--cursor <cursor>', 'pagination cursor')
.option('--size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.listSpeak(options)));
messageCmd
.command('alert-special')
.description('Send popup alert to broadcaster')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--title <text>', 'popup title')
.requiredOption('--message <text>', 'popup message')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.alertToSpecial(options)));
messageCmd
.command('audit')
.description('Submit an approved chat message audit item')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--msg-id <id>', 'message ID')
.requiredOption('--viewer-id <id>', 'viewer ID')
.requiredOption('--nick-name <name>', 'viewer nickname')
.requiredOption('--content <text>', 'message content')
.option('--avatar <url>', 'viewer avatar URL')
.option('--session-id <id>', 'session ID')
.option('--viewer-type <type>', 'viewer type')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.auditMessage(options)));
messageCmd
.command('custom-send')
.description('Send custom chat message')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--content <text>', 'message content')
.option('--img-url <url>', 'image URL')
.option('--join-history-list <value>', 'join history list (true|false)', parseBooleanOption)
.option('--watch-type <type>', 'watch target type')
.option('--important <value>', 'important message flag (true|false)', parseBooleanOption)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.sendCustomMessage(options)));
messageCmd
.command('custom-send-encode')
.description('Send URL-safe base64 encoded custom chat message')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--content <text>', 'encoded message content')
.option('--img-url <url>', 'image URL')
.option('--join-history-list <value>', 'join history list (0|1)', parseJoinHistoryList)
.option('--watch-type <type>', 'watch target type')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.sendCustomMessageEncode(options)));
messageCmd
.command('emit-by-user-id')
.description('Broadcast message to specific users by user ID')
.requiredOption('-r, --room-id <id>', 'room ID')
.requiredOption('-u, --user-ids <ids>', 'user IDs, comma-separated', parseCommaList)
.requiredOption('--payload <text>', 'message payload')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.emitByUserId(options)));
const badwordCmd = chatCmd.command('badword');
badwordCmd.description('Manage account and channel badwords');
badwordCmd
.command('list')
.description('List account badwords')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.listUserBadwords(options)));
badwordCmd
.command('add')
.description('Add account or channel badwords')
.requiredOption('--user-id <id>', 'account user ID')
.requiredOption('--words <words>', 'badwords, comma-separated', parseCommaList)
.option('-c, --channel-id <id>', 'channel ID for channel-level badwords')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.addBadwords(options)));
badwordCmd
.command('delete')
.description('Delete account badwords')
.requiredOption('--words <words>', 'badwords, comma-separated')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.deleteUserBadword(options)));
bannedCmd
.command('ip-add')
.description('Ban an IP address in channel chat')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--ip <ip>', 'IP address')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.addBannedIp(options)));
bannedCmd
.command('user-list')
.description('List account banned users')
.option('--page <number>', 'page number', parsePositiveInteger)
.option('--size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.listUserBanned(options)));
bannedCmd
.command('forbid-list')
.description('List globally forbidden chat users')
.option('--viewer-id <id>', 'viewer ID filter')
.option('--nick-name <name>', 'nickname filter')
.option('--page-number <number>', 'page number', parsePositiveInteger)
.option('--page-size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.listForbidUsers(options)));
bannedCmd
.command('delete')
.description('Delete channel badword or banned IP')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('-t, --type <type>', 'item type (ip|badword)')
.requiredOption('--content <text>', 'IP or badword content')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.deleteChannelBanned(options)));
const noticeCmd = chatCmd.command('notice');
noticeCmd.description('Manage channel notices');
noticeCmd
.command('list')
.description('List channel notices')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--page-number <number>', 'page number', parsePositiveInteger)
.option('--page-size <number>', 'page size', parsePositiveInteger)
.option('--sort <sort>', 'sort expression, for example createTime:desc')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.listBulletins(options)));
noticeCmd
.command('add')
.description('Add channel notice')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--content <text>', 'notice content')
.option('--is-top <value>', 'pin to top (Y|N)')
.option('--is-pop <value>', 'show popup (Y|N)')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.addBulletin(options)));
noticeCmd
.command('clean')
.description('Clear all channel notices')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.cleanNotices(options)));
const qaCmd = chatCmd.command('qa');
qaCmd.description('Manage chat Q&A records');
qaCmd
.command('list')
.description('List channel Q&A records')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--page-number <number>', 'page number', parsePositiveInteger)
.option('--page-size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.listQa(options)));
const censorCmd = chatCmd.command('censor');
censorCmd.description('Manage chat censor settings');
censorCmd
.command('update')
.description('Update chat censor enabled setting')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--enabled <value>', 'enabled flag (Y|N)')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.updateCensorEnabled(options)));
const roleCmd = chatCmd.command('role');
roleCmd.description('Manage chat role information');
roleCmd
.command('admin-get')
.description('Get admin role information')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.getAdminInfo(options)));
roleCmd
.command('admin-update')
.description('Update admin role information')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--nickname <name>', 'admin nickname')
.requiredOption('--actor <title>', 'admin actor/title')
.requiredOption('--avatar <path>', 'admin avatar image file path (jpg/jpeg/png)')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.updateAdminInfo(options)));
roleCmd
.command('teacher-get')
.description('Get teacher role information')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.getTeacherInfo(options)));
roleCmd
.command('teacher-update')
.description('Update teacher role information')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--nickname <name>', 'teacher nickname')
.option('--actor <title>', 'teacher actor/title')
.option('--passwd <password>', 'teacher password')
.option('--avatar <url>', 'teacher avatar URL')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.updateTeacherInfo(options)));
roleCmd
.command('user-list')
.description('List online chat room users')
.requiredOption('-r, --room-id <id>', 'room ID')
.option('--page <number>', 'page number', parsePositiveInteger)
.option('--len <number>', 'page size', parsePositiveInteger)
.option('--to-get-sub-rooms <value>', 'include sub rooms (true|false)', parseBooleanOption)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.getUserList(options)));
const robotCmd = chatCmd.command('robot');
robotCmd.description('Manage channel chat robots');
robotCmd
.command('setting-get')
.description('Get channel robot setting')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.getRobotSetting(options)));
robotCmd
.command('stats')
.description('Get channel robot stats')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.getRobotStats(options)));
robotCmd
.command('setting-update')
.description('Update channel robot setting')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--robot-number <number>', 'robot number', parseNonNegativeInteger)
.requiredOption('--add-robot-model <model>', 'robot add model (timely|fixed_time)')
.option('--change-time <seconds>', 'change time in seconds', parsePositiveInteger)
.option('--virtual-booking-number <number>', 'virtual booking number', parseNonNegativeInteger)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.updateRobotSetting(options)));
robotCmd
.command('list-update')
.description('Update channel robot count and custom robot list')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--robot-number <number>', 'robot number', parseNonNegativeInteger)
.requiredOption('--add-robot-model <model>', 'robot add model (timely|fixed_time)')
.option('--change-time <seconds>', 'change time in seconds', parsePositiveInteger)
.option('--virtual-booking-number <number>', 'virtual booking number', parseNonNegativeInteger)
.option('--robot-list <json>', 'custom robot list JSON array', parseRobotList)
.option('--robot-random-member-enabled <value>', 'random content-library robots (Y|N)')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.updateRobotListSetting(options)));
robotCmd
.command('pause')
.description('Pause channel robot growth')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.pauseRobot(options)));
const enabledCmd = chatCmd.command('enabled');
enabledCmd.description('Manage channel chat switch');
enabledCmd
.command('update')
.description('Batch update channel chat switch')
.requiredOption('--channel-ids <ids>', 'channel IDs, comma-separated', parseCommaList)
.requiredOption('--chat-enabled <yn>', 'chat enabled flag (Y|N)', validateYn)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.batchUpdateChatEnabled({
channelIds: options.channelIds,
chatEnabled: options.chatEnabled,
force: options.force,
output: options.output,
})));
chatCmd
.command('viewer-logout')
.description('Log out a viewer from the channel watch page')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--token <token>', 'viewer token')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => withChatHandler(handler => handler.logoutWatchViewer(options)));
async function loadAuthAndServiceConfig(parentOptions) {
const authResult = auth_adapter_1.authAdapter.tryGetAuthConfig(parentOptions);
if (!authResult) {
throw new Error(auth_adapter_1.authAdapter.getStatusMessage(parentOptions));
}
let configResult;
try {
configResult = await manager_1.configManager.load({
cliOptions: parentOptions,
});
}
catch (error) {
if (error instanceof Error && error.message.includes('Auth configuration is incomplete')) {
configResult = {
config: {
baseUrl: 'https://api.polyv.net',
timeout: 30000,
debug: false
}
};
}
else {
throw error;
}
}
const serviceConfig = {
baseUrl: configResult.config.baseUrl,
timeout: configResult.config.timeout,
debug: configResult.config.debug,
};
return {
authConfig: authResult.config,
serviceConfig,
};
}
}
//# sourceMappingURL=chat.commands.js.map