@ramkrishna-js/framelink 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ramkrishna
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ <div align="center">
2
+
3
+ <img src="https://capsule-render.vercel.app/render?type=waving&color=auto&height=250&section=header&text=FrameLink&fontSize=90&animation=fadeIn&fontAlignY=38" />
4
+
5
+ **🚀 A lightweight, robust, and plugin-ready Lavalink client (v3 & v4) for Node.js.**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/framelink.svg?style=flat-square)](https://www.npmjs.com/package/framelink)
8
+ [![npm downloads](https://img.shields.io/npm/dm/framelink.svg?style=flat-square)](https://www.npmjs.com/package/framelink)
9
+ [![license](https://img.shields.io/github/license/ramkrishna-js/framelink.svg?style=flat-square)](https://github.com/ramkrishna-js/framelink/blob/master/LICENSE)
10
+ [![stars](https://img.shields.io/github/stars/ramkrishna-js/framelink.svg?style=flat-square)](https://github.com/ramkrishna-js/framelink/stargazers)
11
+
12
+ ---
13
+
14
+ [📄 Documentation](https://github.com/ramkrishna-js/framelink#readme) | [💬 Discord Support](https://discord.gg/your-invite-link) | [📦 NPM](https://www.npmjs.com/package/framelink)
15
+
16
+ </div>
17
+
18
+ <hr />
19
+
20
+ ## ✨ Features
21
+ - 🎵 **Universal Support:** Seamlessly works with Lavalink v3 and v4.
22
+ - 🎼 **Multi-Platform:** Built-in support for YouTube, Spotify, Apple Music, Deezer, and more.
23
+ - 🚀 **Performance:** Optimized for speed with minimal memory footprint.
24
+ - 🔄 **Smart Queue:** Advanced queue system with automated autoplay logic.
25
+ - 🧩 **Extensible:** Robust plugin system to customize your experience.
26
+ - 🛡️ **Type-Safe:** Written entirely in TypeScript for a superior DX.
27
+
28
+ <hr />
29
+
30
+ ## 📦 Installation
31
+
32
+ ```bash
33
+ npm install framelink
34
+ ```
35
+
36
+ <hr />
37
+
38
+ ## ╰┈1️⃣ Quick Start
39
+
40
+ ### Initializing the Manager
41
+
42
+ ```typescript
43
+ import { LavalinkManager } from 'framelink';
44
+
45
+ const manager = new LavalinkManager({
46
+ nodes: [
47
+ {
48
+ host: 'localhost',
49
+ port: 2333,
50
+ password: 'youshallnotpass',
51
+ version: 'v4' // or 'v3'
52
+ }
53
+ ],
54
+ send: (guildId, payload) => {
55
+ // Your library's send logic (Discord.js, Eris, etc.)
56
+ }
57
+ });
58
+
59
+ manager.init('YOUR_BOT_ID');
60
+ ```
61
+
62
+ ### Creating a Player & Playing
63
+
64
+ ```typescript
65
+ const player = manager.createPlayer({
66
+ guildId: 'GUILD_ID',
67
+ voiceChannelId: 'VOICE_CHANNEL_ID',
68
+ textChannelId: 'TEXT_CHANNEL_ID',
69
+ autoplay: true
70
+ });
71
+
72
+ // Search for a track
73
+ const res = await manager.search('Never Gonna Give You Up', 'yt');
74
+
75
+ // Add to queue and play
76
+ player.queue.add(res.tracks[0]);
77
+ player.play();
78
+ ```
79
+
80
+ <hr />
81
+
82
+ ## ╰┈2️⃣ Event Handling
83
+
84
+ ```typescript
85
+ manager.on('nodeConnect', (node) => {
86
+ console.log(`Node ${node.options.host} connected!`);
87
+ });
88
+
89
+ manager.on('trackStart', (player, track) => {
90
+ console.log(`Now playing: ${track.info.title}`);
91
+ });
92
+
93
+ manager.on('queueEnd', (player) => {
94
+ console.log(`Queue ended for guild ${player.guildId}`);
95
+ });
96
+ ```
97
+
98
+ <hr />
99
+
100
+ ## ╰┈3️⃣ Supported Platforms
101
+
102
+ FrameLink supports any platform compatible with Lavalink and its plugins (like LavaSrc):
103
+ - YouTube / YouTube Music
104
+ - Spotify
105
+ - Apple Music
106
+ - Deezer
107
+ - SoundCloud
108
+ - Twitch
109
+ - HTTP Links
110
+
111
+ <hr />
112
+
113
+ ## 🧩 Plugins
114
+
115
+ FrameLink is built with extensibility in mind. You can easily create and load plugins to extend the manager's functionality.
116
+
117
+ ```typescript
118
+ import { Plugin } from 'framelink';
119
+
120
+ class MyCustomPlugin extends Plugin {
121
+ name = 'MyPlugin';
122
+ load(manager) {
123
+ super.load(manager);
124
+ console.log('Plugin loaded!');
125
+ }
126
+ unload() {}
127
+ }
128
+
129
+ const manager = new LavalinkManager({
130
+ // ... other options
131
+ plugins: [new MyCustomPlugin()]
132
+ });
133
+ ```
134
+
135
+ <hr />
136
+
137
+ ## 🤝 Contributing
138
+
139
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
140
+
141
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
142
+
143
+ <hr />
144
+
145
+ ## 📜 License
146
+
147
+ Distributed under the MIT License. See [LICENSE](LICENSE) for more information.
148
+
149
+ <hr />
150
+
151
+ <div align="center">
152
+
153
+ Built with ❤️ by [Ramkrishna](https://github.com/ramkrishna-js)
154
+
155
+ </div>
@@ -0,0 +1,6 @@
1
+ export * from './structures/LavalinkManager';
2
+ export * from './structures/LavalinkNode';
3
+ export * from './structures/Player';
4
+ export * from './structures/Queue';
5
+ export * from './structures/Plugin';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./structures/LavalinkManager"), exports);
18
+ __exportStar(require("./structures/LavalinkNode"), exports);
19
+ __exportStar(require("./structures/Player"), exports);
20
+ __exportStar(require("./structures/Queue"), exports);
21
+ __exportStar(require("./structures/Plugin"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+DAA6C;AAC7C,4DAA0C;AAC1C,sDAAoC;AACpC,qDAAmC;AACnC,sDAAoC"}
@@ -0,0 +1,32 @@
1
+ import { EventEmitter } from 'events';
2
+ import { LavalinkNode, NodeOptions } from './LavalinkNode';
3
+ import { Player, PlayerOptions } from './Player';
4
+ import { Plugin } from './Plugin';
5
+ export interface LavalinkManagerOptions {
6
+ nodes: NodeOptions[];
7
+ send: (guildId: string, payload: any) => void;
8
+ autoResume?: boolean;
9
+ plugins?: Plugin[];
10
+ }
11
+ export declare class LavalinkManager extends EventEmitter {
12
+ nodes: Map<string, LavalinkNode>;
13
+ players: Map<string, Player>;
14
+ options: LavalinkManagerOptions;
15
+ userId: string | null;
16
+ plugins: Plugin[];
17
+ constructor(options: LavalinkManagerOptions);
18
+ init(userId: string): void;
19
+ createNode(options: NodeOptions): LavalinkNode;
20
+ createPlayer(options: PlayerOptions): Player;
21
+ destroyPlayer(guildId: string): boolean;
22
+ getBestNode(): LavalinkNode | undefined;
23
+ /**
24
+ * Search for tracks using a specific source or default.
25
+ * @param query The search query.
26
+ * @param source The source prefix (e.g., 'yt', 'sc', 'sp'). Defaults to 'yt'.
27
+ * @returns The load result.
28
+ */
29
+ search(query: string, source?: 'yt' | 'ytm' | 'sc' | 'sp' | 'am' | 'dz' | string): Promise<any>;
30
+ handleVoiceUpdate(update: any): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=LavalinkManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LavalinkManager.d.ts","sourceRoot":"","sources":["../../src/structures/LavalinkManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,WAAW,sBAAsB;IACnC,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,qBAAa,eAAgB,SAAQ,YAAY;IACtC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,sBAAsB,CAAC;IAChC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAM;gBAElB,OAAO,EAAE,sBAAsB;IAWpC,IAAI,CAAC,MAAM,EAAE,MAAM;IAOnB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY;IAO9C,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM;IAS5C,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IASvC,WAAW,IAAI,YAAY,GAAG,SAAS;IAS9C;;;;;OAKG;IACU,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAa;IAYtF,iBAAiB,CAAC,MAAM,EAAE,GAAG;CAgC7C"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LavalinkManager = void 0;
4
+ const events_1 = require("events");
5
+ const LavalinkNode_1 = require("./LavalinkNode");
6
+ const Player_1 = require("./Player");
7
+ class LavalinkManager extends events_1.EventEmitter {
8
+ constructor(options) {
9
+ super();
10
+ this.userId = null;
11
+ this.plugins = [];
12
+ this.options = options;
13
+ this.nodes = new Map();
14
+ this.players = new Map();
15
+ if (options.plugins) {
16
+ this.plugins = options.plugins;
17
+ this.plugins.forEach(p => p.load(this));
18
+ }
19
+ }
20
+ init(userId) {
21
+ this.userId = userId;
22
+ this.options.nodes.forEach(nodeOptions => {
23
+ this.createNode(nodeOptions);
24
+ });
25
+ }
26
+ createNode(options) {
27
+ const node = new LavalinkNode_1.LavalinkNode(this, options);
28
+ this.nodes.set(options.id || options.host, node);
29
+ node.connect();
30
+ return node;
31
+ }
32
+ createPlayer(options) {
33
+ const node = this.getBestNode();
34
+ if (!node)
35
+ throw new Error("No available nodes.");
36
+ const player = new Player_1.Player(this, node, options);
37
+ this.players.set(options.guildId, player);
38
+ return player;
39
+ }
40
+ destroyPlayer(guildId) {
41
+ const player = this.players.get(guildId);
42
+ if (!player)
43
+ return false;
44
+ player.destroy();
45
+ this.players.delete(guildId);
46
+ return true;
47
+ }
48
+ getBestNode() {
49
+ // Simple strategy: return first connected node
50
+ // In future: load balancing
51
+ for (const node of this.nodes.values()) {
52
+ if (node.connected)
53
+ return node;
54
+ }
55
+ return undefined;
56
+ }
57
+ /**
58
+ * Search for tracks using a specific source or default.
59
+ * @param query The search query.
60
+ * @param source The source prefix (e.g., 'yt', 'sc', 'sp'). Defaults to 'yt'.
61
+ * @returns The load result.
62
+ */
63
+ async search(query, source = 'yt') {
64
+ const node = this.getBestNode();
65
+ if (!node)
66
+ throw new Error("No available nodes.");
67
+ const identifier = /^(https?:\/\/)/.test(query)
68
+ ? query
69
+ : `${source}search:${query}`;
70
+ return node.loadTracks(identifier);
71
+ }
72
+ // Handle voice state updates from Discord
73
+ async handleVoiceUpdate(update) {
74
+ if (!['VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE'].includes(update.t))
75
+ return;
76
+ const data = update.d;
77
+ const guildId = data.guild_id;
78
+ if (!guildId)
79
+ return;
80
+ const player = this.players.get(guildId);
81
+ if (!player)
82
+ return;
83
+ if (update.t === 'VOICE_SERVER_UPDATE') {
84
+ player.voiceUpdateState.event = data;
85
+ }
86
+ else {
87
+ if (data.user_id !== this.userId)
88
+ return;
89
+ player.voiceUpdateState.sessionId = data.session_id;
90
+ if (data.channel_id) {
91
+ player.voiceChannelId = data.channel_id;
92
+ }
93
+ }
94
+ if (player.voiceUpdateState.sessionId && player.voiceUpdateState.event) {
95
+ player.node.send({
96
+ op: 'voiceUpdate',
97
+ guildId: guildId,
98
+ sessionId: player.voiceUpdateState.sessionId,
99
+ event: player.voiceUpdateState.event
100
+ });
101
+ // Clear after sending? Usually Lavalink handles it.
102
+ // Some libs keep it for reconnection. Let's keep it.
103
+ }
104
+ }
105
+ }
106
+ exports.LavalinkManager = LavalinkManager;
107
+ //# sourceMappingURL=LavalinkManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LavalinkManager.js","sourceRoot":"","sources":["../../src/structures/LavalinkManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import WebSocket from 'ws';
2
+ import { LavalinkManager } from './LavalinkManager';
3
+ export interface NodeOptions {
4
+ id?: string;
5
+ host: string;
6
+ port?: number;
7
+ password?: string;
8
+ secure?: boolean;
9
+ retryAmount?: number;
10
+ retryDelay?: number;
11
+ version?: 'v3' | 'v4';
12
+ }
13
+ export declare class LavalinkNode {
14
+ manager: LavalinkManager;
15
+ options: NodeOptions;
16
+ socket: WebSocket | null;
17
+ stats: any;
18
+ connected: boolean;
19
+ constructor(manager: LavalinkManager, options: NodeOptions);
20
+ connect(): void;
21
+ send(payload: any): void;
22
+ loadTracks(identifier: string): Promise<any>;
23
+ private onOpen;
24
+ private onMessage;
25
+ private handleEvent;
26
+ private onError;
27
+ private onClose;
28
+ }
29
+ //# sourceMappingURL=LavalinkNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LavalinkNode.d.ts","sourceRoot":"","sources":["../../src/structures/LavalinkNode.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,WAAW;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED,qBAAa,YAAY;IACd,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;IAChC,KAAK,EAAE,GAAG,CAAM;IAChB,SAAS,EAAE,OAAO,CAAS;gBAEtB,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW;IAQnD,OAAO;IA0BP,IAAI,CAAC,OAAO,EAAE,GAAG;IAKX,UAAU,CAAC,UAAU,EAAE,MAAM;IAoB1C,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;CAKlB"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LavalinkNode = void 0;
7
+ const ws_1 = __importDefault(require("ws"));
8
+ class LavalinkNode {
9
+ constructor(manager, options) {
10
+ this.socket = null;
11
+ this.stats = {};
12
+ this.connected = false;
13
+ this.manager = manager;
14
+ this.options = {
15
+ version: 'v4',
16
+ ...options
17
+ };
18
+ }
19
+ connect() {
20
+ if (this.socket)
21
+ return;
22
+ const headers = {
23
+ Authorization: this.options.password || 'youshallnotpass',
24
+ 'User-Id': this.manager.userId || '0',
25
+ 'Client-Name': 'framelink/1.0.0'
26
+ };
27
+ const protocol = this.options.secure ? 'wss' : 'ws';
28
+ let endpoint = '';
29
+ if (this.options.version === 'v4') {
30
+ endpoint = '/v4/websocket';
31
+ }
32
+ const url = `${protocol}://${this.options.host}:${this.options.port || 2333}${endpoint}`;
33
+ this.socket = new ws_1.default(url, { headers });
34
+ this.socket.on('open', this.onOpen.bind(this));
35
+ this.socket.on('message', this.onMessage.bind(this));
36
+ this.socket.on('error', this.onError.bind(this));
37
+ this.socket.on('close', this.onClose.bind(this));
38
+ }
39
+ send(payload) {
40
+ if (!this.connected || !this.socket)
41
+ return;
42
+ this.socket.send(JSON.stringify(payload));
43
+ }
44
+ async loadTracks(identifier) {
45
+ const protocol = this.options.secure ? 'https' : 'http';
46
+ let endpoint = '/loadtracks';
47
+ if (this.options.version === 'v4') {
48
+ endpoint = '/v4/loadtracks';
49
+ }
50
+ const url = new URL(`${protocol}://${this.options.host}:${this.options.port || 2333}${endpoint}`);
51
+ url.searchParams.append('identifier', identifier);
52
+ const response = await fetch(url.toString(), {
53
+ headers: {
54
+ Authorization: this.options.password || 'youshallnotpass'
55
+ }
56
+ });
57
+ return await response.json();
58
+ }
59
+ onOpen() {
60
+ this.connected = true;
61
+ this.manager.emit('nodeConnect', this);
62
+ }
63
+ onMessage(data) {
64
+ const payload = JSON.parse(data.toString());
65
+ switch (payload.op) {
66
+ case 'stats':
67
+ this.stats = payload;
68
+ this.manager.emit('nodeStats', this, payload);
69
+ break;
70
+ case 'playerUpdate':
71
+ const player = this.manager.players.get(payload.guildId);
72
+ if (player)
73
+ player.update(payload.state);
74
+ break;
75
+ case 'event':
76
+ this.handleEvent(payload);
77
+ break;
78
+ default:
79
+ this.manager.emit('nodeMessage', this, payload);
80
+ }
81
+ }
82
+ handleEvent(payload) {
83
+ const player = this.manager.players.get(payload.guildId);
84
+ if (!player)
85
+ return;
86
+ switch (payload.type) {
87
+ case 'TrackStartEvent':
88
+ this.manager.emit('trackStart', player, payload.track);
89
+ break;
90
+ case 'TrackEndEvent':
91
+ this.manager.emit('trackEnd', player, payload.track, payload.reason);
92
+ if (payload.reason === 'FINISHED' || payload.reason === 'LOAD_FAILED') {
93
+ // Auto-play next track in queue or trigger autoplay
94
+ if (player.queue.tracks.length > 0) {
95
+ player.play();
96
+ }
97
+ else if (player.autoplay) {
98
+ player.triggerAutoplay();
99
+ }
100
+ else {
101
+ player.isPlaying = false;
102
+ this.manager.emit('queueEnd', player);
103
+ }
104
+ }
105
+ break;
106
+ case 'TrackExceptionEvent':
107
+ this.manager.emit('trackError', player, payload.track, payload.exception);
108
+ break;
109
+ case 'TrackStuckEvent':
110
+ this.manager.emit('trackStuck', player, payload.track, payload.thresholdMs);
111
+ break;
112
+ case 'WebSocketClosedEvent':
113
+ this.manager.emit('socketClosed', player, payload);
114
+ break;
115
+ }
116
+ }
117
+ onError(error) {
118
+ this.manager.emit('nodeError', this, error);
119
+ }
120
+ onClose(code, reason) {
121
+ this.connected = false;
122
+ this.socket = null;
123
+ this.manager.emit('nodeDisconnect', this, code, reason);
124
+ }
125
+ }
126
+ exports.LavalinkNode = LavalinkNode;
127
+ //# sourceMappingURL=LavalinkNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LavalinkNode.js","sourceRoot":"","sources":["../../src/structures/LavalinkNode.ts"],"names":[],"mappings":";;;;;;AAAA,4CAA2B;AAc3B,MAAa,YAAY;IAOrB,YAAY,OAAwB,EAAE,OAAoB;QAJnD,WAAM,GAAqB,IAAI,CAAC;QAChC,UAAK,GAAQ,EAAE,CAAC;QAChB,cAAS,GAAY,KAAK,CAAC;QAG9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG;YACX,OAAO,EAAE,IAAI;YACb,GAAG,OAAO;SACb,CAAC;IACN,CAAC;IAEM,OAAO;QACV,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAExB,MAAM,OAAO,GAA2B;YACpC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,iBAAiB;YACzD,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG;YACrC,aAAa,EAAE,iBAAiB;SACnC,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACpD,IAAI,QAAQ,GAAG,EAAE,CAAC;QAElB,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAChC,QAAQ,GAAG,eAAe,CAAC;QAC/B,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,QAAQ,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;QAEzF,IAAI,CAAC,MAAM,GAAG,IAAI,YAAS,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAE9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC;IAEM,IAAI,CAAC,OAAY;QACpB,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAC5C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,UAAkB;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QACxD,IAAI,QAAQ,GAAG,aAAa,CAAC;QAE7B,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAChC,QAAQ,GAAG,gBAAgB,CAAC;QAChC,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,QAAQ,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC;QAClG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAElD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACzC,OAAO,EAAE;gBACL,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,iBAAiB;aAC5D;SACJ,CAAC,CAAC;QAEH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAEO,MAAM;QACV,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAEO,SAAS,CAAC,IAAoB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE5C,QAAQ,OAAO,CAAC,EAAE,EAAE,CAAC;YACjB,KAAK,OAAO;gBACR,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;gBACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC9C,MAAM;YAEV,KAAK,cAAc;gBACf,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACzD,IAAI,MAAM;oBAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACzC,MAAM;YAEV,KAAK,OAAO;gBACR,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;gBAC1B,MAAM;YAEV;gBACI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,OAAY;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,iBAAiB;gBAClB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;gBACvD,MAAM;YACV,KAAK,eAAe;gBAChB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBACrE,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,OAAO,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;oBACnE,oDAAoD;oBACpD,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACjC,MAAM,CAAC,IAAI,EAAE,CAAC;oBAClB,CAAC;yBAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBACzB,MAAM,CAAC,eAAe,EAAE,CAAC;oBAC7B,CAAC;yBAAM,CAAC;wBACL,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC;wBACzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;oBACzC,CAAC;gBACN,CAAC;gBACD,MAAM;YACV,KAAK,qBAAqB;gBACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;gBAC1E,MAAM;YACV,KAAK,iBAAiB;gBAClB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;gBAC5E,MAAM;YACV,KAAK,sBAAsB;gBACvB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;gBACnD,MAAM;QACd,CAAC;IACL,CAAC;IAEO,OAAO,CAAC,KAAY;QACxB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IAEO,OAAO,CAAC,IAAY,EAAE,MAAc;QACxC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;CACJ;AAzID,oCAyIC"}
@@ -0,0 +1,36 @@
1
+ import { LavalinkNode } from './LavalinkNode';
2
+ import { LavalinkManager } from './LavalinkManager';
3
+ import { Queue } from './Queue';
4
+ export interface PlayerOptions {
5
+ guildId: string;
6
+ textChannelId?: string;
7
+ voiceChannelId?: string;
8
+ selfDeaf?: boolean;
9
+ selfMute?: boolean;
10
+ autoplay?: boolean;
11
+ }
12
+ export declare class Player {
13
+ manager: LavalinkManager;
14
+ node: LavalinkNode;
15
+ guildId: string;
16
+ voiceChannelId: string | null;
17
+ textChannelId: string | null;
18
+ position: number;
19
+ paused: boolean;
20
+ isPlaying: boolean;
21
+ timestamp: number;
22
+ voiceUpdateState: {
23
+ sessionId?: string;
24
+ event?: any;
25
+ };
26
+ queue: Queue;
27
+ autoplay: boolean;
28
+ constructor(manager: LavalinkManager, node: LavalinkNode, options: PlayerOptions);
29
+ play(track?: string | any, options?: any): Promise<void>;
30
+ triggerAutoplay(): Promise<void>;
31
+ stop(): void;
32
+ setVolume(volume: number): void;
33
+ update(state: any): void;
34
+ destroy(): void;
35
+ }
36
+ //# sourceMappingURL=Player.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Player.d.ts","sourceRoot":"","sources":["../../src/structures/Player.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,MAAM;IACR,OAAO,EAAE,eAAe,CAAC;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IACrC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IACpC,QAAQ,EAAE,MAAM,CAAK;IACrB,MAAM,EAAE,OAAO,CAAS;IACxB,SAAS,EAAE,OAAO,CAAS;IAC3B,SAAS,EAAE,MAAM,CAAK;IACtB,gBAAgB,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,GAAG,CAAA;KAAE,CAAM;IAC3D,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,OAAO,CAAS;gBAErB,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa;IAUnE,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,GAAE,GAAQ;IA4B5C,eAAe;IAgCrB,IAAI;IAQJ,SAAS,CAAC,MAAM,EAAE,MAAM;IAQxB,MAAM,CAAC,KAAK,EAAE,GAAG;IAKjB,OAAO;CAQjB"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Player = void 0;
4
+ const Queue_1 = require("./Queue");
5
+ class Player {
6
+ constructor(manager, node, options) {
7
+ this.voiceChannelId = null;
8
+ this.textChannelId = null;
9
+ this.position = 0;
10
+ this.paused = false;
11
+ this.isPlaying = false;
12
+ this.timestamp = 0;
13
+ this.voiceUpdateState = {};
14
+ this.autoplay = false;
15
+ this.manager = manager;
16
+ this.node = node;
17
+ this.guildId = options.guildId;
18
+ this.voiceChannelId = options.voiceChannelId || null;
19
+ this.textChannelId = options.textChannelId || null;
20
+ this.autoplay = options.autoplay || false;
21
+ this.queue = new Queue_1.Queue(this);
22
+ }
23
+ async play(track, options = {}) {
24
+ if (!track && !this.queue.current && this.queue.tracks.length > 0) {
25
+ const next = this.queue.next();
26
+ if (next) {
27
+ track = next.track; // Assuming object has .track
28
+ }
29
+ }
30
+ if (!track) {
31
+ if (this.autoplay) {
32
+ return this.triggerAutoplay();
33
+ }
34
+ return;
35
+ }
36
+ this.isPlaying = true;
37
+ // Handle if track is an object (Lavalink track object) or string
38
+ const trackString = typeof track === 'string' ? track : track.track;
39
+ this.node.send({
40
+ op: 'play',
41
+ guildId: this.guildId,
42
+ track: trackString,
43
+ ...options
44
+ });
45
+ }
46
+ async triggerAutoplay() {
47
+ const previousTrack = this.queue.previous[this.queue.previous.length - 1];
48
+ if (!previousTrack)
49
+ return; // Cannot autoplay without seed
50
+ // Use previous track URI or ID for recommendation
51
+ // Simple implementation: Search for related tracks or a mix
52
+ // Ideally, this uses a specific source feature like "spotify:seed_tracks" or similar via a plugin
53
+ // For general usage:
54
+ const source = previousTrack.info?.sourceName;
55
+ let identifier = '';
56
+ if (source === 'spotify' || source === 'applemusic' || source === 'deezer') {
57
+ // If using Lavasrc, we might get recommendations.
58
+ // Common pattern: `sprec:${trackId}` or similar if plugin supports it.
59
+ // Fallback to "related" search on YouTube if all else fails?
60
+ identifier = `ytsearch:${previousTrack.info.author} - ${previousTrack.info.title}`;
61
+ }
62
+ else {
63
+ identifier = `ytmsearch:${previousTrack.info.author} - ${previousTrack.info.title}`;
64
+ }
65
+ const res = await this.node.loadTracks(identifier);
66
+ if (res && res.tracks && res.tracks.length > 0) {
67
+ // Filter out current track?
68
+ const nextTrack = res.tracks[0].track === previousTrack.track ? res.tracks[1] : res.tracks[0];
69
+ if (nextTrack) {
70
+ this.queue.add(nextTrack);
71
+ this.play();
72
+ }
73
+ }
74
+ }
75
+ stop() {
76
+ this.isPlaying = false;
77
+ this.node.send({
78
+ op: 'stop',
79
+ guildId: this.guildId
80
+ });
81
+ }
82
+ setVolume(volume) {
83
+ this.node.send({
84
+ op: 'volume',
85
+ guildId: this.guildId,
86
+ volume: volume
87
+ });
88
+ }
89
+ update(state) {
90
+ this.position = state.position;
91
+ this.timestamp = state.time;
92
+ }
93
+ destroy() {
94
+ this.stop();
95
+ this.node.send({
96
+ op: 'destroy',
97
+ guildId: this.guildId
98
+ });
99
+ this.manager.emit('playerDestroy', this);
100
+ }
101
+ }
102
+ exports.Player = Player;
103
+ //# sourceMappingURL=Player.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Player.js","sourceRoot":"","sources":["../../src/structures/Player.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { LavalinkManager } from './LavalinkManager';
2
+ export declare abstract class Plugin {
3
+ manager: LavalinkManager | null;
4
+ abstract name: string;
5
+ load(manager: LavalinkManager): void;
6
+ abstract unload(): void;
7
+ }
8
+ //# sourceMappingURL=Plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plugin.d.ts","sourceRoot":"","sources":["../../src/structures/Plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,8BAAsB,MAAM;IACjB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAQ;IAC9C,SAAgB,IAAI,EAAE,MAAM,CAAC;IAEtB,IAAI,CAAC,OAAO,EAAE,eAAe;aAIpB,MAAM,IAAI,IAAI;CACjC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Plugin = void 0;
4
+ class Plugin {
5
+ constructor() {
6
+ this.manager = null;
7
+ }
8
+ load(manager) {
9
+ this.manager = manager;
10
+ }
11
+ }
12
+ exports.Plugin = Plugin;
13
+ //# sourceMappingURL=Plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plugin.js","sourceRoot":"","sources":["../../src/structures/Plugin.ts"],"names":[],"mappings":";;;AAEA,MAAsB,MAAM;IAA5B;QACW,YAAO,GAA2B,IAAI,CAAC;IAQlD,CAAC;IALU,IAAI,CAAC,OAAwB;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CAGJ;AATD,wBASC"}
@@ -0,0 +1,13 @@
1
+ import { Player } from './Player';
2
+ export declare class Queue {
3
+ readonly player: Player;
4
+ tracks: any[];
5
+ previous: any[];
6
+ current: any | null;
7
+ constructor(player: Player);
8
+ add(track: any | any[]): void;
9
+ next(): any | null;
10
+ clear(): void;
11
+ shuffle(): void;
12
+ }
13
+ //# sourceMappingURL=Queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Queue.d.ts","sourceRoot":"","sources":["../../src/structures/Queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,qBAAa,KAAK;IACd,SAAgB,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,GAAG,EAAE,CAAM;IACnB,QAAQ,EAAE,GAAG,EAAE,CAAM;IACrB,OAAO,EAAE,GAAG,GAAG,IAAI,CAAQ;gBAEtB,MAAM,EAAE,MAAM;IAInB,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,EAAE;IAQtB,IAAI,IAAI,GAAG,GAAG,IAAI;IAUlB,KAAK;IAML,OAAO;CAMjB"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Queue = void 0;
4
+ class Queue {
5
+ constructor(player) {
6
+ this.tracks = [];
7
+ this.previous = [];
8
+ this.current = null;
9
+ this.player = player;
10
+ }
11
+ add(track) {
12
+ if (Array.isArray(track)) {
13
+ this.tracks.push(...track);
14
+ }
15
+ else {
16
+ this.tracks.push(track);
17
+ }
18
+ }
19
+ next() {
20
+ if (this.current) {
21
+ this.previous.push(this.current);
22
+ }
23
+ const nextTrack = this.tracks.shift();
24
+ this.current = nextTrack || null;
25
+ return this.current;
26
+ }
27
+ clear() {
28
+ this.tracks = [];
29
+ this.previous = [];
30
+ this.current = null;
31
+ }
32
+ shuffle() {
33
+ for (let i = this.tracks.length - 1; i > 0; i--) {
34
+ const j = Math.floor(Math.random() * (i + 1));
35
+ [this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]];
36
+ }
37
+ }
38
+ }
39
+ exports.Queue = Queue;
40
+ //# sourceMappingURL=Queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Queue.js","sourceRoot":"","sources":["../../src/structures/Queue.ts"],"names":[],"mappings":";;;AAEA,MAAa,KAAK;IAMd,YAAY,MAAc;QAJnB,WAAM,GAAU,EAAE,CAAC;QACnB,aAAQ,GAAU,EAAE,CAAC;QACrB,YAAO,GAAe,IAAI,CAAC;QAG9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAEM,GAAG,CAAC,KAAkB;QACzB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACL,CAAC;IAEM,IAAI;QACP,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,CAAC,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAEM,KAAK;QACR,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;IAEM,OAAO;QACV,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC;IACL,CAAC;CACJ;AAxCD,sBAwCC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@ramkrishna-js/framelink",
3
+ "version": "1.0.0",
4
+ "description": "🚀 A lightweight, robust, and plugin-ready Lavalink client (v3 & v4) for Node.js.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "ts-node src/index.ts",
13
+ "start": "node dist/index.js",
14
+ "test": "echo \"Error: no test specified\" && exit 1",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "lavalink",
19
+ "lavalink-client",
20
+ "discord",
21
+ "discord-bot",
22
+ "music-bot",
23
+ "music",
24
+ "framelink",
25
+ "lavasrc"
26
+ ],
27
+ "author": "Ramkrishna",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/ramkrishna-js/framelink.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/ramkrishna-js/framelink/issues"
35
+ },
36
+ "homepage": "https://github.com/ramkrishna-js/framelink#readme",
37
+ "type": "commonjs",
38
+ "devDependencies": {
39
+ "@types/node": "^25.0.5",
40
+ "@types/ws": "^8.18.1",
41
+ "ts-node": "^10.9.2",
42
+ "typescript": "^5.9.3"
43
+ },
44
+ "dependencies": {
45
+ "ws": "^8.19.0"
46
+ }
47
+ }