generated from lavaclient/discordjs-example
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
562 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { CommonParams2, type EchoParams } from './types' | ||
|
||
export async function Echo({ send, msg }: EchoParams): Promise<void> { | ||
await send(msg) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { type CommonParams2Validated } from './types' | ||
import { TextChannel, type VoiceBasedChannel, VoiceChannel } from 'discord.js' | ||
import { type Node, type Player } from 'lavaclient' | ||
import { type Bot, type MessageChannel } from '@lib' | ||
|
||
export const createPlayer = async ({ | ||
userTextChannel, | ||
userVc, | ||
bot | ||
}: { | ||
userTextChannel: MessageChannel | ||
userVc: VoiceBasedChannel | ||
bot: Bot | ||
}): Promise<Player<Node>> => { | ||
const player = bot.music.createPlayer(userVc.guild.id) | ||
player.queue.channel = userTextChannel | ||
player.connect(userVc.id) | ||
return player | ||
} | ||
|
||
export async function Join({ userVc, bot, userTextChannel, send }: CommonParams2Validated): Promise<void> { | ||
await createPlayer({ userVc, bot, userTextChannel }) | ||
await send(`Joined ${userVc.toString()}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { type CommonParams2Validated } from './types' | ||
|
||
export async function Leave({ bot, player }: CommonParams2Validated): Promise<void> { | ||
player.disconnect() | ||
await bot.music.destroyPlayer(player.guildId) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { CommonParams2Validated, type NightcoreParams } from './types' | ||
|
||
export async function Nightcore({ | ||
send, | ||
speed: speedParam, | ||
pitch: pitchParam, | ||
rate: rateParam, | ||
player | ||
}: NightcoreParams): Promise<void> { | ||
const shouldEnable = !player.nightcore || speedParam != null || pitchParam != null || rateParam != null | ||
if (!shouldEnable) { | ||
await send("Nightcoren't") | ||
player.nightcore = false | ||
player.filters.timescale = undefined | ||
} else { | ||
player.nightcore = true | ||
const speed = speedParam ?? 1.125 | ||
const pitch = pitchParam ?? 1.125 | ||
const rate = rateParam ?? 1 | ||
await send(`Nightcore enabled with speed ${speed}, pitch ${pitch}, and rate ${rate}`) | ||
player.filters.timescale = { speed, pitch, rate } | ||
} | ||
|
||
await player.setFilters() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { millisecondsToString } from '@lib' | ||
import { type CommonParams2Validated } from './types' | ||
|
||
export async function Pause({ sendIfError, send, player }: CommonParams2Validated): Promise<void> { | ||
const current = player.queue.current | ||
if (current == null) { | ||
await sendIfError("I'm not playing anything bozo") | ||
return | ||
} | ||
await player.pause(true) | ||
const positionHumanReadable = millisecondsToString(player.position ?? 0) | ||
await send(`Paused ${current.title} at ${positionHumanReadable}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { type CommonParams2 } from './types' | ||
|
||
export async function Ping2({ send, bot }: CommonParams2): Promise<void> { | ||
await send(`Pong! **Heartbeat:** *${Math.round(bot.ws.ping)}ms*`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { SpotifyItemType } from '@lavaclient/spotify' | ||
|
||
import type { Addable } from '@lavaclient/queue' | ||
import { type PlayParams } from './types' | ||
|
||
export const Play = | ||
({ next }: { next: boolean }) => | ||
async ({ | ||
userVc, | ||
send, | ||
sendIfError, | ||
userTextChannel, | ||
bot, | ||
query, | ||
guild, | ||
player, | ||
requesterId | ||
}: PlayParams): Promise<void> => { | ||
let tracks: Addable[] = [] | ||
let msg = '' | ||
if (query !== '') { | ||
if (bot.music.spotify.isSpotifyUrl(query)) { | ||
const item = await bot.music.spotify.load(query) | ||
switch (item?.type) { | ||
case SpotifyItemType.Track: { | ||
const track = await item.resolveYoutubeTrack() | ||
tracks = [track] | ||
msg = `Queued track [**${item.name}**](${query}).` | ||
break | ||
} | ||
case SpotifyItemType.Artist: { | ||
tracks = await item.resolveYoutubeTracks() | ||
msg = `Queued the **Top ${tracks.length} tracks** for [**${item.name}**](${query}).` | ||
break | ||
} | ||
case SpotifyItemType.Album: | ||
case SpotifyItemType.Playlist: { | ||
tracks = await item.resolveYoutubeTracks() | ||
msg = `Queued **${tracks.length} tracks** from ${SpotifyItemType[item.type].toLowerCase()} [**${ | ||
item.name | ||
}**](${query}).` | ||
break | ||
} | ||
default: { | ||
await sendIfError("Sorry, couldn't find anything :/") | ||
return | ||
} | ||
} | ||
} else { | ||
const results = await bot.music.rest.loadTracks(/^https?:\/\//.test(query) ? query : `ytsearch:${query}`) | ||
|
||
switch (results.loadType) { | ||
case 'LOAD_FAILED': | ||
case 'NO_MATCHES': { | ||
await sendIfError('uh oh something went wrong') | ||
return | ||
} | ||
case 'PLAYLIST_LOADED': { | ||
tracks = results.tracks | ||
msg = `Queued playlist [**${results.playlistInfo.name}**](${query}), it has a total of **${tracks.length}** tracks.` | ||
break | ||
} | ||
case 'TRACK_LOADED': | ||
case 'SEARCH_RESULT': { | ||
const [track] = results.tracks | ||
tracks = [track] | ||
msg = `Queued [**${track.info.title}**](${track.info.uri})` | ||
break | ||
} | ||
} | ||
} | ||
} | ||
/* create a player and/or join the member's userVc. */ | ||
if (!player?.connected) { | ||
player ??= bot.music.createPlayer(guild.id) | ||
player.queue.channel = userTextChannel | ||
player.connect(userVc.id, { deafened: true }) | ||
} | ||
|
||
/* reply with the queued message. */ | ||
const started = player.playing || player.paused | ||
if (msg !== '') { | ||
// TODO: make it better (this checks if play was used to unpause) | ||
await send(msg, next != null ? 'At the top of the queue.' : '', started) | ||
player.queue.add(tracks, { requester: requesterId, next }) | ||
} else { | ||
await send('Resumed playback') | ||
await player.pause(false) | ||
} | ||
/* do queue tings. */ | ||
if (!started) { | ||
await player.queue.start() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { type CommonParams2Validated } from './types' | ||
|
||
const formatIndex = (index: number, size: number): string => | ||
(index + 1).toString().padStart(size.toString().length, '0') | ||
|
||
export async function Queue({ player, send, guild }: CommonParams2Validated): Promise<void> { | ||
const size = player.queue.tracks.length | ||
const str = player.queue.tracks | ||
.map( | ||
(t, idx) => | ||
`\`#${formatIndex(idx, size)}\` [**${t.title}**](${t.uri}) ${ | ||
t.requester !== undefined ? `<@${t.requester}>` : '' | ||
}` | ||
) | ||
.join('\n') | ||
|
||
await send(`Queue for **${guild.name}**`, str) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { type RemoveParams } from './types' | ||
|
||
export async function Remove({ player, sendIfError, send, index }: RemoveParams): Promise<void> { | ||
const removedTrack = player.queue.remove(index - 1) | ||
if (removedTrack == null) { | ||
await sendIfError('No tracks were removed.') | ||
return | ||
} | ||
|
||
await send(`The track [**${removedTrack.title}**](${removedTrack.uri}) was removed.`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { millisecondsToString } from '@lib' | ||
import { type CommonParams2Validated } from './types' | ||
|
||
export async function Resume({ player, send, current }: CommonParams2Validated): Promise<void> { | ||
await player.pause(false) | ||
const positionHumanReadable = millisecondsToString(player.position ?? 0) | ||
await send(`Resumed ${current?.title} at ${positionHumanReadable}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { millisecondsToString, stringToMilliseconds } from '@lib' | ||
|
||
import { type SeekParams } from './types' | ||
|
||
export const Seek = | ||
({ add = false, multiplier = 1 }: { add?: boolean, multiplier?: 1 | -1 }) => | ||
async ({ current, sendIfError, send, player, position }: SeekParams): Promise<void> => { | ||
const positionNumerised = (add ? player.position ?? 0 : 0) + multiplier * stringToMilliseconds(position) | ||
if (isNaN(positionNumerised)) { | ||
await sendIfError('Position must be a number') | ||
return | ||
} | ||
await player.seek(positionNumerised) | ||
|
||
const positionHumanReadable = millisecondsToString(positionNumerised) | ||
|
||
await send(`Sought ${current?.title} to ${positionHumanReadable}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { type CommonParams2Validated } from './types' | ||
|
||
export async function Skip({ player, send, current }: CommonParams2Validated): Promise<void> { | ||
await player.queue.skip() | ||
await player.queue.start() | ||
await send(`Skipped ${current?.title}`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { type Guild, type VoiceBasedChannel } from 'discord.js' | ||
import { type Bot, type MessageChannel } from '@lib' | ||
import { z } from 'zod' | ||
import { type Node, type Player } from 'lavaclient' | ||
import { type Song } from '@lavaclient/queue' | ||
|
||
const numericCore = z.string().regex(/^[+-]?(\d*[.])?\d+$/, { message: 'not a number' }) | ||
const intigerishCore = z.string().regex(/^\d+$/, { message: 'not an int' }) | ||
export const numeric = () => numericCore.transform(Number) | ||
export const intigerish = () => intigerishCore.transform((x) => parseInt(x, 10)) | ||
|
||
export const optionalNumeric = () => numericCore.optional().transform((x) => (x == null ? undefined : Number(x))) | ||
|
||
type SendFnType = (text: string, ...rest: any[]) => Promise<void> | ||
|
||
export interface CommonParams2 { | ||
userVc: VoiceBasedChannel | null | undefined | ||
userTextChannel: MessageChannel | ||
bot: Bot | ||
guild: Guild | null | undefined | ||
send: SendFnType | ||
sendIfError: SendFnType | ||
player: Player<Node> | undefined | ||
requesterId: string | ||
current: Song | null | undefined | ||
} | ||
|
||
export type CommonParams2Validated = CommonParams2 & { | ||
userVc: VoiceBasedChannel | ||
guild: Guild | ||
player: Player<Node> | ||
} | ||
|
||
export type TextChannelCheckParams = Omit<CommonParams2, 'send' | 'sendIfError'> | ||
|
||
export const EchoParamsSchema = z.object({ | ||
msg: z.string().min(1) | ||
}) | ||
|
||
export type EchoParams = z.infer<typeof EchoParamsSchema> & CommonParams2Validated | ||
|
||
export const NightcoreParamsSchema = z.object({ | ||
speed: optionalNumeric(), | ||
pitch: optionalNumeric(), | ||
rate: optionalNumeric() | ||
}) | ||
|
||
export type NightcoreParams = z.infer<typeof NightcoreParamsSchema> & CommonParams2Validated | ||
|
||
export const PlayParamsSchema = z.object({ | ||
query: z.string().min(1) | ||
}) | ||
|
||
export type PlayParams = z.infer<typeof PlayParamsSchema> & CommonParams2Validated | ||
|
||
export const RemoveParamsSchema = z.object({ | ||
index: intigerish() | ||
}) | ||
|
||
export type RemoveParams = z.infer<typeof RemoveParamsSchema> & CommonParams2Validated | ||
|
||
export const SeekParamsSchema = z.object({ | ||
position: z.string().min(1) | ||
}) | ||
|
||
export type SeekParams = z.infer<typeof SeekParamsSchema> & CommonParams2Validated |
Oops, something went wrong.