polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
601 lines (582 loc) • 32.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateOutputFormat = validateOutputFormat;
exports.validateDateFormat = validateDateFormat;
exports.validateDateRange = validateDateRange;
exports.registerStatisticsCommands = registerStatisticsCommands;
const statistics_handler_1 = require("../handlers/statistics.handler");
const manager_1 = require("../config/manager");
const auth_adapter_1 = require("../config/auth-adapter");
const errors_1 = require("../utils/errors");
const statistics_service_sdk_1 = require("../services/statistics.service.sdk");
const api_command_1 = require("../utils/api-command");
const date_validation_1 = require("../utils/date-validation");
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
};
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 validateOutputFormat(value) {
if (!['table', 'json'].includes(value)) {
throw new Error('Output format must be either "table" or "json"');
}
return value;
}
function validateDateFormat(value) {
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (!regex.test(value)) {
throw new Error('Date format must be yyyy-MM-dd');
}
const date = new Date(value);
if (isNaN(date.getTime())) {
throw new Error(`Invalid date: ${value}`);
}
const [year, month, day] = value.split('-').map(Number);
if (date.getFullYear() !== year ||
date.getMonth() + 1 !== month ||
date.getDate() !== day) {
throw new Error(`Invalid date: ${value}`);
}
return value;
}
function validateDateRange(startDay, endDay) {
const result = (0, date_validation_1.validateDateRange)(startDay, endDay);
if (!result.valid) {
throw new Error(result.error || 'Invalid date range');
}
}
function registerStatisticsCommands(program) {
const statisticsCmd = program.command('statistics');
statisticsCmd.description('View live streaming statistics data');
const runV4StatisticsCommand = async (options, action) => {
try {
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts());
const service = new statistics_service_sdk_1.StatisticsServiceSdk(authConfig, serviceConfig);
(0, api_command_1.displayApiResult)(await action(service), options.output);
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
};
statisticsCmd.command('session-summary-list')
.description('List V4 session statistics summaries')
.option('-c, --channel-id <channelId>', 'channel ID')
.option('--keyword <keyword>', 'keyword')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', 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);
await new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig).listSessionSummary(options);
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
statisticsCmd.command('inviter-poster-list')
.description('List inviter poster statistics')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', 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);
await new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig).listInviterPoster(options);
}
catch (error) {
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
statisticsCmd.command('lottery-list')
.description('List V4 channel lottery statistics records')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--lottery-id <id>', 'lottery ID')
.option('--session-id <id>', 'session ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.listChannelLotteryRecords((0, api_command_1.apiParams)(options))));
statisticsCmd.command('live-data')
.description('Get V4 channel live data summary')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getLiveData((0, api_command_1.apiParams)(options))));
statisticsCmd.command('live-session-list')
.description('List V4 live session statistics')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.listSessionStats((0, api_command_1.apiParams)(options))));
statisticsCmd.command('weixin-booking-list')
.description('List V4 WeChat booking records')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.listWeixinBookings((0, api_command_1.apiParams)(options))));
statisticsCmd.command('invite-list')
.description('List V4 invite statistics records')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--sender-viewer-id <id>', 'sender viewer ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.listInviteStats((0, api_command_1.apiParams)(options))));
statisticsCmd.command('channel-play-summary')
.description('Get multi-channel play summary statistics')
.requiredOption('--start-date <date>', 'start date (yyyy-MM-dd)', validateDateFormat)
.requiredOption('--end-date <date>', 'end date (yyyy-MM-dd)', validateDateFormat)
.option('--user-id <id>', 'account user ID; defaults to configured userId')
.option('--channel-ids <ids>', 'channel IDs, comma-separated')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getChannelPlaySummary((0, api_command_1.apiParams)(options))));
statisticsCmd.command('realtime-viewers')
.description('Get realtime viewer counts for channels')
.requiredOption('--channel-ids <ids>', 'channel IDs, comma-separated')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getRealtimeViewers((0, api_command_1.apiParams)(options))));
statisticsCmd.command('channel-statistic')
.description('Get channel statistic data')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.requiredOption('--start-date <date>', 'start date (yyyy-MM-dd)', validateDateFormat)
.requiredOption('--end-date <date>', 'end date (yyyy-MM-dd)', validateDateFormat)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getChannelStatistic((0, api_command_1.apiParams)(options))));
statisticsCmd.command('channel-session-stats')
.description('Get channel session statistics')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--session-ids <ids>', 'session IDs, comma-separated')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getSessionStats((0, api_command_1.apiParams)(options))));
statisticsCmd.command('mic-list')
.description('List channel mic detail statistics')
.option('--channel-ids <ids>', 'channel IDs, comma-separated')
.option('--start-day <date>', 'start date (yyyy-MM-dd)', validateDateFormat)
.option('--end-day <date>', 'end date (yyyy-MM-dd)', validateDateFormat)
.option('--page <page>', 'page number', parseInt)
.option('--size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getMicDetailList((0, api_command_1.apiParams)(options))));
statisticsCmd.command('link-mic-list')
.description('List channel link-mic detail logs')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.requiredOption('--start-date <date>', 'start date (yyyy-MM-dd)', validateDateFormat)
.requiredOption('--end-date <date>', 'end date (yyyy-MM-dd)', validateDateFormat)
.option('--page <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getLinkMicDetailList((0, api_command_1.apiParams)(options))));
statisticsCmd.command('channel-summary')
.description('Get channel view summary statistics')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.requiredOption('--start-day <date>', 'start date (yyyy-MM-dd)', validateDateFormat)
.requiredOption('--end-day <date>', 'end date (yyyy-MM-dd)', validateDateFormat)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getSummary((0, api_command_1.apiParams)(options))));
statisticsCmd.command('product-click')
.description('List product click statistics')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--session-id <id>', 'session ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getProductClickStats((0, api_command_1.apiParams)(options))));
statisticsCmd.command('product-list-click')
.description('List product-list click statistics')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--session-id <id>', 'session ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getProductListStats((0, api_command_1.apiParams)(options))));
statisticsCmd.command('redpack-list')
.description('List redpack statistics')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--session-id <id>', 'session ID')
.option('--start-time <timestamp>', 'start timestamp', parseInt)
.option('--end-time <timestamp>', 'end timestamp', parseInt)
.option('--page-number <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getRedpackStats((0, api_command_1.apiParams)(options))));
statisticsCmd.command('realtime-v1')
.description('Get realtime viewers using the legacy V1 statistics API')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.option('--user-id <id>', 'account user ID; defaults to configured userId')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getRealtimeViewersV1((0, api_command_1.apiParams)(options))));
statisticsCmd.command('viewlog-v1')
.description('Get V1 viewlog records')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.requiredOption('--current-day <date>', 'query date (yyyy-MM-dd)', validateDateFormat)
.option('--user-id <id>', 'account user ID; defaults to configured userId')
.option('--param1 <value>', 'legacy API param1 value')
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getViewlogV1((0, api_command_1.apiParams)(options))));
statisticsCmd.command('viewlog-v2')
.description('Get V2 paged viewlog records')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.requiredOption('--current-day <date>', 'query date (yyyy-MM-dd)', validateDateFormat)
.option('--page <page>', 'page number', parseInt)
.option('--page-size <size>', 'page size', parseInt)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action((options) => runV4StatisticsCommand(options, (service) => service.getViewlog2((0, api_command_1.apiParams)(options))));
const viewCmd = statisticsCmd
.command('view')
.description('View daily statistics for a channel')
.requiredOption('-c, --channel-id <channelId>', 'channel ID')
.requiredOption('--start-day <date>', 'start date (yyyy-MM-dd)', validateDateFormat)
.requiredOption('--end-day <date>', 'end date (yyyy-MM-dd)', validateDateFormat)
.option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
validateDateRange(options.startDay, options.endDay);
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const statisticsHandler = new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig);
const viewOptions = {
channelId: options.channelId,
startDay: options.startDay,
endDay: options.endDay,
output: options.output
};
await statisticsHandler.viewStatistics(viewOptions);
}
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(err => console.error(` - ${err}`));
}
}
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
viewCmd.addHelpText('after', `
Examples:
# View daily statistics for a channel
$ polyv-live-cli statistics view -c "3151318" --start-day "2024-01-01" --end-day "2024-01-31"
# Output in JSON format
$ polyv-live-cli statistics view -c "3151318" --start-day "2024-01-01" --end-day "2024-01-31" -o json
# With full parameter names
$ polyv-live-cli statistics view --channel-id "3151318" --start-day "2024-01-01" --end-day "2024-01-31" --output table
Date Range:
--start-day Start date in yyyy-MM-dd format (required)
--end-day End date in yyyy-MM-dd format (required)
Note: Date range cannot exceed 60 days
Output Formats:
table Formatted table output (default)
json JSON format for programmatic use
Notes:
- Channel ID is required for all statistics queries
- Date range cannot exceed 60 days
- Statistics include PC and mobile view data
`);
const concurrencyCmd = statisticsCmd
.command('concurrency')
.description('查看历史并发数据')
.requiredOption('-c, --channel-id <channelId>', '频道ID')
.requiredOption('--start-date <date>', '开始日期 (yyyy-MM-dd)', validateDateFormat)
.requiredOption('--end-date <date>', '结束日期 (yyyy-MM-dd)', validateDateFormat)
.option('-o, --output <format>', '输出格式 (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
validateDateRange(options.startDate, options.endDate);
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const statisticsHandler = new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig);
const concurrencyOptions = {
channelId: options.channelId,
startDate: options.startDate,
endDate: options.endDate,
output: options.output
};
await statisticsHandler.viewConcurrency(concurrencyOptions);
}
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(err => console.error(` - ${err}`));
}
}
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
concurrencyCmd.addHelpText('after', `
Examples:
# View historical concurrency data
$ polyv-live-cli statistics concurrency -c "3151318" --start-date "2024-01-01" --end-date "2024-01-31"
# Output in JSON format
$ polyv-live-cli statistics concurrency -c "3151318" --start-date "2024-01-01" --end-date "2024-01-31" -o json
Date Range:
--start-date Start date in yyyy-MM-dd format (required)
--end-date End date in yyyy-MM-dd format (required)
Note: Date range cannot exceed 60 days
Output Formats:
table Formatted table output (default)
json JSON format for programmatic use
`);
const maxConcurrentCmd = statisticsCmd
.command('max-concurrent')
.description('查看历史最高并发人数')
.requiredOption('-c, --channel-id <channelId>', '频道ID')
.requiredOption('--start-time <timestamp>', '开始时间戳 (13位毫秒)', parseInt)
.requiredOption('--end-time <timestamp>', '结束时间戳 (13位毫秒)', parseInt)
.option('-o, --output <format>', '输出格式 (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const rangeValidation = (0, date_validation_1.validateTimestampRange)(options.startTime, options.endTime);
if (!rangeValidation.valid) {
throw new Error(rangeValidation.error || 'Invalid time range');
}
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const statisticsHandler = new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig);
const maxConcurrentOptions = {
channelId: options.channelId,
startTime: options.startTime,
endTime: options.endTime,
output: options.output
};
await statisticsHandler.viewMaxConcurrent(maxConcurrentOptions);
}
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(err => console.error(` - ${err}`));
}
}
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
maxConcurrentCmd.addHelpText('after', `
Examples:
# View maximum historical concurrent viewers
$ polyv-live-cli statistics max-concurrent -c "3151318" --start-time 1704067200000 --end-time 1735689600000
# Output in JSON format
$ polyv-live-cli statistics max-concurrent -c "3151318" --start-time 1704067200000 --end-time 1735689600000 -o json
Timestamp Range:
--start-time Start timestamp in 13-digit milliseconds (required)
--end-time End timestamp in 13-digit milliseconds (required)
Note: Time range cannot exceed 3 months
Output Formats:
table Formatted output (default)
json JSON format for programmatic use
`);
const audienceCmd = statisticsCmd.command('audience');
audienceCmd.description('View audience statistics');
const regionCmd = audienceCmd
.command('region')
.description('View audience region distribution')
.requiredOption('-c, --channel-id <channelId>', '频道ID')
.requiredOption('--start-time <timestamp>', '开始时间戳 (13位毫秒)', parseInt)
.requiredOption('--end-time <timestamp>', '结束时间戳 (13位毫秒)', parseInt)
.option('-t, --type <type>', '地域类型 (country/province/city)', 'province')
.option('-o, --output <format>', '输出格式 (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const rangeValidation = (0, date_validation_1.validate90DayTimestampRange)(options.startTime, options.endTime);
if (!rangeValidation.valid) {
throw new Error(rangeValidation.error || 'Invalid time range');
}
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const statisticsHandler = new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig);
const regionOptions = {
channelId: options.channelId,
startTime: options.startTime,
endTime: options.endTime,
type: options.type,
output: options.output
};
await statisticsHandler.viewRegionDistribution(regionOptions);
}
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(err => console.error(` - ${err}`));
}
}
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
regionCmd.addHelpText('after', `
Examples:
# View region distribution
$ polyv-live-cli statistics audience region -c "3151318" --start-time 1648742400000 --end-time 1651334399000
# With city type
$ polyv-live-cli statistics audience region -c "3151318" --start-time 1648742400000 --end-time 1651334399000 --type city
# Output in JSON format
$ polyv-live-cli statistics audience region -c "3151318" --start-time 1648742400000 --end-time 1651334399000 -o json
Timestamp Range:
--start-time Start timestamp in 13-digit milliseconds (required)
--end-time End timestamp in 13-digit milliseconds (required)
Note: Time range cannot exceed 90 days
Region Types:
--type Region type (default: province)
country: View by country
province: View by province (default)
city: View by city
Output Formats:
table Formatted table output (default)
json JSON format for programmatic use
`);
const deviceCmd = audienceCmd
.command('device')
.description('View audience device distribution')
.requiredOption('-c, --channel-id <channelId>', '频道ID')
.requiredOption('--start-time <timestamp>', '开始时间戳 (13位毫秒)', parseInt)
.requiredOption('--end-time <timestamp>', '结束时间戳 (13位毫秒)', parseInt)
.option('-o, --output <format>', '输出格式 (table|json)', validateOutputFormat, 'table')
.action(async (options) => {
try {
const rangeValidation = (0, date_validation_1.validate90DayTimestampRange)(options.startTime, options.endTime);
if (!rangeValidation.valid) {
throw new Error(rangeValidation.error || 'Invalid time range');
}
const parentOptions = program.opts();
const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(parentOptions);
const statisticsHandler = new statistics_handler_1.StatisticsHandler(authConfig, serviceConfig);
const deviceOptions = {
channelId: options.channelId,
startTime: options.startTime,
endTime: options.endTime,
output: options.output
};
await statisticsHandler.viewDeviceDistribution(deviceOptions);
}
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(err => console.error(` - ${err}`));
}
}
(0, errors_1.logError)(error instanceof Error ? error : new Error(String(error)));
process.exit(1);
}
});
deviceCmd.addHelpText('after', `
Examples:
# View device distribution
$ polyv-live-cli statistics audience device -c "3151318" --start-time 1651386101000 --end-time 1652336501462
# Output in JSON format
$ polyv-live-cli statistics audience device -c "3151318" --start-time 1651386101000 --end-time 1652336501462 -o json
Timestamp Range:
--start-time Start timestamp in 13-digit milliseconds (required)
--end-time End timestamp in 13-digit milliseconds (required)
Note: Time range cannot exceed 90 days
Output Formats:
table Formatted table output (default)
json JSON format for programmatic use
`);
}
//# sourceMappingURL=statistics.commands.js.map