UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

481 lines (452 loc) • 21.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerChannelCommands = registerChannelCommands; exports.parseInteger = parseInteger; exports.validateScene = validateScene; exports.validateTemplate = validateTemplate; exports.validateLimit = validateLimit; exports.validateOutputFormat = validateOutputFormat; const channel_handler_1 = require("../handlers/channel.handler"); const manager_1 = require("../config/manager"); const auth_adapter_1 = require("../config/auth-adapter"); const errors_1 = require("../utils/errors"); 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, maxRetries: 3, debug: false } }; } else { throw error; } } const serviceConfig = { baseUrl: configResult.config.baseUrl, timeout: configResult.config.timeout, maxRetries: configResult.config.maxRetries, debug: configResult.config.debug }; const isVerbose = !!parentOptions.verbose; if (isVerbose) { console.log(`šŸ” Authentication Source: ${authResult.source}`); if (authResult.accountName) { console.log(`šŸ‘¤ Account: ${authResult.accountName}`); } console.log(''); } const result = { authConfig: authResult.config, serviceConfig, isVerbose, }; if (authResult.source) { result.authSource = authResult.source; } if (authResult.accountName) { result.accountName = authResult.accountName; } return result; } function registerChannelCommands(program) { const channelCmd = program.command('channel'); channelCmd.description('Manage live streaming channels'); const createCmd = channelCmd .command('create') .description('Create a new live streaming channel') .requiredOption('-n, --name <name>', 'channel name (required, max 100 characters)') .option('-d, --description <description>', 'channel description (optional, max 500 characters)') .option('--max-viewers <number>', 'maximum number of viewers (optional, max 100,000)', parseInteger) .option('--auto-record', 'enable automatic recording (optional)') .option('--scene <scene>', 'live scene type (optional)', validateScene, 'topclass') .option('--template <template>', 'channel template (optional)', validateTemplate, 'ppt') .option('-p, --password <password>', 'channel password (optional, 6-16 alphanumeric characters)') .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 channelHandler = new channel_handler_1.ChannelHandler(authConfig, serviceConfig); const channelOptions = { name: options.name, description: options.description, maxViewers: options.maxViewers, autoRecord: options.autoRecord || false, scene: options.scene, template: options.template, password: options.password, output: options.output }; await channelHandler.create(channelOptions); } catch (error) { if (error instanceof Error && error.message.includes('Authentication')) { const diagnostics = auth_adapter_1.authAdapter.getDiagnostics(program.opts()); console.error('\nšŸ” Authentication Diagnostics:'); diagnostics.availableSources.forEach(source => { const status = source.appId && source.appSecret ? 'āœ…' : 'āŒ'; console.error(` ${status} ${source.metadata.source}: ${source.type}`); }); if (diagnostics.errors.length > 0) { console.error('\nāŒ Errors:'); diagnostics.errors.forEach(error => console.error(` - ${error}`)); } } (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); createCmd.addHelpText('after', ` Examples: $ polyv-cli channel create -n "My Live Stream" $ polyv-cli channel create -n "Demo Channel" -d "Test channel for demo" $ polyv-cli channel create -n "Secure Stream" -p "stream123" --max-viewers 500 $ polyv-cli channel create -n "Video Stream" --scene cloudclass --template video $ polyv-cli channel create -n "JSON Output" -o json Alternative (full parameter names): $ polyv-cli channel create --name "My Live Stream" $ polyv-cli channel create --name "Demo Channel" --description "Test channel for demo" Scene Types: topclass - Top class scene (default) cloudclass - Cloud class scene telecast - Telecast scene akt - AKT scene Templates: ppt - PowerPoint template (default) video - Video template Output Formats: table - Formatted table output (default) json - JSON format for programmatic use `); const listCmd = channelCmd .command('list') .description('List live streaming channels with pagination') .option('-P, --page <number>', 'page number (optional, minimum 1, default 1)', parseInteger, 1) .option('-l, --limit <number>', 'items per page (optional, 1-100, default 20)', validateLimit, 20) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .option('--category-id <id>', 'filter by category ID (optional)') .option('--keyword <keyword>', 'filter by channel name keyword (optional)') .option('--label-id <id>', 'filter by label ID (optional)') .action(async (options) => { try { const parentOptions = program.opts(); const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions); const channelHandler = new channel_handler_1.ChannelHandler(authConfig, serviceConfig); const listOptions = { page: options.page, limit: options.limit, output: options.output, categoryId: options.categoryId, keyword: options.keyword, labelId: options.labelId }; await channelHandler.listChannels(listOptions); } catch (error) { if (error instanceof Error && error.message.includes('Authentication')) { const diagnostics = auth_adapter_1.authAdapter.getDiagnostics(program.opts()); console.error('\nšŸ” Authentication Diagnostics:'); diagnostics.availableSources.forEach(source => { const status = source.appId && source.appSecret ? 'āœ…' : 'āŒ'; console.error(` ${status} ${source.metadata.source}: ${source.type}`); }); if (diagnostics.errors.length > 0) { console.error('\nāŒ Errors:'); diagnostics.errors.forEach(error => console.error(` - ${error}`)); } } (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); listCmd.addHelpText('after', ` Examples: $ polyv-cli channel list $ polyv-cli channel list -P 2 -l 10 $ polyv-cli channel list -o json Alternative (full parameter names): $ polyv-cli channel list --page 2 --limit 10 --output json $ polyv-cli channel list --keyword "live stream" $ polyv-cli channel list --category-id "cat123" $ polyv-cli channel list --page 1 --limit 5 --output table Pagination: --page Page number (minimum 1, default 1) --limit Items per page (1-100, default 20) Filters: --category-id Filter by category ID --keyword Filter by channel name (partial match) --label-id Filter by label ID Output Formats: table Formatted table output (default) json JSON format for programmatic use `); const getCmd = channelCmd .command('get') .description('Get detailed information for a specific channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .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 channelHandler = new channel_handler_1.ChannelHandler(authConfig, serviceConfig); const getOptions = { channelId: options.channelId, output: options.output }; await channelHandler.getChannelDetail(getOptions); } catch (error) { if (error instanceof Error && error.message.includes('Authentication')) { const diagnostics = auth_adapter_1.authAdapter.getDiagnostics(program.opts()); console.error('\nšŸ” Authentication Diagnostics:'); diagnostics.availableSources.forEach(source => { const status = source.appId && source.appSecret ? 'āœ…' : 'āŒ'; console.error(` ${status} ${source.metadata.source}: ${source.type}`); }); if (diagnostics.errors.length > 0) { console.error('\nāŒ Errors:'); diagnostics.errors.forEach(error => console.error(` - ${error}`)); } } (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); getCmd.addHelpText('after', ` Examples: $ polyv-cli channel get --channelId 3151318 $ polyv-cli channel get --channelId 3151318 --output table $ polyv-cli channel get --channelId 3151318 --output json Parameter: --channelId Channel ID to retrieve details for (required) Output Formats: table Formatted table output with grouped information (default) json JSON format with all available data for programmatic use Note: The table format displays information in groups (Basic Information, Configuration, Statistics & Timing, etc.) for better readability. The json format includes all available fields from the API response. `); const updateCmd = channelCmd .command('update') .description('Update an existing live streaming channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .option('-n, --name <name>', 'channel name (max 100 characters)') .option('-d, --description <description>', 'channel description (max 500 characters)') .option('--publisher <publisher>', 'publisher/host name') .option('-p, --password <password>', 'channel password (6-16 alphanumeric characters)') .option('--max-viewers <number>', 'maximum number of viewers', parseInteger) .option('--start-time <timestamp>', 'live start time (timestamp)', parseInteger) .option('--end-time <timestamp>', 'live end time (timestamp)', parseInteger) .option('--page-views <number>', 'page view count', parseInteger) .option('--likes <number>', 'likes count', parseInteger) .option('--cover-img <url>', 'cover image URL') .option('--splash-img <url>', 'splash image URL') .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 channelHandler = new channel_handler_1.ChannelHandler(authConfig, serviceConfig); const updateOptions = { channelId: options.channelId, name: options.name, description: options.description, publisher: options.publisher, password: options.password, maxViewers: options.maxViewers, startTime: options.startTime, endTime: options.endTime, pageView: options.pageViews, likes: options.likes, coverImg: options.coverImg, splashImg: options.splashImg, output: options.output }; await channelHandler.updateChannel(updateOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); updateCmd.addHelpText('after', ` Examples: $ polyv-cli channel update --channelId 3151318 --name "New Channel Name" $ polyv-cli channel update --channelId 3151318 --name "Test" --publisher "Host Name" $ polyv-cli channel update --channelId 3151318 --password "newpass123" --max-viewers 1000 $ polyv-cli channel update --channelId 3151318 --description "Updated description" --output json $ polyv-cli channel update --channelId 3151318 --cover-img "https://example.com/cover.jpg" Required Parameter: --channelId Channel ID to update (required) Update Parameters (at least one required): --name Channel name (max 100 characters) --description Channel description (max 500 characters) --publisher Publisher/host name --password Channel password (6-16 alphanumeric characters) --max-viewers Maximum number of viewers (positive integer) --start-time Live start time (13-digit timestamp) --end-time Live end time (13-digit timestamp) --page-views Page view count (non-negative integer) --likes Likes count (non-negative integer) --cover-img Cover image URL --splash-img Splash image URL Output Formats: table Formatted table output with update summary (default) json JSON format for programmatic use Note: At least one update parameter must be provided. The password field will be masked in output for security. Time parameters should be 13-digit timestamps. `); const deleteCmd = channelCmd .command('delete') .description('Delete a single live streaming channel with confirmation') .requiredOption('-c, --channelId <id>', 'channel ID to delete') .option('-f, --force', 'force delete without confirmation') .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 channelHandler = new channel_handler_1.ChannelHandler(authConfig, serviceConfig); const deleteOptions = { channelId: options.channelId, force: options.force || false, output: options.output }; await channelHandler.deleteChannel(deleteOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); deleteCmd.addHelpText('after', ` Examples: $ polyv-cli channel delete --channelId 3151318 $ polyv-cli channel delete --channelId 3151318 --force $ polyv-cli channel delete --channelId 3151318 --output json Required Parameter: --channelId Channel ID to delete (required) Optional Parameters: --force Skip interactive confirmation prompt (use with caution!) --output Output format (table|json, default: table) Output Formats: table Formatted table output with deletion confirmation (default) json JSON format for programmatic use 🚨 WARNING: Channel deletion is PERMANENT and cannot be undone. All channel data, including recordings, chat history, and configurations will be lost. By default, you will be prompted to confirm the deletion. Use --force flag to skip confirmation, but be very careful! Interactive Confirmation: When not using --force, you will be prompted to type 'yes' to confirm the deletion. This helps prevent accidental deletions. Non-Interactive Environments: In non-TTY environments (scripts, CI/CD), you must use --force flag to proceed with deletion. `); const batchDeleteCmd = channelCmd .command('batch-delete') .description('Delete multiple live streaming channels at once') .requiredOption('--channelIds <ids...>', 'channel IDs to delete (space-separated list)') .option('-f, --force', 'force delete without confirmation') .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 channelHandler = new channel_handler_1.ChannelHandler(authConfig, serviceConfig); const deleteOptions = { channelIds: options.channelIds, force: options.force || false, output: options.output }; await channelHandler.deleteChannels(deleteOptions); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); batchDeleteCmd.addHelpText('after', ` Examples: $ polyv-cli channel batch-delete --channelIds 3151318 $ polyv-cli channel batch-delete --channelIds 3151318 3151319 3151320 $ polyv-cli channel batch-delete --channelIds 3151318 --force $ polyv-cli channel batch-delete --channelIds 3151318 3151319 --output json Required Parameter: --channelIds Channel IDs to delete (space-separated list, max 100) Optional Parameters: --force Skip confirmation prompts (be careful!) --output Output format (table|json, default: table) Output Formats: table Formatted table output with deletion summary (default) json JSON format for programmatic use āš ļø WARNING: Channel deletion is PERMANENT and cannot be undone. All channel data, including recordings, chat history, and configurations will be lost. Use --force flag to skip confirmation prompts, but be very careful! Examples with multiple channels: $ polyv-cli channel batch-delete --channelIds 1001 1002 1003 $ polyv-cli channel batch-delete --channelIds 1001 1002 1003 --force --output json Note: This command allows deleting up to 100 channels in a single operation. For single channel deletion with interactive confirmation, use 'channel delete' instead. `); } function parseInteger(value) { const parsed = parseInt(value, 10); if (isNaN(parsed)) { throw new Error(`Invalid number: ${value}`); } return parsed; } function validateScene(value) { const validScenes = ['topclass', 'cloudclass', 'telecast', 'akt']; if (!validScenes.includes(value)) { throw new Error(`Invalid scene type: ${value}. Must be one of: ${validScenes.join(', ')}`); } return value; } function validateTemplate(value) { const validTemplates = ['ppt', 'video']; if (!validTemplates.includes(value)) { throw new Error(`Invalid template: ${value}. Must be one of: ${validTemplates.join(', ')}`); } return value; } function validateLimit(value) { const parsed = parseInt(value, 10); if (isNaN(parsed)) { throw new Error(`Invalid limit: ${value}. Must be a number.`); } if (parsed < 1 || parsed > 100) { throw new Error(`Invalid limit: ${value}. Must be between 1 and 100.`); } return parsed; } function validateOutputFormat(value) { const validFormats = ['table', 'json']; if (!validFormats.includes(value)) { throw new Error(`Invalid output format: ${value}. Must be one of: ${validFormats.join(', ')}`); } return value; } //# sourceMappingURL=channel.commands.js.map