npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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 ansi code 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 frictionpeerDependencies on discord.js, no extra installs

Install

npm install megs-discord-progress

Requires 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 | null

API — 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 | null

ANSI 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