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 🙏

© 2024 – Pkg Stats / Ryan Hefner

frost-music

v0.1.2

Published

A music package for discord

Downloads

3

Readme

Frost discord music package

Just another music package

Uses youtube to get audio

(Real docs soon)

Installing package

npm i frost-music@latest

Installing dependencies

Other dependencies

If you want to skip reading this and just install all of them at once (doesnt install ffmpeg)

npm i ytdl-core yt-stream @discordjs/voice @discordjs/opus sodium-native

Go to actual code


ffmpeg

ffmpeg is required for this package to work

You can download ffmpeg from here

Or if you would rather install it from npm you can run the following code

npm i ffmpeg-static

Youtube

  • ytdl-core - Download audio
  • yt-stream - Search youtube

yt-stream would have been used to download, but it sometimes drops the data

npm i ytdl-core yt-stream

Voice

This pacakge requires:

  • Discord.js voice wrapper @discordjs/voice
  • Opus encoding library @discordjs/opus (can be substituted for opusscript)
  • Encryption package sodium-native (can be substituted for libsodium-wrappers)
npm i @discordjs/voice @discordjs/opus sodium-native

Getting started

Create a basic bot

const {Client, GatewayIntentBits: Intents, Events} = require('discord.js');
const MusicManager = require('frost-music');

let prefix = '!';

const client = new Client({
	intents: [
		Intents.Guilds,
		Intents.GuildMessages,
		Intents.MessageContent,
		Intents.GuildVoiceStates
	]
});

Create the music manager

const Music = new MusicManager(client, {
	exludeBot: true, // Exlude bot accounts from member vc count
	deaf: true, // Make bot deafen
	errors: true, // Log errors
	volume: 100, // Set default volume (starts to distort over 100)
	maxVolume: 250, // Set maximum volume
	loop: false // Set default looping
});

Handle music events

// When song starts
Music.on(Music.Events.songStart, (data, player) => {
	player.data.channels.text.send(`Now playing: \`${data.song.title} by ${data.song.author}\``);
});

// When song is skipped
Music.on(Music.Events.songSkip, (data, player) => {
	player.data.channels.text.send(`Skipped \`${data.song.title} by ${data.song.author}\``);
});

// When song ends
Music.on(Music.Events.songEnd, (data, player) => {
	player.data.channels.text.send(`Song: \`${data.song.title} by ${data.song.author}\` has ended`);
});

// When song is added to queue
Music.on(Music.Events.queueAdd, (data, player) => {
	player.data.channels.text.send(`Added \`${data.song.title} by ${data.song.author}\` to the queue`);
});

// When song is removed from queue
Music.on(Music.Events.queueRemove, (data, player) => {
	player.data.channels.text.send(`Removed \`${data.song.title} by ${data.song.author}\` from queue`);
});

// When queue is cleared
Music.on(Music.Events.queueClear, (player) => {
	player.data.channels.text.send(`Queue cleared`);
});

// When queue is empty
Music.on(Music.Events.queueEnd, (player) => {
	player.data.channels.text.send(`Nothing left to play`);
});

// Get when loop is toggled
Music.on(Music.Events.loopToggled, (looping, player) => {
	player.data.channels.text.send(`Looping set to \`${looping}\``);
});

// Get when volume changes
Music.on(Music.Events.volumeChange, (volume, player) => {
	player.data.channels.text.send(`Volume set to \`${volume}\``);
});

// Get when player is paused
Music.on(Music.Events.paused, (player) => {
	player.data.channels.text.send(`Paused playback`);
});

// Get when player is unpaused
Music.on(Music.Events.unpaused, (player) => {
	player.data.channels.text.send(`Resumed playback`);
});

// Get when bot leaves
Music.on(Music.Events.leave, (player) => {
	player.data.channels.text.send(`Left`);
});

// When an error occours with the player
Music.on(Music.Events.error, (err, player) => {
	console.log(`Error: ${err}`);
});

Handle search

This is seperate because its big and optional

// Get search results (big one bc it also adds)
Music.on(Music.Events.searchResult, (results, msg, player) => {
	let list = [],
		size = results.data.length > 10? 10: results.data.length;
	for(let i = 0; i < size; i++){
		let result = results.data[i];
		list.push(`${i+1}. \`${result.title} by ${result.author}\``)
	}

	// Send results for user to see
	msg.channel.send(list.join('\n'))

	// Add collector to add song
	const collectorFilter = m => (m.author.id == msg.author.id);
	const collector = msg.channel.createMessageCollector({
		filter: collectorFilter,
		time: 15_000 // Give 15 seconds to choose
	});

	// Save if valid awnser has been given
	let recived = false;

	// Get messages
	collector.on('collect', m => {
		// Return if done, or not a number
		if(recived || !Number(m.content)) return;
		// Return if over 10 or less than 1
		if(Number(m.content) > 10 || Number(m.content) < 1) return;
		recived = true;
		
		player.addFromSearch(Number(m.content)-1, m.author.id)
	});

	// End of 15 seconds
	collector.on('end', () => {
		// See if recived
		if(recived) return;
		// Didnt get anything :(
		msg.channel.send('Didnt get a response on time')
	});
});

Auto leave when alone in channel

This is optional

// When user leaves voice
client.on(Events.VoiceStateUpdate, (oldState, newState) => {
	if (!oldState.channel && newState.channel) return;
	if (!Music.has(oldState.guild.id)) return;

	if (Music.membercount(oldState.guild.id) < 1) {
		Music.leave(oldState.guild.id);
	}
});

Handle commands

client.on(Events.MessageCreate, (msg) => {
	if (!msg.content.toLowerCase().startsWith(prefix)) return;
	let args = msg.content.slice(prefix.length).trim().split(/ +/g);
	let command = args.shift().toLowerCase();

	// Play song
	if (command == 'play') {
		// Check if message author is in voice channel
		if (!msg.member.voice.channel) return msg.channel.send("You must be in a voice");
		// Create the player for guild if there is none
		if (!Music.has(msg.guild.id)) Music.create(msg.guild, msg.member.voice.channel, msg.channel);
		let player = Music.get(msg.guild.id);

		// Add song with who it was requested by
		player.play(args.join(' '), msg.author.id);
	}

	// Search for song
	if(command == 'search'){
		// Check if message author is in voice channel
		if (!msg.member.voice.channel) return msg.channel.send("You must be in a voice");
		// Create the player for guild if there is none
		if (!Music.has(msg.guild.id)) Music.create(msg.guild, msg.member.voice.channel, msg.channel);
		let player = Music.get(msg.guild.id);
		
		player.search(args.join(' '), msg);
	}

	// Rest require player before use
	if(Music.has(msg.guild.id)){
		let player = Music.get(msg.guild.id);
		// Skip the current song
		if(command == 'skip') player.skipSong();
		// Pause the saong
		if(command == 'pause') player.pause();
		// Resume the song
		if(command == 'unpause') player.unpause();
		// Set volume of song
		if(command == 'volume') player.setVolume(args[0])
		// Loop current song
		if(command == 'loop') player.loop();
		// Leave channel and stopp all playback
		if(command == 'leave') player.leave();
		// Clear the queue
		if(command == 'clear') player.clearQueue();
		// Remove item from queue
		if(command == 'remove') player.removeFromQueue(arg[0])
	}
});

See when bot has come online

client.on(Events.ClientReady, () => {
	console.log(`Logged in as ${client.user.username}!`);
});

Make client login

client.login('token-here')

-- More platforms may come soon --