UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

446 lines (435 loc) • 21.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateWatermarkPosition = validateWatermarkPosition; exports.validateWatermarkOpacity = validateWatermarkOpacity; exports.validateYNValue = validateYNValue; exports.validateOutputFormat = validateOutputFormat; exports.registerPlayerCommands = registerPlayerCommands; const player_handler_1 = require("../handlers/player.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 validateWatermarkPosition(value) { const validPositions = ['tl', 'tr', 'bl', 'br']; if (!validPositions.includes(value)) { throw new Error(`watermarkPosition must be one of: ${validPositions.join(', ')}`); } return value; } function validateWatermarkOpacity(value) { const opacity = parseFloat(value); if (isNaN(opacity) || opacity < 0 || opacity > 1) { throw new Error('watermarkOpacity must be a number between 0 and 1'); } return opacity; } function validateYNValue(value) { if (value !== 'Y' && value !== 'N') { throw new Error('Value must be "Y" or "N"'); } return value; } function parseFontSize(value) { if (['small', 'middle', 'large'].includes(value)) { return value; } const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 1 || parsed > 256) { throw new Error('font size must be 1-256 or one of small, middle, large'); } return parsed; } function validateAntiRecordType(value) { if (value !== 'marquee' && value !== 'watermark') { throw new Error('anti-record type must be marquee or watermark'); } return value; } function validateAntiRecordModel(value) { if (!['fixed', 'nickname', 'diyurl'].includes(value)) { throw new Error('model type must be fixed, nickname, or diyurl'); } return value; } function validateShowMode(value) { if (value !== 'roll' && value !== 'flicker') { throw new Error('show mode must be roll or flicker'); } return value; } function validateHeadAdvertType(value) { if (!['NONE', 'IMAGE', 'FLV'].includes(value)) { throw new Error('head advert type must be NONE, IMAGE, or FLV'); } return value; } function validateOutputFormat(value) { if (!['table', 'json'].includes(value)) { throw new Error('Output format must be either "table" or "json"'); } return value; } 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 registerPlayerCommands(program) { const playerCmd = program.command('player'); playerCmd.description('Manage channel player settings'); const configCmd = playerCmd.command('config'); configCmd.description('Manage channel player configuration'); const getCmd = configCmd .command('get') .description('Get player configuration for a channel') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .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 playerHandler = new player_handler_1.PlayerHandler(authConfig, serviceConfig); const getOptions = { channelId: options.channelId, output: options.output }; await playerHandler.getConfig(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(err => console.error(` - ${err}`)); } } (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); getCmd.addHelpText('after', ` Examples: # Get player configuration for a channel $ polyv-live-cli player config get -c "3151318" # Output in JSON format $ polyv-live-cli player config get -c "3151318" -o json # With full parameter names $ polyv-live-cli player config get --channel-id "3151318" --output table Output Formats: table Formatted table output (default) json JSON format for programmatic use Notes: - Channel ID is required for all player config queries - Configuration includes watermark, warmup image, and view data settings `); const updateCmd = configCmd .command('update') .description('Update player configuration for a channel') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .option('--watermark-enabled <enabled>', 'watermark enabled (Y/N)', validateYNValue) .option('--watermark-url <url>', 'watermark image URL') .option('--watermark-position <position>', 'watermark position (tl/tr/bl/br)', validateWatermarkPosition) .option('--watermark-opacity <opacity>', 'watermark opacity (0-1)', validateWatermarkOpacity) .option('--warmup-enabled <enabled>', 'warmup enabled (Y/N)', validateYNValue) .option('--warmup-image-url <url>', 'warmup image URL') .option('--base-pv <count>', 'base page views', 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); const playerHandler = new player_handler_1.PlayerHandler(authConfig, serviceConfig); const updateOptions = { channelId: options.channelId, output: options.output }; if (options.watermarkEnabled !== undefined) { updateOptions.watermarkEnabled = options.watermarkEnabled; } if (options.watermarkUrl !== undefined) { updateOptions.watermarkUrl = options.watermarkUrl; } if (options.watermarkPosition !== undefined) { updateOptions.watermarkPosition = options.watermarkPosition; } if (options.watermarkOpacity !== undefined) { updateOptions.watermarkOpacity = options.watermarkOpacity; } if (options.warmupEnabled !== undefined) { updateOptions.warmupEnabled = options.warmupEnabled; } if (options.warmupImageUrl !== undefined) { updateOptions.warmupImageUrl = options.warmupImageUrl; } if (options.basePv !== undefined) { updateOptions.basePv = options.basePv; } await playerHandler.updateConfig(updateOptions); } 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); } }); updateCmd.addHelpText('after', ` Examples: # Update watermark settings $ polyv-live-cli player config update -c "3151318" --watermark-enabled Y --watermark-url "http://example.com/logo.png" --watermark-position br --watermark-opacity 0.8 # Update warmup settings $ polyv-live-cli player config update -c "3151318" --warmup-enabled Y --warmup-image-url "http://example.com/warmup.jpg" # Update base page views $ polyv-live-cli player config update -c "3151318" --base-pv 1000 # Combined update with JSON output $ polyv-live-cli player config update -c "3151318" --watermark-enabled Y --base-pv 1000 -o json Watermark Position: --watermark-position Watermark position on the player tl: Top-left tr: Top-right bl: Bottom-left br: Bottom-right (default) Watermark Opacity: --watermark-opacity Watermark opacity from 0 (transparent) to 1 (opaque) Y/N Values: --watermark-enabled Enable/disable watermark (Y or N) --warmup-enabled Enable/disable warmup image (Y or N) Output Formats: table Formatted output (default) json JSON format for programmatic use `); const warmupCmd = playerCmd.command('warmup').description('Manage player warmup settings'); warmupCmd.command('switch-update') .description('Update the warmup enabled switch') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .requiredOption('--warm-up-enabled <value>', 'warmup enabled (Y|N)', validateYNValue) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).updateWarmupSwitch(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); const skinCmd = playerCmd.command('skin').description('Manage V4 player skin settings'); skinCmd.command('update-batch') .description('Batch update channel player skin') .requiredOption('--channel-ids <ids>', 'channel IDs, comma-separated, max 500', api_command_1.parseStringList) .requiredOption('--skin <skin>', 'skin: black|red|blue|white|green|golden') .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).updateSkinBatch(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); const antiRecordCmd = playerCmd.command('anti-record').description('Manage anti-record settings'); antiRecordCmd.command('get') .description('Get anti-record settings') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).getAntiRecord(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); antiRecordCmd.command('update') .description('Update anti-record settings') .requiredOption('-c, --channel-id <channelId>', 'channel ID (required)') .requiredOption('--anti-record-type <type>', 'anti-record type (marquee|watermark, required)', validateAntiRecordType) .requiredOption('--model-type <type>', 'model type (fixed|nickname|diyurl, required)', validateAntiRecordModel) .requiredOption('--content <content>', 'content text or DIY URL (required)') .requiredOption('--font-size <size>', 'font size (required)', parseFontSize) .option('--opacity <opacity>', 'opacity 0-100', api_command_1.parseNonNegativeNumber) .option('--font-color <color>', 'font color, hex format') .option('--show-mode <mode>', 'show mode (roll|flicker)', validateShowMode) .option('--double-enabled <value>', 'double enabled (Y|N)', validateYNValue) .option('--auto-zoom-enabled <value>', 'auto zoom enabled (Y|N)', validateYNValue) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).updateAntiRecord(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); playerCmd.command('marquee-url') .description('Set marquee URL restriction') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .requiredOption('--marquee-restrict <value>', 'marquee restrict (Y|N)', validateYNValue) .option('--url <url>', 'marquee URL') .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).setMarqueeUrl(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); const advertCmd = playerCmd.command('advert').description('Manage player adverts'); advertCmd.command('head-update') .description('Update player head advert') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .requiredOption('--head-advert-type <type>', 'head advert type (NONE|IMAGE|FLV)', validateHeadAdvertType) .option('--head-advert-media-url <url>', 'head advert media URL (image or video address)') .option('--head-advert-image <url>', 'deprecated: use --head-advert-media-url') .option('--head-advert-flv <url>', 'deprecated: use --head-advert-media-url') .option('--head-advert-href <url>', 'head advert click URL') .option('--head-advert-duration <seconds>', 'duration seconds', api_command_1.parsePositiveInteger) .option('--head-advert-width <width>', 'advert width', api_command_1.parsePositiveInteger) .option('--head-advert-height <height>', 'advert height', api_command_1.parsePositiveInteger) .option('--enabled <value>', 'enabled (Y|N)', validateYNValue) .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).updateHeadAdvert({ ...options, headAdvertMediaUrl: options.headAdvertMediaUrl || options.headAdvertImage || options.headAdvertFlv, }); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); advertCmd.command('stop-update') .description('Update player stop advert') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .option('--enabled <value>', 'enabled (Y|N)', validateYNValue) .option('--stop-advert-image <url>', 'stop advert image URL') .option('--stop-advert-href <url>', 'stop advert click URL') .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).updateStopAdvert(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); playerCmd.command('logo-update') .description('Update player logo settings') .requiredOption('-c, --channel-id <channelId>', 'channel ID') .requiredOption('--logo-image <url>', 'logo image URL') .option('--logo-opacity <opacity>', 'logo opacity', api_command_1.parseNonNegativeNumber) .option('--logo-position <position>', 'logo position (tl|tr|bl|br)', validateWatermarkPosition) .option('--logo-href <url>', 'logo click URL') .option('-f, --force', 'skip confirmation prompt') .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).updateLogo(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); playerCmd.command('watch-feedback-list') .description('List watch feedback records') .option('-c, --channel-id <channelId>', 'channel ID') .option('--page-number <page>', 'page number', api_command_1.parsePositiveInteger) .option('--page-size <size>', 'page size', api_command_1.parsePositiveInteger) .option('-o, --output <format>', 'output format (table|json)', validateOutputFormat, 'table') .action(async (options) => { try { const { authConfig, serviceConfig } = await loadAuthAndServiceConfig(program.opts()); await new player_handler_1.PlayerHandler(authConfig, serviceConfig).listWatchFeedback(options); } catch (error) { (0, errors_1.logError)(error instanceof Error ? error : new Error(String(error))); process.exit(1); } }); } //# sourceMappingURL=player.commands.js.map