UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

555 lines (526 loc) • 26.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerStreamCommands = registerStreamCommands; const stream_handler_1 = require("../handlers/stream.handler"); const stream_service_1 = require("../services/stream.service"); 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 configResult = await manager_1.configManager.load({ cliOptions: parentOptions, }); const authResult = auth_adapter_1.authAdapter.tryGetAuthConfig(parentOptions); if (!authResult) { throw new Error(auth_adapter_1.authAdapter.getStatusMessage(parentOptions)); } const serviceConfig = { baseUrl: configResult.config.baseUrl, timeout: configResult.config.timeout, debug: configResult.config.debug }; const isVerbose = !!parentOptions.verbose; if (isVerbose) { console.log(`āœ… Using authentication from: ${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 registerStreamCommands(program) { const streamCmd = program.command('stream'); streamCmd.description('Manage live streaming operations'); const getKeyCmd = streamCmd .command('get-key') .description('Get RTMP URL and stream key for a live channel') .requiredOption('-c, --channelId <id>', 'channel ID (required, must be a live channel)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .option('-v, --verbose', 'show detailed authentication information') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const streamOptions = { channelId: options.channelId, output: options.output }; await streamHandler.getStreamKey(streamOptions); } 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); } }); getKeyCmd.addHelpText('after', ` Examples: $ polyv-cli stream get-key -c 3151318 $ polyv-cli stream get-key -c 3151318 -o json $ polyv-cli stream get-key -c 3151318 -o table Alternative (full parameter names): $ polyv-cli stream get-key -c 3151318 -o json Requirements: • Channel must be in live streaming state • Valid authentication credentials required • Channel ID must exist and be accessible Output Formats: table Formatted table output with masked stream key (default) json JSON format with full credentials (for programmatic use) Security Notes: • Stream keys are sensitive credentials - keep them secure • Table format masks the stream key for security • JSON format shows full credentials - use carefully • Do not share stream keys in public channels or logs Usage in OBS/Streaming Software: 1. Copy the RTMP URL to your streaming software's server field 2. Copy the stream key to your streaming software's key field 3. Start streaming to begin live broadcast `); const startCmd = streamCmd .command('start') .description('Start live streaming for a channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const streamOptions = { channelId: options.channelId }; await streamHandler.startStream(streamOptions); } 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); } }); startCmd.addHelpText('after', ` Examples: $ polyv-cli stream start -c 3151318 $ polyv-cli stream start -c 3151318 --appId <id> --appSecret <secret> Requirements: • Channel must exist and be accessible • Valid authentication credentials required • User must have permission to start streams for the channel Usage Notes: • This command sets the channel status to "live" • The actual streaming still requires OBS or other streaming software • Use 'stream get-key' to obtain streaming credentials after starting • Stream status changes do not trigger automatic callbacks Expected Behavior: • Success: Channel status changes to live, confirmation displayed • Already Started: Command completes with informational message • Channel Not Found: Error message displayed with specific details • Permission Denied: Authentication or authorization error displayed `); const stopCmd = streamCmd .command('stop') .description('Stop live streaming for a channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const streamOptions = { channelId: options.channelId }; await streamHandler.stopStream(streamOptions); } 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); } }); stopCmd.addHelpText('after', ` Examples: $ polyv-cli stream stop -c 3151318 $ polyv-cli stream stop -c 3151318 --appId <id> --appSecret <secret> Requirements: • Channel must exist and be accessible • Valid authentication credentials required • User must have permission to stop streams for the channel Usage Notes: • This command sets the channel status to "stopped" • The streaming session will be terminated immediately • Use this command to end live broadcasts cleanly • Stream status changes do not trigger automatic callbacks Expected Behavior: • Success: Channel status changes to stopped, confirmation displayed • Already Stopped: Command completes with informational message • Channel Not Found: Error message displayed with specific details • Permission Denied: Authentication or authorization error displayed • Not Live: Error if channel is not currently streaming `); const statusCmd = streamCmd .command('status') .description('Get real-time status information for a live channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .option('-w, --watch', 'enable continuous monitoring (updates every 5 seconds)') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const streamOptions = { channelId: options.channelId, output: options.output, watch: options.watch }; if (options.watch) { console.log('šŸ“ŗ Starting continuous monitoring (Press Ctrl+C to stop)...\n'); const updateInterval = setInterval(async () => { try { process.stdout.write('\x1Bc'); console.log('šŸ“ŗ Live Stream Monitor - Press Ctrl+C to stop\n'); await streamHandler.getStreamStatus(streamOptions); console.log(`\nā±ļø Last updated: ${new Date().toLocaleTimeString()}`); console.log('šŸ”„ Updating in 5 seconds...'); } catch (error) { console.error('āŒ Error updating status:', error instanceof Error ? error.message : String(error)); } }, 5000); process.on('SIGINT', () => { clearInterval(updateInterval); console.log('\n\nšŸ‘‹ Monitoring stopped. Goodbye!'); process.exit(0); }); await streamHandler.getStreamStatus(streamOptions); console.log(`\nā±ļø Last updated: ${new Date().toLocaleTimeString()}`); console.log('šŸ”„ Updating in 5 seconds...'); } else { await streamHandler.getStreamStatus(streamOptions); } } 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); } }); statusCmd.addHelpText('after', ` Examples: $ polyv-cli stream status -c 3151318 $ polyv-cli stream status -c 3151318 -o json $ polyv-cli stream status -c 3151318 -w $ polyv-cli stream status -c 3151318 -w -o table Alternative (full parameter names): $ polyv-cli stream status --channelId 3151318 --output json --watch Requirements: • Channel must exist and be accessible • Valid authentication credentials required • No special permissions needed for status checking Usage Notes: • Status command works for channels in any state (live, waiting, stopped) • Live channels show detailed performance metrics and network information • Watch mode refreshes status every 5 seconds automatically • Use Ctrl+C to stop watch mode • JSON output provides complete status data for programmatic use Status Information Displayed: • Current streaming status (Live, Waiting, Stopped, Error) • Stream duration (for live streams) • Performance metrics (FPS, bandwidth, frame loss rate) • Network information (deploy address, input address, stream name) • Error details (if applicable) • Last update timestamp Output Formats: table Formatted table output with status icons (default) json Complete JSON data for programmatic use Watch Mode: • Continuously monitors stream status • Updates every 5 seconds automatically • Shows live performance metrics • Perfect for monitoring active streams • Press Ctrl+C to exit `); const pushCmd = streamCmd .command('push') .description('Push a local video file to a live channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .requiredOption('-f, --file <path>', 'path to the video file (required)') .option('--verify', 'enable real-time stream verification') .option('--verification-interval <seconds>', 'verification check interval in seconds (default: 10)', parseFloat, 10) .option('--quality-threshold <fps>', 'quality threshold for FPS warnings (default: 15)', parseFloat, 15) .option('--show-viewer-links', 'show viewer links during streaming') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const streamOptions = { channelId: options.channelId, file: options.file, verify: options.verify, verificationInterval: options.verificationInterval, qualityThreshold: options.qualityThreshold, showViewerLinks: options.showViewerLinks }; await streamHandler.pushStream(streamOptions); } 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); } }); pushCmd.addHelpText('after', ` Examples: $ polyv-cli stream push -c 3151318 -f /path/to/video.mp4 $ polyv-cli stream push -c 3151318 -f /path/to/video.mp4 --verify $ polyv-cli stream push -c 3151318 -f /path/to/video.mp4 --verify --verification-interval 5 --quality-threshold 20 $ polyv-cli stream push -c 3151318 -f /path/to/video.mp4 --show-viewer-links Requirements: • FFmpeg must be installed and in the system's PATH • Channel must exist and be accessible • Valid authentication credentials required Usage Notes: • This command uses FFmpeg to push the stream • The command will terminate when the video finishes streaming • Press Ctrl+C to stop the stream manually • Use --verify to enable real-time quality monitoring • Use --show-viewer-links to display playback URLs Verification Options: --verify Enable real-time stream verification --verification-interval Check interval in seconds (default: 10) --quality-threshold FPS threshold for warnings (default: 15) --show-viewer-links Display viewer links during streaming `); const verifyCmd = streamCmd .command('verify') .description('Verify stream quality and performance for a live channel') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .option('-d, --duration <seconds>', 'verification duration in seconds (default: 60)', parseFloat, 60) .option('-i, --interval <seconds>', 'check interval in seconds (default: 10)', parseFloat, 10) .option('-t, --quality-threshold <fps>', 'quality threshold for FPS warnings (default: 15)', parseFloat, 15) .option('--show-viewer-links', 'show viewer links before verification') .option('-s, --save-report <path>', 'save verification report to file') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const verifyOptions = { channelId: options.channelId, duration: options.duration, interval: options.interval, qualityThreshold: options.qualityThreshold, showViewerLinks: options.showViewerLinks, saveReport: options.saveReport, output: options.output }; await streamHandler.verifyStream(verifyOptions); } 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); } }); verifyCmd.addHelpText('after', ` Examples: $ polyv-cli stream verify -c 3151318 $ polyv-cli stream verify -c 3151318 -d 120 -i 5 $ polyv-cli stream verify -c 3151318 -t 20 --show-viewer-links $ polyv-cli stream verify -c 3151318 -s report.json -o json Requirements: • Channel must be in live streaming state • Valid authentication credentials required • Channel must be actively streaming for meaningful results Usage Notes: • Performs systematic quality checks over specified duration • Monitors FPS, bandwidth, and connection stability • Generates detailed performance reports • Ideal for troubleshooting streaming issues • Use before important live broadcasts Verification Options: -d, --duration Test duration in seconds (10-3600, default: 60) -i, --interval Check interval in seconds (5-300, default: 10) -t, --quality-threshold FPS threshold for warnings (default: 15) --show-viewer-links Display viewer links before starting -s, --save-report Save detailed report to JSON file -o, --output Output format (table|json, default: table) Report Contents: • Performance timeline with timestamps • Quality metrics (FPS, bandwidth, latency) • Issue detection and severity levels • Reliability percentage and recommendations • Viewer links for testing different protocols `); const monitorCmd = streamCmd .command('monitor') .description('Monitor stream status in real-time with live dashboard') .requiredOption('-c, --channelId <id>', 'channel ID (required)') .option('-r, --refresh <seconds>', 'refresh interval in seconds (default: 5)', parseFloat, 5) .option('--alerts', 'enable quality alerts and notifications') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const parentOptions = program.opts(); const combinedOptions = { ...parentOptions, ...options }; const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(combinedOptions); const streamService = new stream_service_1.StreamService(authConfig, serviceConfig); const streamHandler = new stream_handler_1.StreamHandler(streamService); const monitorOptions = { channelId: options.channelId, refresh: options.refresh, alerts: options.alerts, output: options.output }; await streamHandler.monitorStream(monitorOptions); } 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); } }); monitorCmd.addHelpText('after', ` Examples: $ polyv-cli stream monitor -c 3151318 $ polyv-cli stream monitor -c 3151318 -r 3 --alerts $ polyv-cli stream monitor -c 3151318 -o json Requirements: • Channel must exist and be accessible • Valid authentication credentials required • Works with channels in any state (live, waiting, stopped) Usage Notes: • Provides real-time dashboard view of stream status • Automatically refreshes at specified intervals • Shows performance metrics, uptime, and quality indicators • Perfect for monitoring active live streams • Press Ctrl+C to stop monitoring Monitoring Features: • Live status display with visual indicators • Performance metrics (FPS, bandwidth, latency) • Stream uptime and duration tracking • Quality alerts when issues are detected • Activity log with recent status changes • Clean, refreshing dashboard interface Monitor Options: -r, --refresh Refresh interval in seconds (1-60, default: 5) --alerts Enable quality alerts and notifications -o, --output Output format (table|json, default: table) Perfect For: • Monitoring live broadcasts • Troubleshooting connection issues • Ensuring consistent stream quality • Keeping track of stream performance `); } function validateOutputFormat(value) { if (value !== 'table' && value !== 'json') { throw new Error(`Invalid output format: ${value}. Must be 'table' or 'json'`); } return value; } //# sourceMappingURL=stream.commands.js.map