polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
555 lines (526 loc) ⢠26.2 kB
JavaScript
;
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