Version 2.1.0 - Passage sur Lavalink V4 et Moonlink.js
Some checks failed
Subsonics - Web/pipeline/head There was a failure building this commit
Subsonics - Web/pipeline/pr-main This commit looks good

This commit is contained in:
2024-04-16 16:05:21 +02:00
parent 960cbeabc3
commit 2241136729
43 changed files with 3298 additions and 91 deletions

14
node_modules/moonlink.js/dist/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,14 @@
export declare const version: string;
export * from "./src/@Managers/MoonlinkManager";
export * from "./src/@Managers/PlayerManager";
export * from "./src/@Managers/NodeManager";
export * from "./src/@Entities/MoonlinkNode";
export * from "./src/@Entities/MoonlinkPlayer";
export * from "./src/@Entities/MoonlinkQueue";
export * from "./src/@Services/MoonlinkMakeRequest";
export * from "./src/@Services/MoonlinkRestFul";
export * from "./src/@Typings/";
export * from "./src/@Utils/MoonlinkDatabase";
export * from "./src/@Utils/MoonlinkFilters";
export * from "./src/@Utils/MoonlinkTrack";
export * from "./src/@Utils/Structure";

31
node_modules/moonlink.js/dist/index.js generated vendored Normal file
View File

@ -0,0 +1,31 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = require("../package.json").version;
__exportStar(require("./src/@Managers/MoonlinkManager"), exports);
__exportStar(require("./src/@Managers/PlayerManager"), exports);
__exportStar(require("./src/@Managers/NodeManager"), exports);
__exportStar(require("./src/@Entities/MoonlinkNode"), exports);
__exportStar(require("./src/@Entities/MoonlinkPlayer"), exports);
__exportStar(require("./src/@Entities/MoonlinkQueue"), exports);
__exportStar(require("./src/@Services/MoonlinkMakeRequest"), exports);
__exportStar(require("./src/@Services/MoonlinkRestFul"), exports);
__exportStar(require("./src/@Typings/"), exports);
__exportStar(require("./src/@Utils/MoonlinkDatabase"), exports);
__exportStar(require("./src/@Utils/MoonlinkFilters"), exports);
__exportStar(require("./src/@Utils/MoonlinkTrack"), exports);
__exportStar(require("./src/@Utils/Structure"), exports);

17
node_modules/moonlink.js/dist/index.mjs generated vendored Normal file
View File

@ -0,0 +1,17 @@
import mod from "./index.js";
export default mod;
export const MoonlinkDatabase = mod.MoonlinkDatabase;
export const MoonlinkFilters = mod.MoonlinkFilters;
export const MoonlinkManager = mod.MoonlinkManager;
export const MoonlinkNode = mod.MoonlinkNode;
export const MoonlinkPlayer = mod.MoonlinkPlayer;
export const MoonlinkQueue = mod.MoonlinkQueue;
export const MoonlinkRestFul = mod.MoonlinkRestFul;
export const MoonlinkTrack = mod.MoonlinkTrack;
export const NodeManager = mod.NodeManager;
export const PlayerManager = mod.PlayerManager;
export const Plugin = mod.Plugin;
export const Structure = mod.Structure;
export const makeRequest = mod.makeRequest;
export const version = mod.version;

View File

@ -0,0 +1,5 @@
{
"queue": {
"137291455336022018": []
}
}

View File

@ -0,0 +1,44 @@
/// <reference types="node" />
import { INode, INodeStats } from "../@Typings";
import { MoonlinkWebSocket } from "../@Services/MoonlinkWebSocket";
import { MoonlinkRestFul } from "../../index";
export declare class MoonlinkNode {
private _manager;
private reconnectTimeout?;
private reconnectAttempts;
private retryAmount;
private retryDelay;
private resumeStatus;
host: string;
identifier?: string;
password: string;
port?: number;
secure: boolean;
regions?: string[];
http: string;
rest: MoonlinkRestFul;
info?: Record<string, any>;
version?: string;
resume?: boolean;
resumed?: boolean;
autoResume?: boolean;
resumeTimeout?: number;
sessionId: string;
socket: MoonlinkWebSocket | null;
state: string;
stats: INodeStats | Record<string, any>;
calls: number;
constructor(node: INode);
get address(): string;
check(node: INode): void;
request(endpoint: string, params: any): Promise<object>;
connect(): Promise<any>;
open(): void;
private reconnect;
protected close(code: number, reason: any): void;
protected error(error: Error): void;
protected message(data: Buffer | string): Promise<void>;
protected handleEvent(payload: any): Promise<any>;
private movePlayers;
private get getAllPlayers();
}

View File

@ -0,0 +1,352 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkNode = void 0;
const MoonlinkWebSocket_1 = require("../@Services/MoonlinkWebSocket");
const index_1 = require("../../index");
class MoonlinkNode {
_manager = index_1.Structure.manager;
reconnectTimeout;
reconnectAttempts = 1;
retryAmount = 6;
retryDelay = 120000;
resumeStatus = false;
host;
identifier;
password;
port;
secure;
regions;
http;
rest;
info = {};
version;
resume = index_1.Structure.manager.options?.resume;
resumed;
autoResume = index_1.Structure.manager.options?.autoResume;
resumeTimeout = 30000;
sessionId;
socket;
state = "DISCONNECTED";
stats = {};
calls = 0;
constructor(node) {
this.check(node);
this.host = node.host;
this.identifier = node.identifier || null;
this.password = node.password ? node.password : "youshallnotpass";
this.port = node.port ? node.port : node.secure == true ? 443 : 80;
this.secure = node.secure || false;
this.regions = node.regions;
this.http = `http${node.secure ? "s" : ""}://${this.address}/v4/`;
this.rest = new (index_1.Structure.get("MoonlinkRestFul"))(this);
if (node.sessionId)
this.sessionId = node.sessionId;
this.connect();
}
get address() {
return `${this.host}:${this.port}`;
}
check(node) {
if (typeof node.host !== "string" && typeof node.host !== "undefined")
throw new Error('@Moonlink(Nodes) - "host" option is not configured correctly');
if (typeof node.password !== "string" &&
typeof node.password !== "undefined")
throw new Error('@Moonlink(Nodes) - the option "password" is not set correctly');
if ((node.port && typeof node.port !== "number") ||
node.port > 65535 ||
node.port < 0)
throw new Error('@Moonlink(Nodes) - the "port" option is not set correctly');
if (typeof node.retryAmount !== "undefined" &&
typeof node.retryAmount !== "number")
throw new Error('@Moonlink(Nodes) - the "retryAmount" option is not set correctly');
if (typeof node.retryDelay !== "undefined" &&
typeof node.retryDelay !== "number")
throw new Error('@Moonlink(Nodes) - the "retryDelay" option is not set correctly');
}
request(endpoint, params) {
this.calls++;
return this.rest.get(`${endpoint}?${params}`);
}
async connect() {
if (this.state == "CONNECTED" || this.state == "READY")
return;
this.state = "CONNECTING";
let headers = {
Authorization: this.password,
"User-Id": this._manager.options.clientId,
"Client-Name": this._manager.options.clientName
};
if (this.resume)
headers["Session-Id"] = index_1.Structure.db.get(`sessionId.${this.identifier ?? this.host.replace(/\./g, "-")}`);
this.socket = new MoonlinkWebSocket_1.MoonlinkWebSocket(`ws${this.secure ? "s" : ""}://${this.address}/v4/websocket`, { headers });
this.socket.on("open", this.open.bind(this));
this.socket.on("close", this.close.bind(this));
this.socket.on("message", this.message.bind(this));
this.socket.on("error", this.error.bind(this));
}
open() {
if (this.reconnectTimeout)
clearTimeout(this.reconnectTimeout);
this._manager.emit("debug", `@Moonlink(Node) - The Node ${this.identifier ?? this.host} has been connected successfully`);
this._manager.emit("nodeCreate", this);
this.state = "CONNECTED";
}
reconnect() {
if (this.reconnectAttempts >= this.retryAmount) {
this._manager.emit("debug", `@Moonlink(Node) - Node ${this.identifier ?? this.host} was destroyed due to inactivity, attempts to reconnect were failed`);
this._manager.emit("nodeDestroy", this);
this.socket.close(1000, "destroy");
this.socket.removeAllListeners();
}
else {
this.reconnectTimeout = setTimeout(() => {
this.socket.removeAllListeners();
this.socket = null;
this.state = "RECONNECTING";
this._manager.emit("nodeReconnect", this);
this.connect();
this._manager.emit("debug", `@Moonlink(Node) - We are trying to reconnect node ${this.identifier ?? this.host}, attempted number ${this.reconnectAttempts}
`);
if (this.getAllPlayers.length &&
this._manager.options?.switchPlayersAnotherNode)
this.movePlayers();
this.reconnectAttempts++;
}, this.retryDelay);
}
}
close(code, reason) {
if (code !== 1000 || reason !== "destroy")
this.reconnect();
this._manager.emit("debug", `@Moonlink(Node) - The node connection ${this.identifier ?? this.host} has been closed`);
this._manager.emit("nodeClose", this, code, reason);
this.getAllPlayers.forEach(player => {
player.playing = false;
});
this.state = "DISCONNECTED";
}
error(error) {
if (!error)
return;
this._manager.emit("nodeError", this, error);
this._manager.emit("debug", `@Moonlink(Nodes) - The ${this.identifier ?? this.host} an error has occurred:
${error}`);
}
async message(data) {
if (Array.isArray(data))
data = Buffer.concat(data);
else if (data instanceof ArrayBuffer)
data = Buffer.from(data);
let payload = JSON.parse(data.toString("utf8"));
if (!payload.op)
return;
this._manager.emit("nodeRaw", this, payload);
switch (payload.op) {
case "ready":
this.sessionId = payload.sessionId;
this.resume
? index_1.Structure.db.set(`sessionId.${this.identifier ?? this.host.replace(/\./g, "-")}`, this.sessionId)
: null;
this.resumed = payload.resumed;
this.rest.setSessionId(this.sessionId);
this.state = "READY";
if (!this._manager.initiated && !this.resumed) {
index_1.Structure.db.delete("queue");
index_1.Structure.db.delete("players");
}
this._manager.emit("debug", `@Moonlink(Node) - ${this.resumed ? ` session was resumed,` : ``} session is currently ${this.sessionId}`);
this._manager.emit("nodeReady", this, this.sessionId, this.resumed);
if (this.resume) {
this.rest.patch(`sessions/${this.sessionId}`, {
data: {
resuming: this.resume,
timeout: this.resumeTimeout
}
});
this._manager.emit("debug", `@Moonlink(Nodes) - Resuming configured`);
}
this.version = await this.rest.getVersion();
this.info = await this.rest.getInfo();
if (this.autoResume) {
let resumePlayers = this.getAllPlayers;
for (const resumePlayer of resumePlayers) {
resumePlayer.restart();
}
}
if (this.resumed) {
const resumedPlayers = await this.rest.get(`sessions/${this.sessionId}/players`);
for (const resumedPlayer of resumedPlayers) {
const previousInfosPlayer = index_1.Structure.db.get(`players.${resumedPlayer.guildId}`) || {};
const player = this._manager.players.create({
guildId: resumedPlayer.guildId,
voiceChannel: previousInfosPlayer.voiceChannel,
textChannel: previousInfosPlayer.textChannel,
volume: previousInfosPlayer.volume,
loop: previousInfosPlayer.loop,
autoPlay: previousInfosPlayer.autoPlay,
autoLeave: previousInfosPlayer.autoLeave,
node: this.identifier ?? this.host,
notBackup: true
});
player.previous = previousInfosPlayer.previous;
if (resumedPlayer.track) {
const track = new (index_1.Structure.get("MoonlinkTrack"))(resumedPlayer.track);
player.current = track;
player.current.position =
resumedPlayer.state.position;
await player.restart();
}
}
this._manager.emit("nodeResumed", this, resumedPlayers);
}
break;
case "stats":
delete payload.op;
this.stats = { ...payload };
break;
case "playerUpdate":
let player = this._manager.players.get(payload.guildId);
if (!player)
return;
player.ping = payload.state.ping;
if (!player.current)
return;
player.current.position = payload.state.position;
player.current.time = payload.state.time;
this._manager.emit("playerUpdate", player, payload, this);
break;
case "event":
this.handleEvent(payload);
break;
default:
this._manager.emit("nodeError", this, new Error(`@Moonlink(Nodes) - Unexpected op "${payload.op}" with data: ${payload}`));
}
}
async handleEvent(payload) {
if (!payload)
return;
if (!payload.guildId)
return;
if (!this._manager.players.has(payload.guildId))
return;
let player = this._manager.players.get(payload.guildId);
switch (payload.type) {
case "TrackStartEvent": {
if (!player.current)
player.current = new (index_1.Structure.get("MoonlinkTrack"))(payload.track);
player.playing = true;
player.paused = false;
this._manager.emit("trackStart", player, player.current);
break;
}
case "TrackEndEvent": {
let track = player.current;
let queue = player.queue.all;
player.playing = false;
if (this._manager.options.previousTracksInArray)
player.previous.push(track);
else
player.previous = track;
if (["loadFailed", "cleanup"].includes(payload.reason)) {
if (!queue) {
player.queue.clear();
{
this._manager.emit("trackEnd", player, track, payload);
this._manager.emit("queueEnd", player, track);
return;
}
}
player.play();
return;
}
if (payload.reason === "replaced") {
this._manager.emit("trackEnd", player, track, payload);
return;
}
if (track && player.loop) {
if (player.loop == 1) {
await this.rest.update({
guildId: payload.guildId,
data: { track: { encoded: payload.track.encoded } }
});
if (this.resumed)
player.current = new (index_1.Structure.get("MoonlinkTrack"))(payload.track);
return;
}
if (player.loop == 2) {
player.queue.add(new (index_1.Structure.get("MoonlinkTrack"))(payload.track));
if (!queue || queue.length === 0)
return this._manager.emit("trackEnd", player, track, payload);
player.play();
return;
}
else {
this._manager.emit("trackEnd", player, track);
this._manager.emit("debug", "@Manager(Nodes) - invalid loop value will be ignored!");
}
}
if (player.queue.size) {
this._manager.emit("trackEnd", player, track);
player.play();
return;
}
if (typeof player.autoPlay === "boolean" &&
player.autoPlay === true) {
if (payload.reason == "stopped")
return;
let uri = `https://www.youtube.com/watch?v=${track.identifier}&list=RD${track.identifier}`;
let req = await this._manager.search(uri);
if (!req ||
!req.tracks ||
["loadFailed", "cleanup"].includes(req.loadType))
return player.stop();
let data = req.tracks[Math.floor(Math.random() * Math.floor(req.tracks.length))];
player.queue.add(data);
player.play();
return;
}
if (player.autoLeave) {
player.destroy();
this._manager.emit("autoLeaved", player, track);
}
if (!player.queue.size) {
this._manager.emit("debug", "@Moonlink(Nodes) - The queue is empty");
this._manager.emit("trackEnd", player, track, payload);
this._manager.emit("queueEnd", player);
player.current = null;
player.queue.clear();
}
break;
}
case "TrackStuckEvent": {
this._manager.emit("trackStuck", player, player.current);
player.stop();
break;
}
case "TrackExceptionEvent": {
this._manager.emit("trackError", player, player.current);
player.stop();
break;
}
case "WebSocketClosedEvent": {
this._manager.emit("socketClosed", player, payload);
break;
}
default: {
const error = new Error(`@Moonlink(Nodes) - unknown event '${payload.type}'.`);
this._manager.emit("nodeError", this, error);
}
}
}
movePlayers() {
this.getAllPlayers.forEach(player => {
let anotherNode = this._manager.nodes.sortByUsage(this._manager.options?.sortNode ?? "players")[0];
this._manager.emit("debug", `@Moonlink(Node) - Moving player ${player.guildId} to ${anotherNode.identifier ?? anotherNode.host}`);
player.transferNode(anotherNode);
});
return true;
}
get getAllPlayers() {
return Object.values(this._manager.players.all).filter(player => player.node === this);
}
}
exports.MoonlinkNode = MoonlinkNode;

View File

@ -0,0 +1,52 @@
/// <reference types="node" />
import { EventEmitter } from "node:events";
import { MoonlinkManager, MoonlinkQueue, MoonlinkNode, MoonlinkTrack, MoonlinkFilters } from "../../index";
import { MoonlinkWebSocket } from "../@Services/MoonlinkWebSocket";
import { IPlayerData, connectOptions } from "../@Typings";
export declare class MoonlinkPlayer {
manager: MoonlinkManager;
guildId: string;
textChannel: string;
voiceChannel: string;
voiceRegion: string;
autoPlay: boolean | null;
autoLeave: boolean | null;
connected: boolean | null;
playing: boolean | null;
paused: boolean | null;
loop: number | null;
volume: number;
ping: number;
queue: MoonlinkQueue;
filters: MoonlinkFilters;
current: Record<string, any>;
previous: MoonlinkTrack[] | MoonlinkTrack | Record<string, any>;
data: Record<string, any>;
node: MoonlinkNode | any;
voiceReceiverWs: MoonlinkWebSocket | any;
constructor(data: IPlayerData);
set(key: string, value: unknown): void;
get<T>(key: string): T;
setTextChannel(channelId: string): boolean;
setVoiceChannel(channelId: string): boolean;
setAutoLeave(mode?: boolean | null): boolean | null;
setAutoPlay(mode: boolean): boolean;
connect(options: connectOptions): boolean | null;
disconnect(): boolean;
restart(): Promise<void>;
play(track?: MoonlinkTrack | string): Promise<boolean>;
pause(): Promise<boolean>;
resume(): Promise<boolean>;
private updatePlaybackStatus;
stop(destroy?: boolean): Promise<boolean>;
skip(position?: number): Promise<boolean>;
setVolume(percent: number): Promise<number>;
setLoop(mode: number | string | null): number | string | null;
destroy(): Promise<boolean>;
private validateNumberParam;
seek(position: number): Promise<number | null>;
shuffle(): boolean;
transferNode(node: MoonlinkNode | string): Promise<boolean>;
listenVoice(): EventEmitter | boolean;
stopListeningVoice(): void;
}

View File

@ -0,0 +1,415 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkPlayer = void 0;
const node_events_1 = require("node:events");
const index_1 = require("../../index");
const MoonlinkWebSocket_1 = require("../@Services/MoonlinkWebSocket");
class MoonlinkPlayer {
manager = index_1.Structure.manager;
guildId;
textChannel;
voiceChannel;
voiceRegion;
autoPlay;
autoLeave;
connected;
playing;
paused;
loop;
volume;
ping;
queue;
filters;
current;
previous;
data;
node;
voiceReceiverWs;
constructor(data) {
this.guildId = data.guildId;
this.textChannel = data.textChannel;
this.voiceChannel = data.voiceChannel;
this.voiceRegion = data.voiceRegion;
this.autoPlay = data.autoPlay;
this.autoLeave = data.autoLeave || false;
this.connected = data.connected || false;
this.playing = data.playing || false;
this.paused = data.paused || false;
this.loop = data.loop || 0;
this.volume = data.volume || 100;
this.ping = data.ping || 0;
this.queue = new (index_1.Structure.get("MoonlinkQueue"))(this.manager, this.guildId);
this.current = null;
this.previous = [];
this.data = {};
this.node = this.manager.nodes.get(data.node);
this.filters = new (index_1.Structure.get("MoonlinkFilters"))(this);
this.voiceReceiverWs = null;
if (!data.notBackup && this.manager.options.resume)
this.manager.players.backup(this);
}
set(key, value) {
this.data[key] = value;
}
get(key) {
return this.data[key] || null;
}
setTextChannel(channelId) {
if (!channelId) {
throw new Error('@Moonlink(Player) - "channelId" option is empty');
}
if (typeof channelId !== "string") {
throw new Error('@Moonlink(Player) - option "channelId" is different from a string');
}
this.manager.emit("playerSetTextChannel", this, this.textChannel, channelId);
this.textChannel = channelId;
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
setVoiceChannel(channelId) {
if (!channelId) {
throw new Error('@Moonlink(Player) - "channelId" option is empty');
}
if (typeof channelId !== "string") {
throw new Error('@Moonlink(Player) - option "channelId" is different from a string');
}
this.manager.emit("playerSetVoiceChannel", this, this.voiceChannel, channelId);
this.voiceChannel = channelId;
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
setAutoLeave(mode) {
if (typeof mode !== "boolean") {
throw new Error('@Moonlink(Player) - "mode" option is empty or different from a boolean');
}
mode ? mode : (mode = !this.autoLeave);
this.autoLeave = mode;
this.manager.emit("playerAutoLeaveTriggered", this, mode);
if (this.manager.options.resume)
this.manager.players.backup(this);
return mode;
}
setAutoPlay(mode) {
if (typeof mode !== "boolean") {
throw new Error('@Moonlink(Player) - "mode" option is empty or different from a boolean');
}
this.autoPlay = mode;
this.manager.emit("playerAutoPlayTriggered", this, mode);
if (this.manager.options.resume)
this.manager.players.backup(this);
return mode;
}
connect(options) {
options = options || { setDeaf: false, setMute: false };
const { setDeaf, setMute } = options;
this.manager._SPayload(this.guildId, JSON.stringify({
op: 4,
d: {
guild_id: this.guildId,
channel_id: this.voiceChannel,
self_mute: setMute,
self_deaf: setDeaf
}
}));
this.connected = true;
this.manager.emit("playerConnected", this);
return true;
}
disconnect() {
this.manager._SPayload(this.guildId, JSON.stringify({
op: 4,
d: {
guild_id: this.guildId,
channel_id: null,
self_mute: false,
self_deaf: false
}
}));
this.connected = false;
this.voiceChannel = null;
return true;
}
async restart() {
this.connect({
setDeaf: true,
setMute: false
});
await this.manager.players.attemptConnection(this.guildId);
if (!this.current && this.queue.size) {
this.play();
return;
}
else {
await this.node.rest.update({
guildId: this.guildId,
data: {
track: {
encoded: this.current.encoded
},
position: this.current.position,
volume: this.volume
}
});
}
this.manager.emit("playerRestarted", this);
if (this.manager.options.resume)
this.manager.players.backup(this);
}
async play(track) {
if (!track && !this.queue.size)
return false;
let data = track
? track
: this.queue.shift();
if (!data)
return false;
if (this.loop && Object.keys(this.current).length != 0) {
this.current.time ? (this.current.time = 0) : false;
this.ping = undefined;
this.queue.push(this.current);
}
if (typeof data == "string") {
try {
let resolveTrack = await this.node.rest.decodeTrack(data);
data = new (index_1.Structure.get("MoonlinkTrack"))(resolveTrack, null);
}
catch (err) {
this.manager.emit("debug", "@Moonlink(Player) - Fails when trying to decode a track " +
data +
", error: " +
err);
return;
}
}
this.current = data;
await this.node.rest.update({
guildId: this.guildId,
data: {
track: {
encoded: data.encoded
},
volume: this.volume
}
});
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
async pause() {
if (this.paused)
return true;
await this.updatePlaybackStatus(true);
this.manager.emit("playerPaused", this);
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
async resume() {
if (this.playing)
return true;
await this.updatePlaybackStatus(false);
this.manager.emit("playerResume", this);
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
async updatePlaybackStatus(paused) {
await this.node.rest.update({
guildId: this.guildId,
data: { paused }
});
this.paused = paused;
this.playing = !paused;
}
async stop(destroy) {
if (!this.queue.size) {
await this.node.rest.update({
guildId: this.guildId,
data: {
track: { encoded: null }
}
});
if (this.manager.options.resume)
this.manager.players.backup(this);
}
this.manager.emit("playerStopped", this, this.current);
this.manager.options?.destroyPlayersStopped && destroy
? this.destroy()
: this.queue.clear();
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
async skip(position) {
if (position) {
this.validateNumberParam(position, "position");
let queue = this.queue.all();
if (!queue[position - 1]) {
throw new Error(`@Moonlink(Player) - the indicated position does not exist, make security in your code to avoid errors`);
}
let data = queue.splice(position - 1, 1)[0];
this.manager.emit("playerSkipped", this, this.current, data);
this.current = data;
this.queue.setQueue(queue);
await this.play(data);
return true;
}
if (this.queue.size) {
this.manager.emit("playerSkipped", this, this.current, this.queue.all[0]);
this.play();
return false;
}
else {
this.stop();
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
}
async setVolume(percent) {
if (typeof percent == "undefined" || isNaN(percent)) {
throw new Error('@Moonlink(Player) - option "percent" is empty or different from a number');
}
var beforeChange = this.volume;
this.volume = percent;
await this.node.rest.update({
guildId: this.guildId,
data: { volume: percent }
});
this.manager.emit("playerVolumeChanged", this, beforeChange, percent);
if (this.manager.options.resume)
this.manager.players.backup(this);
return percent;
}
setLoop(mode) {
if (typeof mode == "string" &&
["off", "track", "queue"].includes(mode)) {
mode == "track"
? (mode = 1)
: mode == "queue"
? (mode = 2)
: (mode = 0);
}
if (typeof mode !== "number" ||
(mode !== null && (mode < 0 || mode > 2))) {
throw new Error('@Moonlink(Player) - the option "mode" is different from a number and string or the option does not exist');
}
this.manager.emit("playerLoopSet", this, this.loop, mode);
this.loop = mode;
if (this.manager.options.resume)
this.manager.players.backup(this);
return mode;
}
async destroy() {
if (this.connected)
this.disconnect();
await this.node.rest.destroy(this.guildId);
this.queue.clear();
this.manager.players.delete(this.guildId);
this.manager.emit("debug", "@Moonlink(Player) - Destroyed player " + this.guildId);
this.manager.emit("playerDestroyed", this.guildId);
if (this.manager.options.resume)
this.manager.players.backup(this);
return true;
}
validateNumberParam(param, paramName) {
if (typeof param !== "number") {
throw new Error(`@Moonlink(Player) - option "${paramName}" is empty or different from a number`);
}
}
async seek(position) {
this.validateNumberParam(position, "position");
if (position >= this.current.duration) {
throw new Error(`@Moonlink(Player) - parameter "position" is greater than the duration of the current track`);
}
if (!this.current.isSeekable && this.current.isStream) {
throw new Error(`@Moonlink(Player) - seek function cannot be applied on live video or cannot be applied in "isSeekable"`);
}
this.manager.emit("playerSeeking", this, this.current.position, position);
await this.node.rest.update({
guildId: this.guildId,
data: { position }
});
if (this.manager.options.resume)
this.manager.players.backup(this);
return position;
}
shuffle() {
if (!this.queue.size) {
throw new Error("@Moonlink(Player)the one that is empty so that the shuffle can be performed");
}
let oldQueue = Array.from(this.queue.all);
let shuffleStatus = this.queue.shuffle();
this.manager.emit("playerShuffled", this, oldQueue, this.queue.all, shuffleStatus);
if (this.manager.options.resume)
this.manager.players.backup(this);
return shuffleStatus;
}
async transferNode(node) {
typeof node == "string" ? (node = this.manager.nodes.get(node)) : null;
if (!node)
return false;
this.node = node;
if (this.current || this.queue.size) {
await this.restart();
return true;
}
else {
await this.manager.players.attemptConnection(this.guildId);
return true;
}
}
listenVoice() {
if (!this.node.info.isNodeLink)
return false;
this.voiceReceiverWs = new MoonlinkWebSocket_1.MoonlinkWebSocket(`ws${this.node.secure ? "s" : ""}://${this.node.address}/connection/data`, {
headers: {
Authorization: this.node.password,
"Client-Name": `Moonlink/${this.manager.version}`,
"guild-id": this.guildId,
"user-id": this.manager.clientId
}
});
const listener = new node_events_1.EventEmitter();
this.voiceReceiverWs.on("message", (data) => {
const payload = JSON.parse(data);
switch (payload?.type) {
case "startSpeakingEvent": {
listener.emit("start", {
...payload.data
});
break;
}
case "endSpeakingEvent": {
payload.data.data = Buffer.from(payload.data.data, "base64");
listener.emit("end", {
...payload.data
});
break;
}
default: {
listener.emit("unknown", {
...payload
});
}
}
});
this.voiceReceiverWs.on("close", () => {
listener.emit("close");
});
this.voiceReceiverWs.on("error", error => {
listener.emit("error", error);
});
return listener;
}
stopListeningVoice() {
if (!this.voiceReceiverWs)
return;
this.voiceReceiverWs.close();
this.voiceReceiverWs = null;
}
}
exports.MoonlinkPlayer = MoonlinkPlayer;

View File

@ -0,0 +1,19 @@
import { MoonlinkDatabase, MoonlinkManager, MoonlinkTrack } from "../..";
export declare class MoonlinkQueue {
db: MoonlinkDatabase;
private guildId;
private manager;
constructor(manager: MoonlinkManager, guildId: string);
add(data: MoonlinkTrack, position?: number): void;
has(identifier: string): boolean;
first(): any;
shift(): any;
push(data: any): void;
clear(): boolean;
get size(): number;
shuffle(): boolean;
remove(position: number): boolean;
get all(): any;
getQueue(): MoonlinkTrack[];
setQueue(queue: MoonlinkTrack[]): void;
}

View File

@ -0,0 +1,99 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkQueue = void 0;
const __1 = require("../..");
class MoonlinkQueue {
db = __1.Structure.db;
guildId;
manager;
constructor(manager, guildId) {
if (!manager || !guildId) {
throw new Error("[ @Moonlink/Queue ]: Invalid constructor arguments");
}
this.guildId = guildId;
this.manager = __1.Structure.manager;
}
add(data, position) {
if (!data)
throw new Error('[ @Moonlink/Queue ]: "data" option is empty');
let queue = this.getQueue();
position =
position !== undefined && position >= 1
? position - 1
: queue.length;
if (position < 0 || position > queue.length) {
throw new Error("@Moonlink(Queue) - Invalid position specified");
}
queue.splice(position, 0, data);
this.setQueue(queue);
}
has(identifier) {
if (!identifier || typeof identifier !== "string") {
throw new Error("@Moonlink(Queue) - Invalid identifier specified");
}
const queue = this.getQueue();
return queue.some(track => track.identifier === identifier);
}
first() {
const queue = this.getQueue();
return queue.length > 0 ? queue[0] : null;
}
shift() {
let queue = this.getQueue();
if (!queue.length)
return null;
let track = queue.shift();
this.setQueue(queue);
return track;
}
push(data) {
let queue = this.getQueue();
queue.push(data);
this.setQueue(queue);
}
clear() {
const queue = this.getQueue();
if (queue.length > 0) {
this.setQueue([]);
return true;
}
return false;
}
get size() {
return this.getQueue().length;
}
shuffle() {
const currentQueue = this.all;
for (let i = currentQueue.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[currentQueue[i], currentQueue[j]] = [
currentQueue[j],
currentQueue[i]
];
}
this.setQueue(currentQueue);
return true;
}
remove(position) {
if (!position || typeof position !== "number" || position < 1) {
throw new Error("[ @Moonlink/Queue ]: Invalid position specified");
}
const queue = this.getQueue();
if (position > queue.length) {
throw new Error("[ @Moonlink/Queue ]: Position exceeds queue length");
}
queue.splice(position - 1, 1);
this.setQueue(queue);
return true;
}
get all() {
return this.getQueue();
}
getQueue() {
return this.db.get(`queue.${this.guildId}`) || [];
}
setQueue(queue) {
this.db.set(`queue.${this.guildId}`, queue);
}
}
exports.MoonlinkQueue = MoonlinkQueue;

View File

@ -0,0 +1,61 @@
/// <reference types="node" />
import { EventEmitter } from "node:events";
import { MoonlinkPlayer, MoonlinkTrack, MoonlinkNode, PlayerManager, NodeManager } from "../../index";
import { INode, IOptions, VoicePacket, SearchResult, SearchQuery } from "../@Typings";
export interface MoonlinkEvents {
autoLeaved: (player: MoonlinkPlayer, track?: any) => void;
debug: (...args: any) => void;
nodeCreate: (node: MoonlinkNode) => void;
nodeReady: (node: MoonlinkNode, sessionId: string, resumed: boolean) => void;
nodeDestroy: (node: MoonlinkNode) => void;
nodeResumed: (node: MoonlinkNode, players: MoonlinkEvents[]) => void;
nodeReconnect: (node: MoonlinkNode) => void;
nodeClose: (node: MoonlinkNode, code: number, reason: string) => void;
nodeRaw: (node: MoonlinkNode, payload: object) => void;
nodeError: (node: MoonlinkNode, error: Error) => void;
trackStart: (player: MoonlinkPlayer, current: any) => void;
trackEnd: (player: MoonlinkPlayer, track: any, payload?: Record<string, any>) => void;
trackStuck: (player: MoonlinkPlayer, track: any) => void;
trackError: (player: MoonlinkPlayer, track: any) => void;
queueEnd: (player: MoonlinkPlayer, track?: any) => void;
playerConnected: (player: MoonlinkPlayer) => void;
playerCreated: (guildId: string) => void;
playerPaused: (player: MoonlinkPlayer) => void;
playerRestarted: (player: MoonlinkPlayer) => void;
playerResume: (player: MoonlinkPlayer) => void;
playerStopped: (player: MoonlinkPlayer, current: MoonlinkTrack) => void;
playerSetVoiceChannel: (player: MoonlinkPlayer, oldChannel: string, newChannel: string) => void;
playerAutoPlayTriggered: (player: MoonlinkPlayer, mode: boolean) => void;
playerAutoLeaveTriggered: (player: MoonlinkPlayer, mode: boolean) => void;
playerSetTextChannel: (player: MoonlinkPlayer, oldChannel: string, newChannel: string) => void;
playerVolumeChanged: (player: MoonlinkPlayer, oldVolume: number, newVolume: number) => void;
playerSkipped: (player: MoonlinkPlayer, oldCurrent: MoonlinkTrack, newCurrent: MoonlinkTrack) => void;
playerSeeking: (player: MoonlinkPlayer, oldPosition: number, newPosition: number) => void;
playerLoopSet: (player: MoonlinkPlayer, oldMode: number, mode: number) => void;
playerShuffled: (player: MoonlinkPlayer, oldQueue: unknown[], newQueue: MoonlinkTrack[], status: boolean) => void;
playerMove: (player: MoonlinkPlayer, newVoiceChannel: string, oldVoiceChannel: string) => void;
playerDisconnect: (player: MoonlinkPlayer) => void;
playerDestroyed: (guildId: string) => void;
playerUpdate: (player: MoonlinkPlayer, node: MoonlinkNode, payload: Record<string, any>) => void;
socketClosed: (player: MoonlinkPlayer, track: MoonlinkTrack) => void;
}
export declare interface MoonlinkManager {
on<K extends keyof MoonlinkEvents>(event: K, listener: MoonlinkEvents[K]): this;
once<K extends keyof MoonlinkEvents>(event: K, listener: MoonlinkEvents[K]): this;
emit<K extends keyof MoonlinkEvents>(event: K, ...args: Parameters<MoonlinkEvents[K]>): boolean;
off<K extends keyof MoonlinkEvents>(event: K, listener: MoonlinkEvents[K]): this;
}
export declare class MoonlinkManager extends EventEmitter {
clientId: string;
readonly _nodes: INode[];
readonly _SPayload: Function;
readonly players: PlayerManager;
readonly nodes: NodeManager;
readonly version: number;
options: IOptions;
initiated: boolean;
constructor(nodes: INode[], options: IOptions, SPayload: Function);
init(clientId?: string): Promise<this>;
search(options: string | SearchQuery): Promise<SearchResult>;
packetUpdate(packet: VoicePacket): void;
}

View File

@ -0,0 +1,148 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkManager = void 0;
const node_events_1 = require("node:events");
const index_1 = require("../../index");
class MoonlinkManager extends node_events_1.EventEmitter {
clientId;
_nodes;
_SPayload;
players;
nodes;
version = require("../../index").version;
options;
initiated = false;
constructor(nodes, options, SPayload) {
super();
this._nodes = nodes;
this._SPayload = SPayload;
this.players = new (index_1.Structure.get("PlayerManager"))();
this.nodes = new (index_1.Structure.get("NodeManager"))();
this.options = options;
if (options.plugins) {
options.plugins.forEach(plugin => {
plugin.load(this);
});
}
if (!this.options.clientName)
this.options.clientName = `Moonlink/${this.version} (https://github.com/Ecliptia/moonlink.js)`;
}
async init(clientId) {
if (this.initiated)
return this;
this.emit("debug", "@Moonlink - moonlink.js has started the initialization process, do not attempt to use functions until everything is initialized correctly ");
if (!clientId && !this.options.clientId)
throw new TypeError('@Moonlink(Manager): "clientId" option is required.');
this.options.clientId = clientId;
this.clientId = clientId;
index_1.Structure.init(this);
await index_1.Structure.db.fetch();
this.nodes.init();
this.players.init();
this.initiated = true;
return this;
}
async search(options) {
return new Promise(async (resolve, reject) => {
try {
if (!options) {
throw new Error("@Moonlink(Manager) - the search option has to be in string format or in an array");
}
let query;
let source;
let requester;
let node;
if (typeof options === "object") {
query = options.query;
source = options.source;
requester = options.requester;
node = options.node;
}
else {
query = options;
}
if (requester &&
typeof requester !== "string" &&
typeof requester !== "object") {
throw new Error('@Moonlink(Manager) - The "requester" option in the search function must be in string or array format');
}
if (source && typeof source !== "string") {
throw new Error("@Moonlink(Manager) - the source option has to be in string format");
}
if (typeof query !== "string" && typeof query !== "object") {
throw new Error("@Moonlink(Manager) - (search) the search option has to be in string or array format");
}
(node && (node = this.nodes.get(node))) ??
(node = this.nodes.sortByUsage("memory")[0]);
const sources = {
youtube: "ytsearch",
youtubemusic: "ytmsearch",
soundcloud: "scsearch"
};
let searchIdentifier = query.startsWith("http://") || query.startsWith("https://")
? query
: source
? sources[source]
? `${sources[source]}:${query}`
: `${source}:${query}`
: `ytsearch:${query}`;
const params = new URLSearchParams({
identifier: searchIdentifier
});
const res = await node.request("loadtracks", params);
if (["error", "empty"].includes(res.loadType)) {
this.emit("debug", "@Moonlink(Manager) - not found or there was an error loading the track");
return resolve(res);
}
if (["track"].includes(res.loadType)) {
res.data = [res.data];
}
if (["playlist"].includes(res.loadType)) {
res.playlistInfo = {
duration: res.data.tracks.reduce((acc, cur) => acc + cur.info.length, 0),
name: res.data.info.name,
selectedTrack: res.data.info.selectedTrack
};
res.pluginInfo = res.data.pluginInfo;
res.data = [...res.data.tracks];
}
const tracks = res.data.map(track => new (index_1.Structure.get("MoonlinkTrack"))(track, requester));
resolve({
...res,
tracks
});
}
catch (error) {
this.emit("debug", "@Moonlink(Manager) - An error occurred: " + error);
reject(error);
}
});
}
packetUpdate(packet) {
const { t, d } = packet;
if (!["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(t))
return;
const update = d;
const guildId = update.guild_id;
const player = this.players.get(guildId);
if (!update.token && !update.session_id)
return;
if (t === "VOICE_SERVER_UPDATE") {
this.players.handleVoiceServerUpdate(update, guildId);
}
if (t === "VOICE_STATE_UPDATE" && update.user_id === this.clientId) {
if (!player)
return;
if (!update.channel_id) {
this.players.handlePlayerDisconnect(guildId);
}
if (update.channel_id &&
update.channel_id !== player.voiceChannel) {
this.players.handlePlayerMove(update.channel_id, player.voiceChannel, guildId);
}
this.players.updateVoiceStates(guildId, update);
this.players.attemptConnection(guildId);
}
}
}
exports.MoonlinkManager = MoonlinkManager;

View File

@ -0,0 +1,19 @@
import { MoonlinkManager, MoonlinkNode, INode, SortType } from "../../index";
export declare class NodeManager {
initiated: boolean;
_manager: MoonlinkManager;
map: Map<any, any>;
constructor();
init(): void;
check(): void;
add(node: INode): void;
remove(name: string): boolean;
get(name: any): any;
sortByUsage(sortType: SortType): MoonlinkNode[];
private sortNodesByMemoryUsage;
private sortNodesByLavalinkCpuLoad;
private sortNodesBySystemCpuLoad;
private sortNodesByCalls;
private sortNodesByPlayingPlayers;
private sortNodesByPlayers;
}

View File

@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeManager = void 0;
const index_1 = require("../../index");
class NodeManager {
initiated = false;
_manager;
map;
constructor() {
this.map = new Map();
}
init() {
this._manager = index_1.Structure.manager;
this.check();
this._manager.emit("debug", "@Moonlink(Nodes) - Structure(Nodes) was successfully initialized and assigned the value of the main class and checked the nodes");
this.initiated = true;
}
check() {
if (!this._manager?._nodes)
throw new Error('@Moonlink(Nodes) - "nodes" option is empty');
if (this._manager?._nodes && !Array.isArray(this._manager?._nodes))
throw new Error('@Moonlink(Nodes) - the "nodes" option has to be in an array');
if (this._manager?._nodes && this._manager?._nodes.length == 0)
throw new Error('@Moonlink(Nodes) - there are no parameters with "node(s)" information in the object');
this._manager?._nodes.forEach(node => this.add(node));
}
add(node) {
this._manager.emit("debug", `@Moonlink(Nodes) - The node ${node.host || node.identifier} has been added, and is starting its initialization process`);
const NodeInstance = new (index_1.Structure.get("MoonlinkNode"))(node);
if (node.identifier)
this.map.set(node.identifier, NodeInstance);
else
this.map.set(node.host, NodeInstance);
return;
}
remove(name) {
if (!name) {
throw new Error('[ @Moonlink/Manager ]: option "name" is empty');
}
const removed = this.map.delete(name);
this._manager.emit("debug", `@Moonlink(Nodes) - The node ${name} has been successfully deleted`);
return removed;
}
get(name) {
return this.map.get(name) ? this.map.get(name) : null;
}
sortByUsage(sortType) {
this._manager.emit("debug", `@Moonlink(Nodes) - A new lavalink server is being drawn, sorting the type ${sortType}`);
const connectedNodes = [...this.map.values()].filter(node => node.state == "READY");
if (connectedNodes.length == 0)
throw new TypeError("[ @Moonlink/Manager ]: No lavalink server connected");
switch (sortType) {
case "memory":
return this.sortNodesByMemoryUsage(connectedNodes);
case "cpuLavalink":
return this.sortNodesByLavalinkCpuLoad(connectedNodes);
case "cpuSystem":
return this.sortNodesBySystemCpuLoad(connectedNodes);
case "calls":
return this.sortNodesByCalls(connectedNodes);
case "playingPlayers":
return this.sortNodesByPlayingPlayers(connectedNodes);
case "players":
default:
return this.sortNodesByPlayers(connectedNodes);
}
}
sortNodesByMemoryUsage(nodes) {
return nodes.sort((a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0));
}
sortNodesByLavalinkCpuLoad(nodes) {
return nodes.sort((a, b) => (a.stats?.cpu?.lavalinkLoad || 0) -
(b.stats?.cpu?.lavalinkLoad || 0));
}
sortNodesBySystemCpuLoad(nodes) {
return nodes.sort((a, b) => (a.stats?.cpu?.systemLoad || 0) -
(b.stats?.cpu?.systemLoad || 0));
}
sortNodesByCalls(nodes) {
return nodes.sort((a, b) => a.calls - b.calls);
}
sortNodesByPlayingPlayers(nodes) {
return nodes.sort((a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0));
}
sortNodesByPlayers(nodes) {
return nodes.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
}
}
exports.NodeManager = NodeManager;

View File

@ -0,0 +1,19 @@
import { MoonlinkPlayer, MoonlinkManager, createOptions } from "../../index";
export declare class PlayerManager {
_manager: MoonlinkManager;
cache: Record<string, MoonlinkPlayer>;
private voices;
constructor();
init(): void;
handleVoiceServerUpdate(update: any, guildId: string): void;
handlePlayerDisconnect(guildId: string): void;
handlePlayerMove(newChannelId: string, oldChannelId: string, guildId: string): void;
updateVoiceStates(guildId: string, update: any): void;
attemptConnection(guildId: string): Promise<boolean>;
has(guildId: string): boolean;
get(guildId: string): MoonlinkPlayer | null;
create(data: createOptions): MoonlinkPlayer;
get all(): Record<string, any> | null;
backup(player: any): boolean;
delete(guildId: any): void;
}

View File

@ -0,0 +1,160 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlayerManager = void 0;
const index_1 = require("../../index");
class PlayerManager {
_manager;
cache = {};
voices = {};
constructor() { }
init() {
this._manager = index_1.Structure.manager;
this._manager.emit("debug", "@Moonlink(Players) - Structure(Players) has been initialized, and assigned the value of the main class ");
}
handleVoiceServerUpdate(update, guildId) {
this.voices[guildId] = {
...this.voices[guildId],
endpoint: update.endpoint,
token: update.token
};
this.attemptConnection(guildId);
}
handlePlayerDisconnect(guildId) {
this._manager.emit("playerDisconnect", this.cache[guildId]);
this._manager.emit("debug", `@Moonlink(PlayerManager) - a player(${guildId}) was disconnected, issuing stop and resolving information`);
Object.assign(this.cache[guildId], {
connected: false,
voiceChannel: null,
playing: false
});
this.cache[guildId].stop();
}
handlePlayerMove(newChannelId, oldChannelId, guildId) {
this._manager.emit("playerMove", this.cache[guildId], newChannelId, oldChannelId);
this._manager.emit("debug", `@Moonlink(PlayerManager) - a player(${guildId}) was moved channel, resolving information`);
this.cache[guildId].voiceChannel = newChannelId;
if (this._manager.options.resume)
this.backup(this.cache[guildId]);
}
updateVoiceStates(guildId, update) {
this.voices[guildId] = {
...this.voices[guildId],
sessionId: update.session_id
};
}
async attemptConnection(guildId) {
if (!this.cache[guildId])
return false;
if (this.voices[guildId] &&
!this.voices[guildId]?.token &&
!this.voices[guildId]?.endpoint &&
!this.voices[guildId]?.sessionId)
return false;
if (this._manager.options?.balancingPlayersByRegion) {
const voiceRegion = this.voices[guildId]?.endpoint?.match(/([a-zA-Z-]+)\d+/)?.[1];
if (!this.cache[guildId].voiceRegion) {
const connectedNodes = [
...this._manager.nodes.map.values()
].filter(node => node.state == "READY");
const matchingNode = connectedNodes.find(node => node.regions.includes(voiceRegion));
this.cache[guildId].voiceRegion = voiceRegion;
if (matchingNode) {
this.cache[guildId].node = matchingNode;
}
}
}
else if (!this.cache[guildId].voiceRegion) {
const voiceRegion = this.voices[guildId]?.endpoint?.match(/([a-zA-Z-]+)\d+/)?.[1];
this.cache[guildId].voiceRegion = voiceRegion;
}
await this.cache[guildId].node.rest.update({
guildId,
data: {
voice: this.voices[guildId]
}
});
return true;
}
has(guildId) {
return !!this.cache[guildId];
}
get(guildId) {
if (!guildId && typeof guildId !== "string")
throw new Error('@Moonlink(PlayerManager) - "guildId" option in parameter to get player is empty or type is different from string');
if (!this.has(guildId))
return null;
return this.cache[guildId];
}
create(data) {
if (typeof data !== "object" ||
!data.guildId ||
typeof data.guildId !== "string" ||
!data.textChannel ||
typeof data.textChannel !== "string" ||
!data.voiceChannel ||
typeof data.voiceChannel !== "string" ||
(data.autoPlay !== undefined &&
typeof data.autoPlay !== "boolean") ||
(data.node && typeof data.node !== "string")) {
const missingParams = [];
if (!data.guildId || typeof data.guildId !== "string")
missingParams.push("guildId");
if (!data.textChannel || typeof data.textChannel !== "string")
missingParams.push("textChannel");
if (!data.voiceChannel || typeof data.voiceChannel !== "string")
missingParams.push("voiceChannel");
if (data.autoPlay !== undefined &&
typeof data.autoPlay !== "boolean")
missingParams.push("autoPlay");
if (data.node && typeof data.node !== "string")
missingParams.push("node");
throw new Error(`@Moonlink(PlayerManager) - Missing parameters for player creation: ${missingParams.join(", ")}`);
}
if (this.has(data.guildId))
return this.get(data.guildId);
let nodeSorted = this._manager.nodes.sortByUsage(`${this._manager.options.sortNode ?? "players"}`)[0];
data.node = nodeSorted.identifier ?? nodeSorted.host;
this._manager.emit("debug", `@Moonlink(Players) - A server player was created (${data.guildId})`);
this._manager.emit("playerCreated", data.guildId);
this.cache[data.guildId] = new (index_1.Structure.get("MoonlinkPlayer"))(data);
return this.cache[data.guildId];
}
get all() {
return this.cache ?? null;
}
backup(player) {
const playerData = {};
const playerKeys = Object.keys(player);
playerKeys.forEach(key => {
if ([
"guildId",
"voiceChannel",
"textChannel",
"volume",
"loop",
"autoPlay",
"autoLeave",
"data",
"previous"
].includes(key)) {
const value = index_1.Structure.db.get(`players.${player.guildId}.${key}`);
if (player[key] !== undefined &&
player[key] !== null &&
player[key] !== value) {
playerData[key] = player[key];
}
else if (value !== undefined && value !== null) {
playerData[key] = value;
}
}
});
index_1.Structure.db.set(`players.${player.guildId}`, playerData);
return true;
}
delete(guildId) {
delete this.cache[guildId];
if (index_1.Structure.db.get(`players.${guildId}`))
index_1.Structure.db.delete(`players.${guildId}`);
}
}
exports.PlayerManager = PlayerManager;

View File

@ -0,0 +1,7 @@
/// <reference types="node" />
/// <reference types="node" />
import * as http from "http";
import * as https from "https";
export declare function makeRequest<T>(uri: string, options: http.RequestOptions | (https.RequestOptions & {
method?: string;
}), data?: Record<string, any>): Promise<T>;

View File

@ -0,0 +1,128 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeRequest = void 0;
const http = __importStar(require("http"));
const https = __importStar(require("https"));
const http2 = __importStar(require("http2"));
const zlib = __importStar(require("zlib"));
const index_1 = require("../../index");
function makeRequest(uri, options, data) {
return new Promise(resolve => {
const url = new URL(uri);
if (index_1.Structure.manager.options.http2 === true) {
let client = http2.connect(url.origin, {
protocol: url.protocol === "https:" ? "https:" : "http:",
rejectUnauthorized: false
});
const reqOptions = {
":method": options.method,
":path": url.pathname + url.search,
"User-Agent": "Moonlink(Bot)",
"Content-Type": "application/json",
...(options.headers || {})
};
let chunks = "";
const req = client.request(reqOptions);
req.on("error", error => {
index_1.Structure.manager.emit("debug", `@Moonlink(MakeRequest[HTTP/2]) - An error occurred when requesting the ${url}: ${error}`);
client.close();
resolve(error);
});
req.on("response", headers => {
req.setEncoding("utf8");
req.on("data", chunk => (chunks += chunk));
req.on("end", () => {
client.close();
try {
const parsedData = JSON.parse(chunks);
resolve(parsedData);
}
catch (parseError) {
resolve(parseError);
}
});
req.on("error", error => {
index_1.Structure.manager.emit("debug", `@Moonlink(MakeRequest[HTTP/2]) - An error occurred when requesting the ${url}: ${error}`);
client.close();
resolve(error);
});
});
data ? req.end(JSON.stringify(data)) : req.end();
}
else {
let requestModule = http;
if (url.protocol === "https:") {
requestModule = https;
}
options.headers = {
"Content-Type": "application/json",
"Accept-Encoding": "br",
...(options.headers || {})
};
const reqOptions = {
host: url.hostname,
port: url.port
? parseInt(url.port)
: url.protocol === "https:"
? 443
: 80,
path: url.pathname + url.search,
method: options.method || "GET",
...options
};
const req = requestModule.request(url, reqOptions, async (res) => {
let newStream = res;
if (res.headers["content-encoding"] === "br") {
newStream = res.pipe(zlib.createBrotliDecompress());
}
const chunks = [];
newStream.on("data", async (chunk) => {
chunks.push(chunk);
});
newStream.on("end", async () => {
try {
const responseData = Buffer.concat(chunks).toString();
if (reqOptions.path == "/version")
resolve(responseData);
const parsedData = JSON.parse(responseData);
resolve(parsedData);
}
catch (err) {
resolve(err);
}
});
res.on("error", (err) => {
resolve(err);
});
});
if (data) {
req.write(JSON.stringify(data));
}
req.end();
}
});
}
exports.makeRequest = makeRequest;

View File

@ -0,0 +1,28 @@
import { MoonlinkManager, MoonlinkNode } from "../../index";
import { RestOptions, Endpoint } from "../@Typings";
export declare class MoonlinkRestFul {
manager: MoonlinkManager;
sessionId: string;
node: MoonlinkNode;
url: string;
constructor(node: MoonlinkNode);
setSessionId(sessionId: string): void;
update(data: RestOptions): Promise<Record<string, unknown>>;
destroy(guildId: string): Promise<Record<string, unknown>>;
get(endpoint: Endpoint): Promise<any>;
post(endpoint: Endpoint, data: RestOptions): Promise<Record<string, unknown>>;
patch(endpoint: Endpoint, data: RestOptions | any): Promise<Record<string, unknown>>;
delete(endpoint: Endpoint): Promise<Record<string, unknown>>;
decodeTrack(encodedTrack: string): Promise<Record<string, unknown>>;
decodeTracks(data: RestOptions): Promise<Record<string, unknown>>;
getInfo(): Promise<Record<string, unknown>>;
getStats(): Promise<Record<string, unknown>>;
getVersion(): Promise<any>;
routePlannerFreeAddress(data: RestOptions): Promise<Record<string, unknown>>;
routePlannerFreeAll(data: RestOptions): Promise<Record<string, unknown>>;
private ensureUrlIsSet;
private makeGetRequest;
private makePostRequest;
private makePatchRequest;
private makeDeleteRequest;
}

View File

@ -0,0 +1,112 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkRestFul = void 0;
const index_1 = require("../../index");
class MoonlinkRestFul {
manager;
sessionId;
node;
url;
constructor(node) {
this.manager = index_1.Structure.manager;
this.node = node;
}
setSessionId(sessionId) {
this.sessionId = sessionId;
this.ensureUrlIsSet();
}
async update(data) {
this.ensureUrlIsSet();
return this.makePatchRequest(`sessions/${this.sessionId}/players/${data.guildId}`, data.data);
}
async destroy(guildId) {
return this.makeDeleteRequest(`sessions/${this.sessionId}/players/${guildId}`);
}
async get(endpoint) {
this.ensureUrlIsSet();
return this.makeGetRequest(endpoint);
}
async post(endpoint, data) {
this.ensureUrlIsSet();
return this.makePostRequest(endpoint, data);
}
async patch(endpoint, data) {
this.ensureUrlIsSet();
return this.makePatchRequest(endpoint, data.data);
}
async delete(endpoint) {
this.ensureUrlIsSet();
return this.makeDeleteRequest(endpoint);
}
async decodeTrack(encodedTrack) {
return this.get(`decodetrack?encodedTrack=${encodedTrack}`);
}
async decodeTracks(data) {
return this.post("decodetracks", data);
}
async getInfo() {
return this.get("info");
}
async getStats() {
return this.get("stats");
}
async getVersion() {
const headers = {
Authorization: this.node.password
};
return (0, index_1.makeRequest)((this.node.secure
? "https://"
: "http://") + this.node.address + "/version", {
method: "GET",
headers
}).catch(err => err);
}
async routePlannerFreeAddress(data) {
return this.post("routeplanner/free/address", data);
}
async routePlannerFreeAll(data) {
return this.post("routeplanner/free/all", data);
}
ensureUrlIsSet() {
if (!this.url) {
this.url = this.node.http;
}
}
async makeGetRequest(endpoint) {
const headers = {
Authorization: this.node.password
};
return (0, index_1.makeRequest)(this.url + endpoint, {
method: "GET",
headers
}).catch(err => err);
}
async makePostRequest(endpoint, data) {
const headers = {
Authorization: this.node.password
};
return (0, index_1.makeRequest)(this.url + endpoint, {
method: "POST",
headers
}, data).catch(err => err);
}
async makePatchRequest(endpoint, data) {
const headers = {
Authorization: this.node.password
};
return (0, index_1.makeRequest)(this.url + endpoint, {
method: "PATCH",
headers
}, data).catch(err => err);
}
async makeDeleteRequest(endpoint) {
const headers = {
Authorization: this.node.password
};
return (0, index_1.makeRequest)(this.url + endpoint, {
method: "DELETE",
headers
}).catch(err => err);
}
}
exports.MoonlinkRestFul = MoonlinkRestFul;

View File

@ -0,0 +1,19 @@
/// <reference types="node" />
/// <reference types="node" />
import { EventEmitter } from "events";
export declare class MoonlinkWebSocket extends EventEmitter {
private url;
private options;
private socket;
private established;
private closing;
private headers?;
private partialMessage?;
constructor(uri: string, options: any);
private buildRequestOptions;
private buildHandshake;
connect(): void;
private parseFrame;
writeFrame(data: any): Buffer;
close(code?: number, reason?: string): void;
}

View File

@ -0,0 +1,243 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkWebSocket = void 0;
const http_1 = __importDefault(require("http"));
const https_1 = __importDefault(require("https"));
const crypto_1 = __importDefault(require("crypto"));
const events_1 = require("events");
class MoonlinkWebSocket extends events_1.EventEmitter {
url;
options;
socket;
established;
closing = false;
headers;
partialMessage = null;
constructor(uri, options) {
super();
this.url = new URL(uri);
this.options = {
port: this.url.port
? this.url.port
: this.url.protocol === "wss:"
? 443
: 80,
method: "GET",
protocol: this.url.protocol === "wss:" ? "https:" : "http:",
secure: this.url.protocol === "wss:",
...options
};
if (process.versions &&
process.versions.node &&
process.versions.node.match(/20\.[0-2]\.0/)) {
require("net").setDefaultAutoSelectFamily(false);
}
this.connect();
}
buildRequestOptions() {
const requestOptions = {
port: this.options.port,
headers: this.buildHandshake(this.options),
method: "GET",
keepAlive: true,
noDelay: true,
keepAliveInitialDelay: 0,
timeout: 0
};
return this.options.secure
? requestOptions
: { ...requestOptions, protocol: "http:" };
}
buildHandshake(options) {
const headers = { ...options.headers };
headers["Host"] = this.url.host;
headers["Upgrade"] = "websocket";
headers["Connection"] = "Upgrade";
headers["Sec-WebSocket-Key"] = crypto_1.default
.randomBytes(16)
.toString("base64");
headers["Sec-WebSocket-Version"] = "13";
return headers;
}
connect() {
const { request } = this.options.secure ? https_1.default : http_1.default;
const requestOptions = this.buildRequestOptions();
const req = request(`${this.options.secure ? "https://" : "http://"}${this.url.host}${this.url.pathname}${this.url.search || ""}`, requestOptions);
req.on("upgrade", (res, socket, head) => {
this.established = true;
this.socket = socket;
this.emit("open", this.socket);
if (res.headers.upgrade.toLowerCase() !== "websocket" ||
res.headers["sec-websocket-accept"] !==
crypto_1.default
.createHash("sha1")
.update(requestOptions.headers["Sec-WebSocket-Key"] +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
.digest("base64")) {
socket.destroy();
return;
}
if (head && head.length > 0)
socket.unshift(head);
this.headers = res.headers;
socket.on("data", data => {
const frame = this.parseFrame(data);
switch (frame.opcode) {
case 0: {
if (frame.fin) {
if (!this.partialMessage) {
this.partialMessage = frame.payload;
}
else {
this.partialMessage = Buffer.concat([
this.partialMessage,
frame.payload
]);
;
}
const message = this.partialMessage.toString("utf-8");
this.emit("message", message);
this.partialMessage = null;
}
else {
if (!this.partialMessage) {
this.partialMessage = frame.payload;
}
else {
this.partialMessage = Buffer.concat([
this.partialMessage,
frame.payload
]);
}
}
break;
}
case 1: {
if (frame.fin) {
this.emit("message", frame.payload.toString("utf-8"));
}
else {
this.partialMessage = frame.payload;
}
break;
}
case 8: {
const code = frame.payload.readUInt16BE(0);
const reason = frame.payload.slice(2).toString("utf8");
this.emit("close", code, reason);
break;
}
default: {
console.log("Emitted data that has not been implemented; opcode: " +
frame.opcode);
if (frame.payloadLength + frame.payloadOffset <
data.length) {
this.socket.unshift(data.slice(frame.payloadLength + frame.payloadOffset));
}
}
}
});
socket.on("close", hadError => {
if (hadError)
this.emit("error", hadError);
if (!this.closing)
this.emit("close");
});
socket.on("error", error => this.emit("error", error));
});
req.on("error", error => {
this.emit("error", error);
});
req.on("close", code => {
if (!this.established)
this.emit("close", code);
});
req.end();
}
parseFrame(data) {
const opcode = data[0] & 0x0f;
const fin = (data[0] & 0x80) === 0x80;
const mask = (data[1] & 0x80) === 0x80;
let payloadOffset = 2;
let payloadLength = data[1] & 0x7f;
if (payloadLength === 126) {
payloadLength = data.readUInt16BE(2);
payloadOffset += 2;
}
else if (payloadLength === 127) {
payloadLength = data.readUInt32BE(2);
payloadOffset += 8;
}
const maskingKey = mask
? data.slice(payloadOffset, payloadOffset + 4)
: null;
payloadOffset += mask ? 4 : 0;
const payload = data.slice(payloadOffset, payloadOffset + payloadLength);
if (mask && maskingKey) {
for (let i = 0; i < payload.length; i++) {
payload[i] ^= maskingKey[i % 4];
}
}
return {
opcode,
fin,
mask,
maskingKey,
payloadLength,
payloadOffset,
payload
};
}
writeFrame(data) {
const { fin, opcode, mask, payload } = data;
const header1 = (fin ? 128 : 0) | (opcode & 15);
const header2 = (mask ? 128 : 0) | (payload.length & 127);
let frame = Buffer.allocUnsafe(2);
frame.writeUInt8(header1, 0);
frame.writeUInt8(header2, 1);
if (payload.length > 125 && payload.length < 65535) {
let extendedFrame = Buffer.allocUnsafe(2);
extendedFrame.writeUInt16BE(payload.length, 0);
frame = Buffer.concat([frame, extendedFrame]);
}
else if (payload.length > 65535) {
let extendedFrame = Buffer.allocUnsafe(8);
extendedFrame.writeUInt32BE(0, 0);
extendedFrame.writeUInt32BE(payload.length, 4);
frame = Buffer.concat([frame, extendedFrame]);
}
if (mask) {
let maskingKey = Buffer.from([
Math.floor(Math.random() * 256),
Math.floor(Math.random() * 256),
Math.floor(Math.random() * 256),
Math.floor(Math.random() * 256)
]);
frame = Buffer.concat([frame, maskingKey]);
for (let i = 0; i < payload.length; i++) {
payload[i] ^= maskingKey[i % 4];
}
}
frame = Buffer.concat([frame, payload]);
return frame;
}
close(code = 1000, reason = "normal closing") {
if (this.socket && this.established) {
this.closing = true;
const buffer = Buffer.alloc(2 + Buffer.byteLength(reason));
buffer.writeUInt16BE(code, 0);
buffer.write(reason, 2, Buffer.byteLength(reason), "utf-8");
let frame = this.writeFrame({
fin: true,
opcode: 8,
mask: false,
payload: buffer
});
this.socket.write(frame);
}
}
}
exports.MoonlinkWebSocket = MoonlinkWebSocket;

267
node_modules/moonlink.js/dist/src/@Typings/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,267 @@
import { MoonlinkManager, MoonlinkPlayer, MoonlinkFilters, MoonlinkDatabase, MoonlinkRestFul, MoonlinkQueue, MoonlinkNode, MoonlinkTrack, PlayerManager, NodeManager, Plugin } from "../../index";
export type Constructor<T> = new (...args: any[]) => T;
export interface createOptions {
guildId: string;
textChannel: string;
voiceChannel: string;
autoPlay?: boolean;
autoLeave?: boolean;
notBackup?: boolean;
loop?: number;
volume?: number;
node?: string;
}
export type SortType = "memory" | "cpuLavalink" | "cpuSystem" | "calls" | "playingPlayers" | "players";
export interface VoiceState {
op: "voiceUpdate";
guildId: string;
event: VoiceServer;
sessionId?: string;
}
export interface VoiceServer {
token: string;
guild_id: string;
endpoint: string;
}
export interface VoiceState {
guild_id: string;
user_id: string;
session_id: string;
channel_id: string;
}
export interface VoicePacket {
t?: "VOICE_SERVER_UPDATE" | "VOICE_STATE_UPDATE";
d: VoiceState | VoiceServer;
}
export type LoadType = "track" | "playlist" | "search" | "empty" | "error";
export interface TrackData {
encoded?: string;
info: TrackDataInfo;
pluginInfo: object;
}
export interface TrackDataInfo {
title: string;
identifier: string;
author: string;
length: number;
position: number;
isSeekable: boolean;
isStream: boolean;
uri: string;
}
export type SearchPlatform = "youtube" | "youtubemusic" | "soundcloud" | string;
export interface SearchQuery {
source?: SearchPlatform | string | undefined | null;
query: string | string[];
requester?: string | object | any;
node?: string;
}
export interface SearchResult {
loadType: LoadType;
tracks: MoonlinkTrack[];
playlistInfo?: PlaylistInfo;
exception?: {
message: string;
severity: string;
};
}
export interface INodeStats {
players: number;
playingPlayers: number;
uptime: number;
memory: {
reservable: number;
used: number;
free: number;
allocated: number;
};
frameStats: {
sent: number;
deficit: number;
nulled: number;
};
cpu: {
cores: number;
systemLoad: number;
lavalinkLoad: number;
};
}
export interface INode {
host: string;
identifier?: string;
password: string;
port: number;
secure: boolean;
regions?: string[];
retryAmount?: number;
retryDelay?: number;
sessionId?: string;
}
export interface IOptions {
clientId?: string;
clientName?: string;
sortNode?: SortType;
autoResume?: boolean;
resume?: boolean;
plugins?: Plugin[];
http2?: boolean;
doNotSaveToFiles?: boolean;
switchPlayersAnotherNode?: boolean;
destroyPlayersStopped?: boolean;
balancingPlayersByRegion?: boolean;
previousTracksInArray?: boolean;
}
export interface IHeaders {
Authorization: string;
"User-Id": string;
"Client-Name": string;
}
export interface Extendable {
MoonlinkManager: typeof MoonlinkManager;
MoonlinkPlayer: typeof MoonlinkPlayer;
MoonlinkDatabase: typeof MoonlinkDatabase;
MoonlinkFilters: typeof MoonlinkFilters;
MoonlinkRestFul: typeof MoonlinkRestFul;
MoonlinkQueue: typeof MoonlinkQueue;
MoonlinkNode: typeof MoonlinkNode;
MoonlinkTrack: typeof MoonlinkTrack;
PlayerManager: typeof PlayerManager;
NodeManager: typeof NodeManager;
}
export interface PlaylistInfo {
name: string;
selectedTrack?: MoonlinkTrack;
duration: number;
}
export interface LavalinkResult {
data: TrackData[];
loadType: LoadType;
exception?: {
message: string;
severity: string;
};
playlistInfo: {
name: string;
selectedTrack?: number;
};
}
export interface VoiceOptions {
endpoint: string;
token: string;
sessionId: string;
connected?: boolean;
ping?: number;
}
export type Endpoint = string;
export interface objectTrack {
encoded: string;
}
export interface PreviousInfosPlayer {
voiceChannel?: string;
textChannel?: string;
guildId?: string;
volume?: number;
autoPlay?: boolean;
autoLeave?: boolean;
previous?: object | MoonlinkTrack;
loop?: number;
current?: Record<string, any>;
}
export interface RestOptions {
guildId: string;
data: {
track?: objectTrack;
identifier?: string;
startTime?: number;
endTime?: number;
volume?: number;
position?: number;
paused?: Boolean;
filters?: Object;
voice?: VoiceOptions;
};
}
export interface connectOptions {
setMute?: boolean;
setDeaf?: boolean;
}
export interface IPlayerData {
guildId: string;
textChannel: string | null;
voiceChannel: string | null;
voiceRegion?: string | null;
autoPlay?: boolean | null;
autoLeave?: boolean | null;
connected?: boolean | null;
playing?: boolean | null;
paused?: boolean | null;
shuffled?: boolean | null;
loop?: number | null;
volume?: number | null;
notBackup?: boolean;
ping?: number;
node?: string;
}
export interface TrackInfo {
identifier: string;
isSeekable: boolean;
author: string;
isStream: boolean;
length: number;
position: number;
title: string;
uri?: string;
artworkUrl?: string;
sourceName: string;
isrc?: string;
}
export interface MoonlinkTrackOptions {
info: TrackInfo;
encoded?: string;
pluginInfo?: object;
}
export interface Equalizer {
band: number;
gain: number;
}
export interface Karaoke {
level?: number;
monoLevel?: number;
filterBand?: number;
filterWidth?: number;
}
export interface Timescale {
speed?: number;
pitch?: number;
rate?: number;
}
export interface Tremolo {
frequency?: number;
depth?: number;
}
export interface Vibrato {
frequency?: number;
depth?: number;
}
export interface Rotation {
rotationHz?: number;
}
export interface Distortion {
sinOffset?: number;
sinScale?: number;
cosOffset?: number;
cosScale?: number;
tanOffset?: number;
tanScale?: number;
offset?: number;
scale?: number;
}
export interface ChannelMix {
leftToLeft?: number;
leftToRight?: number;
rightToLeft?: number;
rightToRight?: number;
}
export interface LowPass {
smoothing?: number;
}

2
node_modules/moonlink.js/dist/src/@Typings/index.js generated vendored Normal file
View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -0,0 +1,15 @@
type Data = Record<string, any>;
export declare class MoonlinkDatabase {
data: Data;
id: string;
constructor(clientId: string);
set<T>(key: string, value: T): void;
get<T>(key: string): T | undefined;
push<T>(key: string, value: T): void;
delete(key: string): boolean;
private updateData;
private getFilePath;
fetch(): void;
private save;
}
export {};

View File

@ -0,0 +1,113 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkDatabase = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
class MoonlinkDatabase {
data = {};
id;
constructor(clientId) {
this.fetch();
this.id = clientId;
}
set(key, value) {
if (!key)
throw new Error('@Moonlink(Database) - "key" is empty');
const keys = key.split(".");
if (keys.length === 0)
return;
this.updateData(this.data, keys, value);
this.save();
}
get(key) {
if (!key)
throw new Error('[ @Moonlink(Database) - "key" is empty');
if (Object.keys(this.data).length === 0)
this.fetch();
return (key.split(".").reduce((acc, curr) => acc?.[curr], this.data) ?? null);
}
push(key, value) {
if (!key)
throw new Error('@Moonlink(Database) - "key" is empty');
const oldArray = this.get(key) || [];
if (Array.isArray(oldArray)) {
oldArray.push(value);
this.set(key, oldArray);
}
else {
throw new Error("@Moonlink(Database) - Key does not point to an array");
}
}
delete(key) {
if (!key)
throw new Error('@Moonlink(Database) - "key" is empty');
const keys = key.split(".");
if (keys.length === 0)
return false;
const lastKey = keys.pop() || "";
let currentObj = this.data;
keys.forEach(k => {
if (typeof currentObj[k] === "object") {
currentObj = currentObj[k];
}
else {
throw new Error(`@Moonlink(Database) - Key path "${key}" does not exist`);
}
});
if (currentObj && lastKey in currentObj) {
delete currentObj[lastKey];
this.save();
return true;
}
return false;
}
updateData(data, keys, value) {
let currentObj = data;
keys.forEach((key, index) => {
if (index === keys.length - 1) {
currentObj[key] = value;
}
else {
if (typeof currentObj[key] !== "object") {
currentObj[key] = {};
}
currentObj = currentObj[key];
}
});
}
getFilePath() {
return path_1.default.join(__dirname, "../@Datastore", `database-${this.id}.json`);
}
fetch() {
try {
const directory = path_1.default.join(__dirname, "../@Datastore");
if (!fs_1.default.existsSync(directory)) {
fs_1.default.mkdirSync(directory, { recursive: true });
}
const filePath = this.getFilePath();
const rawData = fs_1.default.readFileSync(filePath, "utf-8");
this.data = JSON.parse(rawData) || {};
}
catch (err) {
if (err.code === "ENOENT") {
this.data = {};
}
else {
throw new Error("@Moonlink(Database) - Failed to fetch data (Error):", err);
}
}
}
save() {
try {
const filePath = this.getFilePath();
fs_1.default.writeFileSync(filePath, JSON.stringify(this.data, null, 2));
}
catch (error) {
throw new Error("@Moonlink(Database) - Failed to save data");
}
}
}
exports.MoonlinkDatabase = MoonlinkDatabase;

View File

@ -0,0 +1,29 @@
import { Equalizer, Karaoke, Timescale, Tremolo, Vibrato, Rotation, Distortion, ChannelMix, LowPass } from "../@Typings";
export declare class MoonlinkFilters {
private player;
private manager;
private rest;
volume: number | null;
equalizer: Equalizer[] | null;
karaoke: Karaoke | null;
timescale: Timescale | null;
tremolo: Tremolo | null;
vibrato: Vibrato | null;
rotation: Rotation | null;
distortion: Distortion | null;
channelMix: ChannelMix | null;
lowPass: LowPass | null;
constructor(player: any);
setVolume(volume: number | null): this;
setEqualizer(equalizer: Equalizer[] | null): this;
setKaraoke(karaoke: Karaoke | null): this;
setTimescale(timescale: Timescale | null): this;
setTremolo(tremolo: Tremolo | null): this;
setVibrato(vibrato: Vibrato | null): this;
setRotation(rotation: Rotation | null): this;
setDistortion(distortion: Distortion | null): this;
setChannelMix(channelMix: ChannelMix | null): this;
setLowPass(lowPass: LowPass | null): this;
resetFilters(): this;
private updateFiltersFromRest;
}

View File

@ -0,0 +1,131 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkFilters = void 0;
const index_1 = require("../../index");
class MoonlinkFilters {
player;
manager;
rest;
volume;
equalizer;
karaoke;
timescale;
tremolo;
vibrato;
rotation;
distortion;
channelMix;
lowPass;
constructor(player) {
this.player = player;
this.rest = player.node.rest;
this.manager = index_1.Structure.manager;
this.volume = this.player.get("Fvolume") || null;
this.equalizer = this.player.get("equalizer") || null;
this.karaoke = this.player.get("karaoke") || null;
this.timescale = this.player.get("timescale") || null;
this.tremolo = this.player.get("tremolo") || null;
this.vibrato = this.player.get("vibrato") || null;
this.rotation = this.player.get("rotation") || null;
this.distortion = this.player.get("distortion") || null;
this.channelMix = this.player.get("channelMix") || null;
this.lowPass = this.player.get("lowPass") || null;
}
setVolume(volume) {
this.player.set("Fvolume", volume);
this.volume = volume;
this.updateFiltersFromRest();
return this;
}
setEqualizer(equalizer) {
this.player.set("equalizer", equalizer);
this.equalizer = equalizer;
this.updateFiltersFromRest();
return this;
}
setKaraoke(karaoke) {
this.player.set("karaoke", karaoke);
this.karaoke = karaoke;
this.updateFiltersFromRest();
return this;
}
setTimescale(timescale) {
this.player.set("timescale", timescale);
this.timescale = timescale;
this.updateFiltersFromRest();
return this;
}
setTremolo(tremolo) {
this.player.set("tremolo", tremolo);
this.tremolo = tremolo;
this.updateFiltersFromRest();
return this;
}
setVibrato(vibrato) {
this.player.set("vibrato", vibrato);
this.vibrato = vibrato;
this.updateFiltersFromRest();
return this;
}
setRotation(rotation) {
this.player.set("rotation", rotation);
this.rotation = rotation;
this.updateFiltersFromRest();
return this;
}
setDistortion(distortion) {
this.player.set("distortion", distortion);
this.distortion = distortion;
this.updateFiltersFromRest();
return this;
}
setChannelMix(channelMix) {
this.player.set("channelMix", channelMix);
this.channelMix = channelMix;
this.updateFiltersFromRest();
return this;
}
setLowPass(lowPass) {
this.player.set("lowPass", lowPass);
this.lowPass = lowPass;
this.updateFiltersFromRest();
return this;
}
resetFilters() {
this.setVolume(null);
this.setEqualizer(null);
this.setKaraoke(null);
this.setTimescale(null);
this.setTremolo(null);
this.setVibrato(null);
this.setRotation(null);
this.setDistortion(null);
this.setChannelMix(null);
this.setLowPass(null);
this.updateFiltersFromRest();
return this;
}
async updateFiltersFromRest() {
let { volume, equalizer, karaoke, timescale, tremolo, vibrato, rotation, distortion, channelMix, lowPass } = this;
const dataToUpdate = {
guildId: this.player.guildId,
data: {
filters: {
...(volume !== null && { volume }),
...(equalizer !== null && { equalizer }),
...(karaoke !== null && { karaoke }),
...(timescale !== null && { timescale }),
...(tremolo !== null && { tremolo }),
...(vibrato !== null && { vibrato }),
...(rotation !== null && { rotation }),
...(distortion !== null && { distortion }),
...(channelMix !== null && { channelMix }),
...(lowPass !== null && { lowPass })
}
}
};
await this.rest.update(dataToUpdate);
return true;
}
}
exports.MoonlinkFilters = MoonlinkFilters;

View File

@ -0,0 +1,20 @@
import { MoonlinkTrackOptions } from "../@Typings";
export declare class MoonlinkTrack {
encoded: string | null;
identifier: string;
title: string;
author: string;
url: string;
duration: number;
position: number;
isSeekable: boolean;
isStream: boolean;
sourceName: string;
requester: any;
artworkUrl: string;
isrc: string;
time?: number;
constructor(data?: MoonlinkTrackOptions, requester?: string | any);
get calculateRealTimePosition(): number;
setRequester(data: any): void;
}

View File

@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoonlinkTrack = void 0;
class MoonlinkTrack {
encoded;
identifier;
title;
author;
url;
duration;
position;
isSeekable;
isStream;
sourceName;
requester;
artworkUrl;
isrc;
time = 0;
constructor(data, requester) {
this.encoded = data.encoded;
this.title = data.info.title;
this.author = data.info.author;
this.url = data.info.uri;
this.duration = data.info.length;
this.position = data.info.position;
this.identifier = data.info.identifier;
this.isSeekable = Boolean(data.info.isSeekable);
this.isStream = Boolean(data.info.isStream);
this.sourceName = data.info.sourceName || null;
this.requester = requester;
this.artworkUrl = data.info.artworkUrl;
this.isrc = data.info.isrc;
}
get calculateRealTimePosition() {
if (this.position >= this.duration) {
return this.duration;
}
if (this.time) {
const elapsed = Date.now() - this.time;
const calculatedPosition = this.position + elapsed / 1000;
if (calculatedPosition >= this.duration) {
return this.duration;
}
return calculatedPosition;
}
return this.position;
}
setRequester(data) {
this.requester = data;
}
}
exports.MoonlinkTrack = MoonlinkTrack;

View File

@ -0,0 +1,13 @@
import { Extendable } from "../@Typings";
import { MoonlinkManager, MoonlinkDatabase } from "../../index";
export declare abstract class Structure {
static manager: MoonlinkManager;
static db: MoonlinkDatabase;
static extend<K extends keyof Extendable, T extends Extendable[K]>(name: K, extender: (target: Extendable[K]) => T): T;
static init(manager: MoonlinkManager): void;
static get<K extends keyof Extendable>(name: K): Extendable[K];
}
export declare class Plugin {
load(manager: MoonlinkManager): void;
unload(manager: MoonlinkManager): void;
}

46
node_modules/moonlink.js/dist/src/@Utils/Structure.js generated vendored Normal file
View File

@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Plugin = exports.Structure = void 0;
const index_1 = require("../../index");
const structures = {
MoonlinkManager: index_1.MoonlinkManager,
MoonlinkRestFul: index_1.MoonlinkRestFul,
MoonlinkPlayer: index_1.MoonlinkPlayer,
MoonlinkFilters: index_1.MoonlinkFilters,
MoonlinkDatabase: index_1.MoonlinkDatabase,
MoonlinkQueue: index_1.MoonlinkQueue,
MoonlinkNode: index_1.MoonlinkNode,
MoonlinkTrack: index_1.MoonlinkTrack,
PlayerManager: index_1.PlayerManager,
NodeManager: index_1.NodeManager
};
class Structure {
static manager;
static db;
static extend(name, extender) {
if (!(name in structures)) {
throw new TypeError(`"${name}" is not a valid structure`);
}
const extended = extender(structures[name]);
structures[name] = extended;
return extended;
}
static init(manager) {
this.manager = manager;
this.db = new (Structure.get("MoonlinkDatabase"))(manager.clientId);
this.manager.emit("debug", `@Moonlink(Structure) - The main class and database are assigned to structure :)`);
}
static get(name) {
const structure = structures[name];
if (!structure) {
throw new TypeError(`"${name}" structure must be provided.`);
}
return structure;
}
}
exports.Structure = Structure;
class Plugin {
load(manager) { }
unload(manager) { }
}
exports.Plugin = Plugin;