megs-discord-progress
v1.0.0
Published
Beautiful live-updating progress bars for Discord bots — music players, downloads, tasks. Supports embeds and ANSI colored code blocks.
Maintainers
Readme
megs-discord-progress
Beautiful live-updating progress bars for Discord bots — music players, downloads, batch tasks. Supports embed and ANSI colored code block styles.
Most Discord music bots just show text like "Now playing: X". This package renders smooth, sub-character precision progress bars with ANSI colors, automatic rate-limit-safe message editing, and both embed and code-block styles. Made to pair with megs-ascii-progress.
Built by megs · megsnaf
Features
- Music bar — Now-playing with live-updating progress, play/pause/seek support
- Task bar — Generic progress bar for downloads, imports, batch jobs
- Two styles — Discord embed card OR ANSI code block (both supported, your choice)
- ANSI colored bars — Uses Discord's
ansicode block syntax for real colors - Sub-character smoothness — 8× finer resolution with
▏▎▍▌▋▊▉█ - Rate-limit safe — 2.5s minimum update interval enforced
- Auto-cleanup — Handles deleted messages, channel errors gracefully
- TypeScript-first with full type definitions
- Zero friction —
peerDependencieson discord.js, no extra installs
Install
npm install megs-discord-progressRequires discord.js@^14 in your project.
Quick Start — Music Bar
const { MegsMusicBar } = require('megs-discord-progress');
const bar = new MegsMusicBar({
channel: message.channel,
song: {
title: 'Kuzu Kuzu',
author: 'Tarkan',
duration: 222000,
url: 'https://youtube.com/...',
thumbnail: 'https://...',
requestedBy: message.author.tag,
},
style: 'embed',
updateInterval: 5000,
color: 'green',
emptyColor: 'gray',
width: 20,
});
await bar.start();
player.on('pause', () => bar.pause());
player.on('resume', () => bar.resume());
player.on('end', () => bar.stop());Renders as a Discord embed that updates every 5 seconds with a live progress bar, time stamps, thumbnail, and author info.
Quick Start — Task Bar
const { MegsTaskBar } = require('megs-discord-progress');
const bar = new MegsTaskBar({
channel: message.channel,
total: 1000,
label: 'Importing users',
style: 'embed',
showFraction: true,
showEta: true,
showSpeed: true,
color: 'cyan',
});
await bar.start();
for (const user of users) {
await importUser(user);
bar.increment();
}
await bar.stop('Import complete!');Styles
style: 'embed' (default)
Rich Discord embed with title, description, thumbnail, and fields. Best for user-facing commands like !play.
style: 'code'
ANSI colored code block. Best for admin/debug commands or when you want a compact look. Uses Discord's ansi code block syntax for real color rendering.
API — MegsMusicBar
new MegsMusicBar(options: MegsMusicBarOptions)Options
| Option | Type | Default | Description |
| -------------------- | -------------------------- | -------------- | ------------------------------------------------- |
| channel | TextBasedChannel | required | Channel to send message in |
| song | MegsSong | required | Song info |
| style | 'embed' \| 'code' | 'embed' | Rendering style |
| updateInterval | number | 5000 | Edit interval in ms (min 2500) |
| showTimestamps | boolean | true | Show 1:24 / 3:42 |
| width | number | 20 | Bar width in characters |
| filledChar | string | █ | Character for filled portion |
| emptyChar | string | ░ | Character for empty portion |
| color | MegsAnsiColor | — | Filled color (code style only) |
| emptyColor | MegsAnsiColor | 'gray' | Empty color (code style only) |
| embedColor | number | 0x5865f2 | Embed color (embed style only) |
| title | string | '🎵 Now Playing' | Embed title |
| footer | string | — | Embed footer |
| getCurrentPosition | () => number | — | Custom position getter (integrate with player) |
| onStop | () => void | — | Called when bar stops |
MegsSong
{
title: string;
url?: string;
duration: number; // in milliseconds
thumbnail?: string;
author?: string;
requestedBy?: string;
}Methods
await bar.start() // Send the initial message
bar.pause() // Pause (icon becomes ⏸️)
bar.resume() // Resume playback
bar.seek(positionMs: number) // Jump to a position
bar.updateSong(song: MegsSong) // Switch to next song (for queues)
await bar.stop() // Finalize the message (shows ⏹️)
await bar.destroy() // Delete the message entirely
bar.getPosition(): number // Current position in ms
bar.getState(): 'playing' | 'paused' | 'stopped'
bar.getMessage(): Message | nullAPI — MegsTaskBar
new MegsTaskBar(options: MegsTaskBarOptions)Options
| Option | Type | Default | Description |
| ---------------- | ------------------- | ------------------ | ------------------------------------ |
| channel | TextBasedChannel | required | Channel to send message in |
| total | number | required | Max value |
| label | string | 'Processing' | Task label |
| style | 'embed' \| 'code' | 'embed' | Rendering style |
| updateInterval | number | 3000 | Edit interval in ms (min 2500) |
| showPercent | boolean | true | Show 45% |
| showFraction | boolean | false | Show 450/1000 |
| showEta | boolean | true | Show ETA: 00:42 |
| showSpeed | boolean | false | Show 1.2 MB/s or 24/s |
| width | number | 20 | Bar width |
| color | MegsAnsiColor | — | Filled color (code style) |
| embedColor | number | 0x5865f2 | Embed color |
| title | string | '⚙️ Task in progress' | Embed title |
| description | string | — | Embed description |
| onComplete | () => void | — | Called on completion |
Methods
await bar.start(initialValue?)
bar.update(value: number)
bar.increment(amount?: number)
bar.setLabel(label: string)
bar.setTotal(total: number)
bar.bytesMode(enabled?: boolean) // Format as bytes (1.2MB)
await bar.stop(finalMessage?)
await bar.destroy()
bar.getPercent(): number
bar.getMessage(): Message | nullANSI Colors (for style: 'code')
Discord's ansi code block supports these colors: gray, red, green, yellow, blue, pink, cyan, white.
{ style: 'code', color: 'green', emptyColor: 'gray' }Rate Limit Safety
Discord rate-limits message edits to roughly 5 per 5 seconds per channel. This package enforces a minimum updateInterval of 2500ms to stay well under that limit. Don't try to override it — you'll just get 429s.
Integration Examples
With discord-player
const { useMainPlayer } = require('discord-player');
player.events.on('playerStart', (queue, track) => {
const bar = new MegsMusicBar({
channel: queue.metadata.channel,
song: {
title: track.title,
author: track.author,
duration: track.durationMS,
thumbnail: track.thumbnail,
requestedBy: track.requestedBy?.tag,
},
getCurrentPosition: () => queue.node.getTimestamp().current.value,
});
await bar.start();
queue.metadata.bar = bar;
});
player.events.on('playerPause', (queue) => queue.metadata.bar?.pause());
player.events.on('playerResume', (queue) => queue.metadata.bar?.resume());
player.events.on('emptyQueue', (queue) => queue.metadata.bar?.stop());With @discordjs/voice
const { createAudioPlayer, AudioPlayerStatus } = require('@discordjs/voice');
const player = createAudioPlayer();
const bar = new MegsMusicBar({ /* ... */ });
player.on(AudioPlayerStatus.Playing, () => bar.resume());
player.on(AudioPlayerStatus.Paused, () => bar.pause());
player.on(AudioPlayerStatus.Idle, () => bar.stop());
await bar.start();HTTP download with progress
const axios = require('axios');
const fs = require('fs');
const { data, headers } = await axios.get(url, { responseType: 'stream' });
const total = parseInt(headers['content-length'], 10);
const bar = new MegsTaskBar({
channel: message.channel,
total,
label: 'Downloading',
showSpeed: true,
showEta: true,
}).bytesMode(true);
await bar.start();
let received = 0;
data.on('data', (chunk) => {
received += chunk.length;
bar.update(received);
});
data.on('end', () => bar.stop('Download complete!'));
data.pipe(fs.createWriteStream('output.zip'));Compatibility
- Node.js 16.11+
- discord.js v14+ (peerDependency — install in your project)
License
MIT © megs
Companion Package
megs-ascii-progress— Terminal progress bars with the same sub-character smoothness
