polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
433 lines • 20.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateOutputFormat = validateOutputFormat;
exports.parsePositiveInteger = parsePositiveInteger;
exports.validateYn = validateYn;
exports.registerInteractionCommands = registerInteractionCommands;
const interaction_handler_1 = require("../handlers/interaction.handler");
const manager_1 = require("../config/manager");
const auth_adapter_1 = require("../config/auth-adapter");
const errors_1 = require("../utils/errors");
const api_command_1 = require("../utils/api-command");
function validateOutputFormat(value) {
if (!['table', 'json'].includes(value)) {
throw new Error('Output format must be either "table" or "json"');
}
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 validateYn(value) {
if (value !== 'Y' && value !== 'N') {
throw new Error('Value must be Y or N');
}
return value;
}
function registerInteractionCommands(program) {
const interactionCmd = program.command('interaction');
interactionCmd.description('Manage cross-cutting live interaction APIs');
async function withInteractionHandler(action) {
try {
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
await action(new interaction_handler_1.InteractionHandler(authConfig, serviceConfig));
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
}
interactionCmd
.command('favor')
.description('Send likes for a viewer')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--viewer-id <id>', 'viewer ID')
.option('--times <number>', 'like count', parsePositiveInteger)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.sendFavor({
channelId: options.channelId,
viewerId: options.viewerId,
times: options.times,
force: options.force,
output: options.output,
})));
interactionCmd
.command('reward')
.description('Send a reward message')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--nickname <name>', 'viewer nickname')
.requiredOption('--avatar <url>', 'viewer avatar URL')
.requiredOption('--viewer-id <id>', 'viewer ID')
.requiredOption('--donate-type <type>', 'donate type')
.requiredOption('--content <text>', 'reward content')
.option('--good-image <url>', 'gift image URL')
.option('--session-id <id>', 'live session ID')
.option('--good-num <number>', 'gift count')
.option('--need-user-image <Y|N>', 'whether user image is required', validateYn)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.sendRewardMsg({
channelId: options.channelId,
nickname: options.nickname,
avatar: options.avatar,
viewerId: options.viewerId,
donateType: options.donateType,
content: options.content,
goodImage: options.goodImage,
sessionId: options.sessionId,
goodNum: options.goodNum,
needUserImage: options.needUserImage,
force: options.force,
output: options.output,
})));
const webhookCmd = interactionCmd
.command('webhook')
.description('Manage student question webhook');
webhookCmd
.command('get')
.description('Get student question webhook configuration')
.option('--room-id <id>', 'room ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.getStudentQuestionWebhook({
roomId: options.roomId,
output: options.output,
})));
webhookCmd
.command('set')
.description('Set student question webhook configuration')
.requiredOption('--room-id <id>', 'room ID')
.requiredOption('--callback-url <url>', 'callback URL')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.setStudentQuestionWebhook({
roomId: options.roomId,
callbackUrl: options.callbackUrl,
force: options.force,
output: options.output,
})));
webhookCmd
.command('delete')
.description('Delete student question webhook configuration')
.requiredOption('--room-id <id>', 'room ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.deleteStudentQuestionWebhook({
roomId: options.roomId,
force: options.force,
output: options.output,
})));
interactionCmd
.command('teacher-answer')
.description('Send a teacher answer to a student question')
.requiredOption('--room-id <id>', 'room ID')
.requiredOption('--viewer-user-id <id>', 'viewer user ID')
.requiredOption('--content <text>', 'answer content')
.option('--teacher-nick <name>', 'teacher nickname')
.option('--teacher-pic <url>', 'teacher avatar URL')
.option('--msg-type <type>', 'message type')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.sendTeacherAnswer({
roomId: options.roomId,
viewerUserId: options.viewerUserId,
content: options.content,
teacherNick: options.teacherNick,
teacherPic: options.teacherPic,
msgType: options.msgType,
force: options.force,
output: options.output,
})));
const eventCmd = interactionCmd
.command('event')
.description('Manage interaction listener events');
eventCmd
.command('list')
.description('List interaction listener events')
.requiredOption('--room-id <id>', 'room ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.listInteractionEvents({
roomId: options.roomId,
output: options.output,
})));
eventCmd
.command('save')
.description('Save an interaction listener event (create one or more listener tasks)')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--tasks <json>', 'task rule list JSON array (each item: type, startTime, endTime, ...)', api_command_1.parseJsonArray)
.requiredOption('--all-done <Y|N>', 'whether all tasks must complete to count the activity done (Y|N)', validateYn)
.option('--callback-url <url>', 'callback URL')
.option('--payload <payload>', 'payload string')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.saveInteractionEvent({
channelId: options.channelId,
tasks: options.tasks,
allDone: options.allDone,
callbackUrl: options.callbackUrl,
payload: options.payload,
force: options.force,
output: options.output,
})));
eventCmd
.command('delete')
.description('Delete an interaction listener event')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--task-ids <json>', 'task ID list JSON array (pass the activityId when allDone=Y)', api_command_1.parseJsonArray)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.deleteInteractionEvent({
channelId: options.channelId,
taskIds: options.taskIds,
force: options.force,
output: options.output,
})));
const invitePosterCmd = interactionCmd
.command('invite-poster')
.description('Manage invite poster interaction helpers');
invitePosterCmd
.command('create')
.description('Create an invite poster inviter')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--open-id <id>', 'viewer open ID')
.requiredOption('--nickname <name>', 'viewer nickname')
.option('--avatar <url>', 'viewer avatar URL')
.option('--viewer-id <id>', 'viewer ID')
.option('--invitee <id>', 'invitee ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.createInvitePoster({
channelId: options.channelId,
openId: options.openId,
nickname: options.nickname,
avatar: options.avatar,
viewerId: options.viewerId,
invitee: options.invitee,
force: options.force,
output: options.output,
})));
const scriptCmd = interactionCmd
.command('script')
.description('Manage pseudo-live disk video interaction scripts');
scriptCmd
.command('query')
.description('Query custom interaction scripts for a disk video')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--disk-video-id <id>', 'disk video ID')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.queryDiskVideoCustomScript({
channelId: options.channelId,
diskVideoId: options.diskVideoId,
output: options.output,
})));
scriptCmd
.command('upload')
.description('Upload a custom interaction script for a disk video')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--disk-video-id <id>', 'disk video ID')
.requiredOption('--file <path>', 'script file path')
.option('--label-id <id>', 'disk video label ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.uploadDiskVideoCustomScript({
channelId: options.channelId,
diskVideoId: options.diskVideoId,
filePath: options.file,
labelId: options.labelId,
force: options.force,
output: options.output,
})));
scriptCmd
.command('delete')
.description('Delete an interaction script')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--id <id>', 'script ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.deleteInteractionScript({
channelId: options.channelId,
id: options.id,
force: options.force,
output: options.output,
})));
const taskRewardCmd = interactionCmd
.command('task-reward')
.description('Manage task reward activities');
taskRewardCmd
.command('list')
.description('List task reward activities')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--page <number>', 'page number', parsePositiveInteger)
.option('--size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.listTaskRewardActivities({
channelId: options.channelId,
page: options.page,
size: options.size,
output: options.output,
})));
taskRewardCmd
.command('create')
.description('Create a task reward activity')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--activity-name <name>', 'activity name')
.requiredOption('--task-rule <number>', 'task rule', parsePositiveInteger)
.requiredOption('--start-time <timestamp>', 'start time (timestamp in milliseconds)', api_command_1.parseTimestamp)
.requiredOption('--end-time <timestamp>', 'end time (timestamp in milliseconds)', api_command_1.parseTimestamp)
.requiredOption('--tasks-json <json>', 'task settings JSON array', api_command_1.parseJsonArray)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.createTaskRewardActivity({
channelId: options.channelId,
activityName: options.activityName,
taskRule: options.taskRule,
startTime: options.startTime,
endTime: options.endTime,
tasks: options.tasksJson,
force: options.force,
output: options.output,
})));
taskRewardCmd
.command('update')
.description('Update a task reward activity')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--activity-id <id>', 'activity ID')
.requiredOption('--tasks-json <json>', 'task settings JSON array', api_command_1.parseJsonArray)
.option('--activity-name <name>', 'activity name')
.option('--task-rule <number>', 'task rule', parsePositiveInteger)
.option('--start-time <timestamp>', 'start time (timestamp in milliseconds)', api_command_1.parseTimestamp)
.option('--end-time <timestamp>', 'end time (timestamp in milliseconds)', api_command_1.parseTimestamp)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.updateTaskRewardActivity({
channelId: options.channelId,
activityId: options.activityId,
activityName: options.activityName,
taskRule: options.taskRule,
startTime: options.startTime,
endTime: options.endTime,
tasks: options.tasksJson,
force: options.force,
output: options.output,
})));
taskRewardCmd
.command('delete')
.description('Delete a task reward activity')
.requiredOption('--activity-id <id>', 'activity ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.deleteTaskRewardActivity({
activityId: options.activityId,
force: options.force,
output: options.output,
})));
taskRewardCmd
.command('stop')
.description('Stop a task reward activity')
.requiredOption('--activity-id <id>', 'activity ID')
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.stopTaskRewardActivity({
activityId: options.activityId,
force: options.force,
output: options.output,
})));
taskRewardCmd
.command('stats')
.description('List task reward activity statistics')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.option('--page <number>', 'page number', parsePositiveInteger)
.option('--size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.listTaskRewardStats({
channelId: options.channelId,
page: options.page,
size: options.size,
output: options.output,
})));
taskRewardCmd
.command('viewer-detail')
.description('List viewer details for a task reward activity')
.requiredOption('-c, --channel-id <id>', 'channel ID')
.requiredOption('--activity-id <id>', 'activity ID')
.option('--viewer-id <id>', 'viewer ID')
.option('--page <number>', 'page number', parsePositiveInteger)
.option('--size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.listTaskRewardViewerDetails({
channelId: options.channelId,
activityId: options.activityId,
viewerId: options.viewerId,
page: options.page,
size: options.size,
output: options.output,
})));
taskRewardCmd
.command('viewer-list')
.description('List viewer-side task reward details')
.requiredOption('--viewer-id <id>', 'viewer ID')
.option('--page <number>', 'page number', parsePositiveInteger)
.option('--size <number>', 'page size', parsePositiveInteger)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.listViewerTaskRewardDetails({
viewerId: options.viewerId,
page: options.page,
size: options.size,
output: options.output,
})));
taskRewardCmd
.command('submit-accept-info')
.description('Submit viewer accept information for a task reward')
.requiredOption('--id <id>', 'viewer task reward record ID')
.requiredOption('--viewer-id <id>', 'viewer ID')
.requiredOption('--form-info-json <json>', 'accept form information JSON array', api_command_1.parseJsonArray)
.option('-f, --force', 'skip confirmation prompt')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => withInteractionHandler((handler) => handler.submitViewerTaskRewardAcceptInfo({
id: options.id,
viewerId: options.viewerId,
formInfo: options.formInfoJson,
force: options.force,
output: options.output,
})));
}
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;
}
}
return {
authConfig: authResult.config,
serviceConfig: {
baseUrl: configResult.config.baseUrl,
timeout: configResult.config.timeout,
debug: configResult.config.debug,
},
};
}
//# sourceMappingURL=interaction.commands.js.map