muthera 1.0.7 → 1.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muthera",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "A simple Lavalink wrapper for Discord music bot. Forked from Niizuki.",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -147,7 +147,7 @@ async function dzAutoPlay(trackId, title = null, artist = null, retries = 3) {
147
147
  } catch (_) {}
148
148
  }
149
149
 
150
- if (!trackData || trackData.error) throw new Error("Deezer track not found");
150
+ if (!trackData || trackData.error) return null;
151
151
 
152
152
  const originalTrackId = String(trackData.id);
153
153
  const artistId = trackData.artist?.id ? String(trackData.artist.id) : null;
@@ -196,7 +196,7 @@ async function dzAutoPlay(trackId, title = null, artist = null, retries = 3) {
196
196
  }
197
197
 
198
198
  const arr = Array.from(candidates.values());
199
- if (!arr.length) throw new Error("No Deezer recommendations found");
199
+ if (!arr.length) return null;
200
200
  const pick = arr[Math.floor(Math.random() * arr.length)];
201
201
  return `https://www.deezer.com/track/${pick.id}`;
202
202
  }
@@ -92,6 +92,14 @@ class Player extends EventEmitter {
92
92
 
93
93
  this.isAutoplay = true;
94
94
 
95
+ // Helper: emit autoplayFailed instead of stop() to avoid re-triggering
96
+ // TrackEndEvent → queueEnd → autoplay infinite loop
97
+ const fail = (e) => {
98
+ if (e) console.log(e);
99
+ this.muthera.emit("autoplayFailed", this);
100
+ return this;
101
+ };
102
+
95
103
  if (player.previous) {
96
104
  if (player.previous.info.sourceName === "youtube") {
97
105
  try {
@@ -107,23 +115,26 @@ class Player extends EventEmitter {
107
115
  !response.tracks ||
108
116
  ["error", "empty"].includes(response.loadType)
109
117
  )
110
- return this.stop();
118
+ return fail();
119
+
120
+ // Filter out the previous track to avoid immediate duplicate
121
+ const tracks = response.tracks.filter(
122
+ (t) => t.info.identifier !== player.previous.info.identifier
123
+ );
111
124
 
112
- let track =
113
- response.tracks[
114
- Math.floor(Math.random() * Math.floor(response.tracks.length))
115
- ];
125
+ if (!tracks.length) return fail();
116
126
 
117
127
  if (this.connected) {
118
- this.queue.push(track);
128
+ // Push entire Mix playlist into queue
129
+ for (const t of tracks) this.queue.push(t);
119
130
  await this.play();
120
131
  } else {
121
- return this.stop();
132
+ return fail();
122
133
  }
123
134
 
124
135
  return this;
125
136
  } catch (e) {
126
- return this.stop();
137
+ return fail(e);
127
138
  }
128
139
  } else if (player.previous.info.sourceName === "youtubemusic") {
129
140
  try {
@@ -138,23 +149,26 @@ class Player extends EventEmitter {
138
149
  !response.tracks ||
139
150
  ["error", "empty"].includes(response.loadType)
140
151
  )
141
- return this.stop();
152
+ return fail();
142
153
 
143
- let track =
144
- response.tracks[
145
- Math.floor(Math.random() * Math.floor(response.tracks.length))
146
- ];
154
+ // Filter out the previous track to avoid immediate duplicate
155
+ const tracks = response.tracks.filter(
156
+ (t) => t.info.identifier !== player.previous.info.identifier
157
+ );
158
+
159
+ if (!tracks.length) return fail();
147
160
 
148
161
  if (this.connected) {
149
- this.queue.push(track);
162
+ // Push entire Mix playlist into queue
163
+ for (const t of tracks) this.queue.push(t);
150
164
  await this.play();
151
165
  } else {
152
- return this.stop();
166
+ return fail();
153
167
  }
154
168
 
155
169
  return this;
156
170
  } catch (e) {
157
- return this.stop();
171
+ return fail(e);
158
172
  }
159
173
  } else if (player.previous.info.sourceName === "soundcloud") {
160
174
  try {
@@ -170,7 +184,7 @@ class Player extends EventEmitter {
170
184
  !response.tracks ||
171
185
  ["error", "empty"].includes(response.loadType)
172
186
  )
173
- return this.stop();
187
+ return fail();
174
188
 
175
189
  let track =
176
190
  response.tracks[
@@ -181,19 +195,18 @@ class Player extends EventEmitter {
181
195
  this.queue.push(track);
182
196
  await this.play();
183
197
  } else {
184
- return this.stop();
198
+ return fail();
185
199
  }
186
200
 
187
201
  return this;
188
202
  });
189
203
  } catch (e) {
190
- console.log(e);
191
- return this.stop();
204
+ return fail(e);
192
205
  }
193
206
  } else if (player.previous.info.sourceName === "deezer") {
194
207
  try {
195
208
  const data = await dzAutoPlay(player.previous.info.identifier);
196
- if (!data) return this.stop();
209
+ if (!data) return fail();
197
210
 
198
211
  const response = await this.muthera.resolve({
199
212
  query: data,
@@ -205,8 +218,8 @@ class Player extends EventEmitter {
205
218
  !response.tracks ||
206
219
  ["error", "empty"].includes(response.loadType)
207
220
  )
208
- return this.stop();
209
-
221
+ return fail();
222
+
210
223
  const track =
211
224
  response.tracks[Math.floor(Math.random() * response.tracks.length)];
212
225
 
@@ -214,12 +227,11 @@ class Player extends EventEmitter {
214
227
  this.queue.push(track);
215
228
  await this.play();
216
229
  } else {
217
- return this.stop();
230
+ return fail();
218
231
  }
219
232
  return this;
220
233
  } catch (e) {
221
- console.log(e);
222
- return this.stop();
234
+ return fail(e);
223
235
  }
224
236
  } else if (player.previous.info.sourceName === "applemusic") {
225
237
  try {
@@ -239,7 +251,7 @@ class Player extends EventEmitter {
239
251
  !response.tracks ||
240
252
  ["error", "empty"].includes(response.loadType)
241
253
  )
242
- return this.stop();
254
+ return fail();
243
255
 
244
256
  const track =
245
257
  response.tracks[Math.floor(Math.random() * response.tracks.length)];
@@ -248,13 +260,12 @@ class Player extends EventEmitter {
248
260
  this.queue.push(track);
249
261
  await this.play();
250
262
  } else {
251
- return this.stop();
263
+ return fail();
252
264
  }
253
265
 
254
266
  return this;
255
267
  } catch (e) {
256
- console.log(e);
257
- return this.stop();
268
+ return fail(e);
258
269
  }
259
270
  } else if (player.previous.info.sourceName === "spotify") {
260
271
  try {
@@ -265,7 +276,7 @@ class Player extends EventEmitter {
265
276
  if (platform.includes("dz")) {
266
277
  // Use Deezer related-artist API for proper similar song recommendations
267
278
  const data = await dzAutoPlay(null, title, artist);
268
- if (!data) return this.stop();
279
+ if (!data) return fail();
269
280
 
270
281
  const response = await this.muthera.resolve({
271
282
  query: data,
@@ -278,7 +289,7 @@ class Player extends EventEmitter {
278
289
  ["error", "empty"].includes(response.loadType) ||
279
290
  response.tracks.length === 0
280
291
  )
281
- return this.stop();
292
+ return fail();
282
293
 
283
294
  const track =
284
295
  response.tracks[Math.floor(Math.random() * response.tracks.length)];
@@ -287,7 +298,7 @@ class Player extends EventEmitter {
287
298
  this.queue.push(track);
288
299
  await this.play();
289
300
  } else {
290
- return this.stop();
301
+ return fail();
291
302
  }
292
303
  return this;
293
304
  } else {
@@ -304,7 +315,7 @@ class Player extends EventEmitter {
304
315
  ["error", "empty"].includes(response.loadType) ||
305
316
  response.tracks.length === 0
306
317
  )
307
- return this.stop();
318
+ return fail();
308
319
 
309
320
  const filtered = response.tracks.filter(
310
321
  (t) => t.info.title.toLowerCase() !== title.toLowerCase()
@@ -316,13 +327,12 @@ class Player extends EventEmitter {
316
327
  this.queue.push(track);
317
328
  await this.play();
318
329
  } else {
319
- return this.stop();
330
+ return fail();
320
331
  }
321
332
  return this;
322
333
  }
323
334
  } catch (e) {
324
- console.log(e);
325
- return this.stop();
335
+ return fail(e);
326
336
  }
327
337
  }
328
338
  } else return this;