diff --git a/package.json b/package.json index d8ccef4..cf4f549 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "lib/**/*" ], "scripts": { - "test": "cd test && node index.js", + "test": "yarn build && cd test && node index.js", "build": "tsc", "format": "prettier --write \"src/**/*.ts\"", "lint": "tslint -p tsconfig.json" @@ -47,7 +47,7 @@ "@discordjs/opus": "^0.5.0", "@types/node": "^14.14.37", "@types/ws": "^7.4.1", - "discord.js": "discordjs/discord.js", + "discord.js": "^12.5.3", "prettier": "^2.2.1", "tslint": "^6.1.3", "tslint-config-prettier": "^1.18.0", diff --git a/src/Player.ts b/src/Player.ts index a3baab8..20597f3 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -1,11 +1,10 @@ -import YouTube from 'youtube-sr'; import { EventEmitter } from 'events'; import { Client, Collection, Snowflake, Collector, Message } from 'discord.js'; -import { PlayerOptions } from './types/types'; +import { PlayerOptions, QueueFilters } from './types/types'; import Util from './utils/Util'; import AudioFilters from './utils/AudioFilters'; -import Queue from './Structures/Queue'; -import Track from './Structures/Track'; +import { Queue } from './Structures/Queue'; +import { Track } from './Structures/Track'; import { PlayerErrorEventCodes, PlayerEvents } from './utils/Constants'; import PlayerError from './utils/PlayerError'; import ytdl from 'discord-ytdl-core'; @@ -17,7 +16,7 @@ import { Client as SoundCloudClient } from 'soundcloud-scraper'; const SoundCloud = new SoundCloudClient(); -export default class Player extends EventEmitter { +export class Player extends EventEmitter { public client!: Client; public options: PlayerOptions; public filters: typeof AudioFilters; @@ -53,6 +52,9 @@ export default class Player extends EventEmitter { * Player queues */ this.queues = new Collection(); + + this._resultsCollectors = new Collection(); + this._cooldownsTimeout = new Collection(); } static get AudioFilters() { @@ -146,7 +148,7 @@ export default class Player extends EventEmitter { }); } - async play(message: Message, query: string | Track, firstResult?: boolean) { + async play(message: Message, query: string | Track, firstResult?: boolean): Promise { if (!message) throw new PlayerError('Play function needs message'); if (!query) throw new PlayerError('Play function needs search query as a string or Player.Track object'); @@ -162,9 +164,9 @@ export default class Player extends EventEmitter { else { if (ytdl.validateURL(query)) { const info = await ytdl.getBasicInfo(query).catch(() => {}); - if (!info) return this.emit(PlayerEvents.NO_RESULTS, message, query); + if (!info) return void this.emit(PlayerEvents.NO_RESULTS, message, query); if (info.videoDetails.isLiveContent && !this.options.enableLive) - return this.emit( + return void this.emit( PlayerEvents.ERROR, PlayerErrorEventCodes.LIVE_VIDEO, message, @@ -208,6 +210,28 @@ export default class Player extends EventEmitter { return this.queues.find((g) => g.guildID === message.guild.id); } + setFilters(message: Message, newFilters: QueueFilters): Promise { + return new Promise((resolve) => { + const queue = this.queues.find((g) => g.guildID === message.guild.id); + if (!queue) + this.emit( + PlayerEvents.ERROR, + PlayerErrorEventCodes.NOT_PLAYING, + message, + new PlayerError('Not playing') + ); + + Object.keys(newFilters).forEach((filterName) => { + // @ts-ignore + queue.filters[filterName] = newFilters[filterName]; + }); + + this._playStream(queue, true).then(() => { + resolve(); + }); + }); + } + private _addTrackToQueue(message: Message, track: Track) { const queue = this.getQueue(message); if (!queue) @@ -246,7 +270,7 @@ export default class Player extends EventEmitter { queue.tracks.push(track); this.emit(PlayerEvents.QUEUE_CREATE, message, queue); resolve(queue); - // this._playTrack(queue, true) + this._playTrack(queue, true); }) .catch((err) => { this.queues.delete(message.guild.id); @@ -260,7 +284,7 @@ export default class Player extends EventEmitter { }); } - private async _playTrack(queue: Queue, firstPlay: boolean) { + private async _playTrack(queue: Queue, firstPlay: boolean): Promise { if (queue.stopped) return; if (queue.tracks.length === 1 && !queue.loopMode && !queue.repeatMode && !firstPlay) { @@ -275,10 +299,10 @@ export default class Player extends EventEmitter { this.queues.delete(queue.guildID); if (queue.stopped) { - return this.emit(PlayerEvents.MUSIC_STOP, queue.firstMessage); + return void this.emit(PlayerEvents.MUSIC_STOP, queue.firstMessage); } - return this.emit(PlayerEvents.QUEUE_END, queue.firstMessage, queue); + return void this.emit(PlayerEvents.QUEUE_END, queue.firstMessage, queue); } if (!queue.repeatMode && !firstPlay) { @@ -316,7 +340,7 @@ export default class Player extends EventEmitter { } }); - let encoderArgs: string[]; + let encoderArgs: string[] = []; if (encoderArgsFilters.length < 1) { encoderArgs = []; } else { @@ -386,3 +410,5 @@ export default class Player extends EventEmitter { }); } } + +export default Player; diff --git a/src/Structures/Queue.ts b/src/Structures/Queue.ts index 41a48ab..76294ed 100644 --- a/src/Structures/Queue.ts +++ b/src/Structures/Queue.ts @@ -1,11 +1,11 @@ import { Message, Snowflake, VoiceConnection } from 'discord.js'; import AudioFilters from '../utils/AudioFilters'; -import Player from '../Player'; +import { Player } from '../Player'; import { EventEmitter } from 'events'; -import Track from './Track'; +import { Track } from './Track'; import { QueueFilters } from '../types/types'; -export default class Queue extends EventEmitter { +export class Queue extends EventEmitter { public player!: Player; public guildID: Snowflake; public voiceConnection?: VoiceConnection; @@ -127,3 +127,5 @@ export default class Queue extends EventEmitter { return this.voiceConnection?.dispatcher?.streamTime + this.additionalStreamTime || 0; } } + +export default Queue; diff --git a/src/Structures/Track.ts b/src/Structures/Track.ts index b74bef0..c40b41d 100644 --- a/src/Structures/Track.ts +++ b/src/Structures/Track.ts @@ -1,8 +1,8 @@ -import Player from '../Player'; +import { Player } from '../Player'; import { User } from 'discord.js'; import { TrackData } from '../types/types'; -export default class Track { +export class Track { public player!: Player; public title!: string; public description!: string; @@ -67,3 +67,5 @@ export default class Track { return `${this.title} by ${this.author}`; } } + +export default Track; diff --git a/src/index.ts b/src/index.ts index e7420c2..1f75632 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -export * as AudioFilters from './utils/AudioFilters'; +export { AudioFilters } from './utils/AudioFilters'; export * as Constants from './utils/Constants'; -export * as Player from './Player'; -export * as Util from './utils/Util'; -export * as Track from './Structures/Track'; -export * as Queue from './Structures/Queue'; +export { Player } from './Player'; +export { Util } from './utils/Util'; +export { Track } from './Structures/Track'; +export { Queue } from './Structures/Queue'; export * from './types/types'; -export * as PlayerError from './utils/PlayerError'; +export { PlayerError } from './utils/PlayerError'; export { version } from '../package.json'; diff --git a/src/types/types.ts b/src/types/types.ts index 69c5214..192c826 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -13,35 +13,7 @@ export interface PlayerOptions { useSafeSearch?: boolean; } -export type FiltersName = - | 'bassboost' - | '8D' - | 'vaporwave' - | 'nightcore' - | 'phaser' - | 'tremolo' - | 'vibrato' - | 'reverse' - | 'treble' - | 'normalizer' - | 'surrounding' - | 'pulsator' - | 'subboost' - | 'karaoke' - | 'flanger' - | 'gate' - | 'haas' - | 'mcompand' - | 'mono' - | 'mstlr' - | 'mstrr' - | 'compressor' - | 'expander' - | 'softlimiter' - | 'chorus' - | 'chorus2d' - | 'chorus3d' - | 'fadein'; +export type FiltersName = keyof QueueFilters; export type TrackSource = 'soundcloud' | 'youtube' | 'arbitrary'; @@ -60,34 +32,34 @@ export interface TrackData { } export type QueueFilters = { - bassboost: boolean; - '8D': boolean; - vaporwave: boolean; - nightcore: boolean; - phaser: boolean; - tremolo: boolean; - vibrato: boolean; - reverse: boolean; - treble: boolean; - normalizer: boolean; - surrounding: boolean; - pulsator: boolean; - subboost: boolean; - karaoke: boolean; - flanger: boolean; - gate: boolean; - haas: boolean; - mcompand: boolean; - mono: boolean; - mstlr: boolean; - mstrr: boolean; - compressor: boolean; - expander: boolean; - softlimiter: boolean; - chorus: boolean; - chorus2d: boolean; - chorus3d: boolean; - fadein: boolean; + bassboost?: boolean; + '8D'?: boolean; + vaporwave?: boolean; + nightcore?: boolean; + phaser?: boolean; + tremolo?: boolean; + vibrato?: boolean; + reverse?: boolean; + treble?: boolean; + normalizer?: boolean; + surrounding?: boolean; + pulsator?: boolean; + subboost?: boolean; + karaoke?: boolean; + flanger?: boolean; + gate?: boolean; + haas?: boolean; + mcompand?: boolean; + mono?: boolean; + mstlr?: boolean; + mstrr?: boolean; + compressor?: boolean; + expander?: boolean; + softlimiter?: boolean; + chorus?: boolean; + chorus2d?: boolean; + chorus3d?: boolean; + fadein?: boolean; }; export type QueryType = diff --git a/src/utils/AudioFilters.ts b/src/utils/AudioFilters.ts index 736e300..4c1fa3f 100644 --- a/src/utils/AudioFilters.ts +++ b/src/utils/AudioFilters.ts @@ -55,3 +55,4 @@ const FilterList = { }; export default FilterList; +export { FilterList as AudioFilters }; diff --git a/src/utils/PlayerError.ts b/src/utils/PlayerError.ts index 32cd56a..c87e1f6 100644 --- a/src/utils/PlayerError.ts +++ b/src/utils/PlayerError.ts @@ -6,3 +6,5 @@ export default class PlayerError extends Error { Error.captureStackTrace(this); } } + +export { PlayerError }; diff --git a/src/utils/Util.ts b/src/utils/Util.ts index 3e7bb19..87517b8 100644 --- a/src/utils/Util.ts +++ b/src/utils/Util.ts @@ -1,7 +1,7 @@ import { PlayerOptions, QueryType } from '../types/types'; import { FFmpeg } from 'prism-media'; import YouTube from 'youtube-sr'; -import Track from '../Structures/Track'; +import { Track } from '../Structures/Track'; // @ts-ignore import { validateURL as SoundcloudValidateURL } from 'soundcloud-scraper'; @@ -12,7 +12,7 @@ const vimeoRegex = /(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/ const facebookRegex = /(https?:\/\/)(www\.|m\.)?(facebook|fb).com\/.*\/videos\/.*/; const reverbnationRegex = /https:\/\/(www.)?reverbnation.com\/(.+)\/song\/(.+)/; -export default class Util { +export class Util { constructor() { throw new Error(`The ${this.constructor.name} class is static and cannot be instantiated!`); } @@ -127,3 +127,5 @@ export default class Util { }); } } + +export default Util; diff --git a/yarn.lock b/yarn.lock index ab51860..e4eb2ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -300,17 +300,19 @@ discord-ytdl-core@^5.0.2: dependencies: prism-media "^1.2.7" -discord.js@discordjs/discord.js: - version "12.5.0" - resolved "https://codeload.github.com/discordjs/discord.js/tar.gz/e848d25c86fcd4a11a7879f7dcd55d0bc93faa6d" +discord.js@^12.5.3: + version "12.5.3" + resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-12.5.3.tgz#56820d473c24320871df9ea0bbc6b462f21cf85c" + integrity sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw== dependencies: "@discordjs/collection" "^0.1.6" "@discordjs/form-data" "^3.0.1" abort-controller "^3.0.0" node-fetch "^2.6.1" - prism-media "^1.2.2" + prism-media "^1.2.9" + setimmediate "^1.0.5" tweetnacl "^1.0.3" - ws "^7.3.1" + ws "^7.4.4" dom-serializer@^1.0.1, dom-serializer@~1.2.0: version "1.2.0" @@ -667,7 +669,7 @@ prettier@^2.2.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== -prism-media@^1.2.2, prism-media@^1.2.7: +prism-media@^1.2.7, prism-media@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.2.9.tgz#8d4f97b36efdfc82483eb8d3db64020767866f36" integrity sha512-UHCYuqHipbTR1ZsXr5eg4JUmHER8Ss4YEb9Azn+9zzJ7/jlTtD1h0lc4g6tNx3eMlB8Mp6bfll0LPMAV4R6r3Q== @@ -737,6 +739,11 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + signal-exit@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -898,7 +905,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^7.3.1: +ws@^7.4.4: version "7.4.4" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59" integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==