polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
416 lines • 14.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChannelDetailsPopup = void 0;
const blessed_1 = __importDefault(require("blessed"));
class ChannelDetailsPopup {
constructor(config) {
this.channel = null;
this.isVisible = false;
this.scrollOffset = 0;
this.maxScrollOffset = 0;
this.config = config;
this.screen = config.screen;
this.eventBus = config.eventBus;
this.createPopup();
this.setupEventListeners();
}
createPopup() {
this.popup = blessed_1.default.box({
parent: this.screen,
top: 'center',
left: 'center',
width: '90%',
height: '85%',
border: { type: 'line' },
style: {
fg: 'white',
bg: 'black',
border: { fg: 'cyan' }
},
shadow: true,
keys: true,
vi: true,
mouse: true,
scrollable: false,
hidden: true,
label: ' Channel Details ',
tags: true
});
this.headerBox = blessed_1.default.box({
parent: this.popup,
top: 0,
left: 0,
width: '100%',
height: 4,
border: { type: 'line' },
style: {
fg: 'cyan',
bg: 'black',
border: { fg: 'gray' }
},
tags: true
});
this.scrollBox = blessed_1.default.box({
parent: this.popup,
top: 4,
left: 0,
width: '100%',
height: 'shrink',
bottom: 2,
scrollable: true,
alwaysScroll: true,
keys: true,
vi: true,
mouse: true,
scrollbar: {
ch: ' ',
track: {
bg: 'gray'
},
style: {
inverse: true
}
},
style: {
fg: 'white',
bg: 'black'
},
tags: true
});
this.footerBox = blessed_1.default.box({
parent: this.popup,
bottom: 0,
left: 0,
width: '100%',
height: 2,
border: { type: 'line' },
style: {
fg: 'gray',
bg: 'black',
border: { fg: 'gray' }
},
content: this.getFooterContent(),
tags: true
});
this.setupKeyBindings();
}
setupKeyBindings() {
this.popup.key(['escape', 'q'], () => {
this.hide();
});
this.popup.key(['r', 'R', 'f5'], () => {
this.refreshChannel();
});
this.popup.key(['up', 'k'], () => {
this.scroll(-1);
});
this.popup.key(['down', 'j'], () => {
this.scroll(1);
});
this.popup.key(['pageup'], () => {
this.scroll(-10);
});
this.popup.key(['pagedown'], () => {
this.scroll(10);
});
this.popup.key(['home'], () => {
this.scrollToTop();
});
this.popup.key(['end'], () => {
this.scrollToBottom();
});
this.popup.key(['ctrl+c'], () => {
this.copyChannelInfo();
});
}
setupEventListeners() {
this.eventBus.on('channel:updated', (data) => {
if (this.isVisible && this.channel && data.channelId === this.channel.channelId) {
this.updateChannel(data.channel);
}
});
this.eventBus.on('dashboard:refresh', () => {
if (this.isVisible) {
this.refreshChannel();
}
});
}
show(channel) {
this.channel = channel;
this.isVisible = true;
this.scrollOffset = 0;
this.updateContent();
this.popup.show();
this.popup.focus();
this.screen.render();
if (this.config.refreshInterval > 0) {
this.startAutoRefresh();
}
this.eventBus.emit('channelDetails:shown', {
channelId: channel.channelId,
timestamp: new Date()
});
}
hide() {
this.isVisible = false;
this.popup.hide();
this.screen.render();
this.stopAutoRefresh();
if (this.channel) {
this.eventBus.emit('channelDetails:hidden', {
channelId: this.channel.channelId,
timestamp: new Date()
});
}
this.channel = null;
}
updateChannel(channel) {
this.channel = channel;
if (this.isVisible) {
this.updateContent();
this.screen.render();
}
}
updateContent() {
if (!this.channel)
return;
const headerContent = this.getHeaderContent();
this.headerBox.setContent(headerContent);
const detailsContent = this.getDetailsContent();
this.scrollBox.setContent(detailsContent);
this.updateFooter();
const contentLines = detailsContent.split('\n').length;
const visibleLines = this.scrollBox.height - 2;
this.maxScrollOffset = Math.max(0, contentLines - visibleLines);
}
getHeaderContent() {
if (!this.channel)
return '';
const statusColors = this.getStatusColors(this.channel.status);
const statusIcon = this.config.showColors ? statusColors.icon : '';
const statusText = `${statusIcon} ${this.channel.statusText}`;
return `{center}{bold}${this.channel.name}{/bold}{/center}\n` +
`{center}Channel ID: {cyan-fg}${this.channel.channelId}{/cyan-fg} | Status: {${statusColors.fg}-fg}${statusText}{/${statusColors.fg}-fg}{/center}`;
}
getDetailsContent() {
if (!this.channel)
return '';
const sections = [
this.getBasicInfoSection(),
this.getStatisticsSection(),
this.getTimingSection(),
this.getPublisherSection(),
this.getStatusHistorySection()
];
return sections.join('\n\n');
}
getBasicInfoSection() {
if (!this.channel)
return '';
const statusColors = this.getStatusColors(this.channel.status);
const statusDisplay = this.config.showColors ?
`{${statusColors.fg}-fg}${statusColors.icon} ${this.channel.statusText}{/${statusColors.fg}-fg}` :
this.channel.statusText;
return `{yellow-fg}{bold}Basic Information{/bold}{/yellow-fg}\n` +
`├─ Channel ID: {cyan-fg}${this.channel.channelId}{/cyan-fg}\n` +
`├─ Name: {white-fg}${this.channel.name}{/white-fg}\n` +
`├─ Status: ${statusDisplay}\n` +
`├─ Publisher: {green-fg}${this.channel.publisher}{/green-fg}\n` +
`└─ Selected: {magenta-fg}${this.channel.selected ? 'Yes' : 'No'}{/magenta-fg}`;
}
getStatisticsSection() {
if (!this.channel)
return '';
const viewerPercentage = this.channel.maxViewer > 0 ?
((this.channel.viewerCount / this.channel.maxViewer) * 100).toFixed(1) + '%' :
'N/A';
return `{yellow-fg}{bold}Statistics{/bold}{/yellow-fg}\n` +
`├─ Current Viewers: {cyan-fg}${this.channel.viewerCount.toLocaleString()}{/cyan-fg}\n` +
`├─ Max Viewers: {cyan-fg}${this.channel.maxViewer.toLocaleString()}{/cyan-fg}\n` +
`└─ Utilization: {magenta-fg}${viewerPercentage}{/magenta-fg}`;
}
getTimingSection() {
if (!this.channel)
return '';
const formatTime = (timestamp) => {
if (timestamp === 0)
return 'Not set';
return new Date(timestamp).toLocaleString();
};
const getDuration = (start, end) => {
if (start === 0 || end === 0)
return 'N/A';
const duration = end - start;
const hours = Math.floor(duration / (1000 * 60 * 60));
const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60));
return `${hours}h ${minutes}m`;
};
return `{yellow-fg}{bold}Timing Information{/bold}{/yellow-fg}\n` +
`├─ Created: {cyan-fg}${formatTime(this.channel.createdTime)}{/cyan-fg}\n` +
`├─ Start Time: {green-fg}${formatTime(this.channel.startTime)}{/green-fg}\n` +
`├─ End Time: {red-fg}${formatTime(this.channel.endTime)}{/red-fg}\n` +
`└─ Duration: {magenta-fg}${getDuration(this.channel.startTime, this.channel.endTime)}{/magenta-fg}`;
}
getPublisherSection() {
if (!this.channel)
return '';
return `{yellow-fg}{bold}Publisher Information{/bold}{/yellow-fg}\n` +
`├─ Publisher: {green-fg}${this.channel.publisher}{/green-fg}\n` +
`└─ Publishing Status: {cyan-fg}${this.getPublishingStatus()}{/cyan-fg}`;
}
getStatusHistorySection() {
return `{yellow-fg}{bold}Recent Activity{/bold}{/yellow-fg}\n` +
`├─ Last Updated: {cyan-fg}${new Date().toLocaleString()}{/cyan-fg}\n` +
`├─ Status Changes: {green-fg}Available in full version{/green-fg}\n` +
`└─ Performance Metrics: {magenta-fg}Available in full version{/magenta-fg}`;
}
getPublishingStatus() {
if (!this.channel)
return 'Unknown';
switch (this.channel.status) {
case 'live':
return 'Broadcasting Live';
case 'waiting':
return 'Waiting to Start';
case 'end':
return 'Broadcast Ended';
case 'banpush':
return 'Banned from Broadcasting';
case 'playback':
return 'Playing Back';
case 'unStart':
return 'Not Started';
default:
return 'Unknown Status';
}
}
getFooterContent() {
return `{center}{gray-fg}ESC/q: Close | r/F5: Refresh | ↑↓: Scroll | Home/End: Top/Bottom | Ctrl+C: Copy{/gray-fg}{/center}`;
}
updateFooter() {
this.footerBox.setContent(this.getFooterContent());
}
getStatusColors(status) {
const colorMap = {
'live': { fg: 'green', icon: '●' },
'waiting': { fg: 'yellow', icon: '◯' },
'end': { fg: 'gray', icon: '◦' },
'banpush': { fg: 'red', icon: '✖' },
'playback': { fg: 'blue', icon: '▶' },
'unStart': { fg: 'gray', icon: '◦' }
};
return colorMap[status] || { fg: 'white', icon: '?' };
}
scroll(amount) {
this.scrollOffset = Math.max(0, Math.min(this.maxScrollOffset, this.scrollOffset + amount));
this.scrollBox.scrollTo(this.scrollOffset);
this.screen.render();
}
scrollToTop() {
this.scrollOffset = 0;
this.scrollBox.scrollTo(0);
this.screen.render();
}
scrollToBottom() {
this.scrollOffset = this.maxScrollOffset;
this.scrollBox.scrollTo(this.maxScrollOffset);
this.screen.render();
}
copyChannelInfo() {
if (!this.channel)
return;
const info = `Channel: ${this.channel.name}\n` +
`ID: ${this.channel.channelId}\n` +
`Status: ${this.channel.statusText}\n` +
`Publisher: ${this.channel.publisher}\n` +
`Viewers: ${this.channel.viewerCount}/${this.channel.maxViewer}`;
this.eventBus.emit('channelDetails:copied', {
channelId: this.channel.channelId,
info,
timestamp: new Date()
});
this.showNotification('Channel info copied to clipboard!');
}
showNotification(message) {
const notification = blessed_1.default.box({
parent: this.screen,
top: 'center',
left: 'center',
width: 'shrink',
height: 'shrink',
content: ` ${message} `,
style: {
fg: 'white',
bg: 'green'
},
padding: {
left: 2,
right: 2,
top: 1,
bottom: 1
}
});
this.screen.render();
if (this.notificationTimer) {
clearTimeout(this.notificationTimer);
}
this.notificationTimer = setTimeout(() => {
this.screen.remove(notification);
this.screen.render();
this.notificationTimer = undefined;
}, 2000);
}
refreshChannel() {
if (!this.channel)
return;
this.eventBus.emit('channel:requestRefresh', {
channelId: this.channel.channelId,
timestamp: new Date()
});
}
startAutoRefresh() {
this.stopAutoRefresh();
if (this.config.refreshInterval > 0) {
this.refreshTimer = setInterval(() => {
this.refreshChannel();
}, this.config.refreshInterval);
}
}
stopAutoRefresh() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
this.refreshTimer = undefined;
}
if (this.notificationTimer) {
clearTimeout(this.notificationTimer);
this.notificationTimer = undefined;
}
}
isShowing() {
return this.isVisible;
}
getCurrentChannel() {
return this.channel;
}
destroy() {
this.stopAutoRefresh();
this.hide();
if (this.popup && this.screen) {
try {
if (typeof this.screen.remove === 'function') {
this.screen.remove(this.popup);
}
}
catch (error) {
}
}
this.eventBus.emit('channelDetails:destroyed', {
timestamp: new Date()
});
}
}
exports.ChannelDetailsPopup = ChannelDetailsPopup;
//# sourceMappingURL=channel-details.popup.js.map