feat: base

This commit is contained in:
Snowflake107 2021-06-10 01:12:29 +05:45
parent 311df79adc
commit fac2662025
9 changed files with 116 additions and 18 deletions

View file

@ -66,6 +66,7 @@
"@discordjs/opus": "^0.5.0", "@discordjs/opus": "^0.5.0",
"@types/node": "^14.14.41", "@types/node": "^14.14.41",
"@types/ws": "^7.4.1", "@types/ws": "^7.4.1",
"discord-api-types": "^0.18.1",
"discord.js": "^13.0.0-dev.dda5ee2e9f0839d3e42d25114ae1b47355cdfd27", "discord.js": "^13.0.0-dev.dda5ee2e9f0839d3e42d25114ae1b47355cdfd27",
"discord.js-docgen": "discordjs/docgen#ts-patch", "discord.js-docgen": "discordjs/docgen#ts-patch",
"jsdoc-babel": "^0.5.0", "jsdoc-babel": "^0.5.0",

View file

@ -30,9 +30,14 @@ export class Player extends EventEmitter {
return new Promise<Queue>((resolve) => { return new Promise<Queue>((resolve) => {
if (this.queues.has(message.guild.id)) return this.queues.get(message.guild.id); if (this.queues.has(message.guild.id)) return this.queues.get(message.guild.id);
const channel = message.member.voice?.channel; const channel = message.member.voice?.channel;
if (!channel) return void this.emit( if (!channel)
return void this.emit(
PlayerEvents.ERROR, PlayerEvents.ERROR,
new PlayerError('Voice connection is not available in this server!', PlayerErrorEventCodes.NOT_CONNECTED, message) new PlayerError(
'Voice connection is not available in this server!',
PlayerErrorEventCodes.NOT_CONNECTED,
message
)
); );
const queue = new Queue(this, message.guild); const queue = new Queue(this, message.guild);
@ -57,7 +62,7 @@ export class Player extends EventEmitter {
}); });
return queue; return queue;
}) });
} }
public getQueue(message: Message) { public getQueue(message: Message) {

View file

@ -1,12 +1,11 @@
import Player from "../Player"; import Player from '../Player';
export class Playlist { export class Playlist {
player: Player; player: Player;
constructor(player: Player, data: any) { constructor(player: Player, data: any) {
Object.defineProperty(this, "player", { value: player }); Object.defineProperty(this, 'player', { value: player });
} }
} }
export default Playlist; export default Playlist;

View file

@ -0,0 +1,89 @@
import { DiscordGatewayAdapterCreator, DiscordGatewayAdapterLibraryMethods } from '@discordjs/voice';
import {
VoiceChannel,
Snowflake,
Client,
Constants,
WebSocketShard,
Guild,
StageChannel,
Collection
} from 'discord.js';
import { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v8';
class VoiceAdapter {
public client: Client;
public adapters = new Collection<Snowflake, DiscordGatewayAdapterLibraryMethods>();
public clients = new Set<Client>();
public guilds = new Collection<WebSocketShard, Set<Snowflake>>();
constructor(client: Client) {
this.client = client;
Object.defineProperty(this, 'client', {
enumerable: false,
writable: true,
configurable: true
});
}
trackVoiceState() {
if (this.clients.has(this.client)) return;
this.clients.add(this.client);
this.client.ws.on('VOICE_STATE_UPDATE', (data: GatewayVoiceServerUpdateDispatchData) => {
this.adapters.get(data.guild_id)?.onVoiceServerUpdate(data);
});
this.client.ws.on(Constants.WSEvents.VOICE_STATE_UPDATE, (payload: GatewayVoiceStateUpdateDispatchData) => {
if (payload.guild_id && payload.session_id && payload.user_id === this.client.user?.id) {
this.adapters.get(payload.guild_id)?.onVoiceStateUpdate(payload);
}
});
}
cleanupGuilds(shard: WebSocketShard) {
const guilds = this.guilds.get(shard);
if (guilds) {
for (const guildID of guilds.values()) {
this.adapters.get(guildID)?.destroy();
}
}
}
trackGuild(guild: Guild) {
let guilds = this.guilds.get(guild.shard);
if (!guilds) {
const cleanup = () => this.cleanupGuilds(guild.shard);
guild.shard.on('close', cleanup);
guild.shard.on('destroyed', cleanup);
guilds = new Set();
this.guilds.set(guild.shard, guilds);
}
guilds.add(guild.id);
}
}
export default function createAdapter(channel: VoiceChannel | StageChannel): DiscordGatewayAdapterCreator {
return (methods) => {
const adapter = new VoiceAdapter(channel.client);
adapter.adapters.set(channel.guild.id, methods);
adapter.trackVoiceState();
adapter.trackGuild(channel.guild);
return {
sendPayload(data) {
if (channel.guild.shard.status === Constants.Status.READY) {
channel.guild.shard.send(data);
return true;
}
return false;
},
destroy() {
return adapter.adapters.delete(channel.guild.id);
}
};
};
}

View file

@ -0,0 +1 @@
class VoiceSubscriptionManager {}

View file

@ -17,7 +17,7 @@ export enum PlayerEvents {
SEARCH_RESULTS = 'searchResults', SEARCH_RESULTS = 'searchResults',
TRACK_ADD = 'trackAdd', TRACK_ADD = 'trackAdd',
TRACK_START = 'trackStart' TRACK_START = 'trackStart'
}; }
export enum PlayerErrorEventCodes { export enum PlayerErrorEventCodes {
DEFAULT = 'PlayerError', DEFAULT = 'PlayerError',
@ -28,7 +28,7 @@ export enum PlayerErrorEventCodes {
PARSE_ERROR = 'ParseError', PARSE_ERROR = 'ParseError',
VIDEO_UNAVAILABLE = 'VideoUnavailable', VIDEO_UNAVAILABLE = 'VideoUnavailable',
MUSIC_STARTING = 'MusicStarting' MUSIC_STARTING = 'MusicStarting'
}; }
export const PlayerOptions: DP_OPTIONS = { export const PlayerOptions: DP_OPTIONS = {
leaveOnEnd: true, leaveOnEnd: true,

View file

@ -1,4 +1,4 @@
import { Message } from "discord.js"; import { Message } from 'discord.js';
export default class PlayerError extends Error { export default class PlayerError extends Error {
discordMessage: Message; discordMessage: Message;

View file

@ -7,12 +7,15 @@ import { validateURL as SoundcloudValidateURL } from 'soundcloud-scraper';
import { VoiceChannel } from 'discord.js'; import { VoiceChannel } from 'discord.js';
const spotifySongRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/; const spotifySongRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/;
const spotifyPlaylistRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})/; const spotifyPlaylistRegex =
/https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})/;
const spotifyAlbumRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:album\/|\?uri=spotify:album:)((\w|-){22})/; const spotifyAlbumRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:album\/|\?uri=spotify:album:)((\w|-){22})/;
const vimeoRegex = /(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|video\/|)(\d+)(?:|\/\?)/; const vimeoRegex =
/(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|video\/|)(\d+)(?:|\/\?)/;
const facebookRegex = /(https?:\/\/)(www\.|m\.)?(facebook|fb).com\/.*\/videos\/.*/; const facebookRegex = /(https?:\/\/)(www\.|m\.)?(facebook|fb).com\/.*\/videos\/.*/;
const reverbnationRegex = /https:\/\/(www.)?reverbnation.com\/(.+)\/song\/(.+)/; const reverbnationRegex = /https:\/\/(www.)?reverbnation.com\/(.+)\/song\/(.+)/;
const attachmentRegex = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/; const attachmentRegex =
/^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
export class Util { export class Util {
/** /**