Skip to content

Commit 3159c6a

Browse files
committed
v2.3.6 - lyrics support + new source
1 parent 0934791 commit 3159c6a

29 files changed

+1131
-31
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,3 +722,21 @@ if(previousTrack) {
722722
- FIXED autoplay not working :: Accidentally added an invalid if statement, which made autoplay not working anymore (during the if statement to not prevent autoplay spam)
723723
- Added a new AutoplayExecution Debug Log
724724
- Added more samples to the Testbot related configuration
725+
726+
727+
## **Version 2.3.6
728+
- Added Lyrics Support:
729+
- New Player Functions:
730+
- **` const lyrics = await player.getCurrentLyrics(false); `** -> *Get lyrics of current playing track*
731+
- **` const lyrics = await player.getLyrics(track, true); `** -> *Get lyrics of a specific track with ignoring it's sources*
732+
- **` player.subscribeLyrics(); `** -> *Subscribe this guild to retrieve "live lyrics" as the song is *playing
733+
- **` player.unsubscribeLyrics(); `** -> *Unsubscribe from lyrics
734+
- New Node Functions ( same as from player, just so you can access it without player too ):*
735+
- **` const lyrics = await player.node.lyrics.getCurrent(player.guildId, false); `**
736+
- **` const lyrics = await player.node.lyrics.get(track, true); `**
737+
- **` player.node.lyrics.subscribe(player.guildId); `**
738+
- **` player.node.lyrics.unsubscribe(player.guildId); `**
739+
- New Manager Event sfor Lyrics:
740+
- **` lavalink.on("LyricsLine", (player, track, lyricsLine) => {}); `**
741+
- **` lavalink.on("LyricsFound", (player, track, data) => {}); `**
742+
- **` lavalink.on("LyricsNotFound", (player, track, lyricsLine) => {}); `**

dist/cjs/structures/LavalinkManagerStatics.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ export declare const LavalinkPlugins: {
77
LavaSrc: string;
88
GoogleCloudTTS: string;
99
LavaSearch: string;
10+
Jiosaavn_Plugin: string;
1011
LavalinkFilterPlugin: string;
12+
JavaTimedLyricsPlugin: string;
1113
};
1214
/** Lavalink Sources regexes for url validations */
1315
export declare const SourceLinksRegexes: Record<SourcesRegex, RegExp>;

dist/cjs/structures/LavalinkManagerStatics.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,22 @@ exports.DefaultSources = {
6565
"http": "http",
6666
"https": "https",
6767
"link": "link",
68-
"uri": "uri"
68+
"uri": "uri",
69+
// jiosaavn
70+
"jiosaavn": "jssearch",
71+
"js": "jssearch",
72+
"jssearch": "jssearch",
73+
"jsrec": "jsrec"
6974
};
7075
/** Lavalink Plugins definiton */
7176
exports.LavalinkPlugins = {
7277
DuncteBot_Plugin: "DuncteBot-plugin",
7378
LavaSrc: "lavasrc-plugin",
7479
GoogleCloudTTS: "tts-plugin",
7580
LavaSearch: "lavasearch-plugin",
76-
LavalinkFilterPlugin: "lavalink-filter-plugin"
81+
Jiosaavn_Plugin: "jiosaavn-plugin",
82+
LavalinkFilterPlugin: "lavalink-filter-plugin",
83+
JavaTimedLyricsPlugin: "java-lyrics-plugin"
7784
};
7885
/** Lavalink Sources regexes for url validations */
7986
exports.SourceLinksRegexes = {
@@ -111,6 +118,8 @@ exports.SourceLinksRegexes = {
111118
SpotifyAlbumRegex: /(https?:\/\/)(www\.)?open\.spotify\.com\/((?<region>[a-zA-Z-]+)\/)?(user\/(?<user>[a-zA-Z0-9-_]+)\/)?album\/(?<identifier>[a-zA-Z0-9-_]+)/,
112119
AllSpotifyRegex: /(https?:\/\/)(www\.)?open\.spotify\.com\/((?<region>[a-zA-Z-]+)\/)?(user\/(?<user>[a-zA-Z0-9-_]+)\/)?(?<type>track|album|playlist|artist|episode|show)\/(?<identifier>[a-zA-Z0-9-_]+)/,
113120
appleMusic: /https?:\/\/?(?:www\.)?music\.apple\.com\/(\S+)/,
121+
/** From jiosaavn-plugin */
122+
jiosaavn: /(https?:\/\/)(www\.)?jiosaavn\.com\/(?<type>song|album|featured|artist)\/([a-zA-Z0-9-_\/,]+)/,
114123
/** FROM DUNCTE BOT PLUGIN */
115124
tiktok: /https:\/\/www\.tiktok\.com\//,
116125
mixcloud: /https:\/\/www\.mixcloud\.com\//,

dist/cjs/structures/Node.d.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { DestroyReasonsType } from "./Types/Player.js";
33
import type { Track } from "./Types/Track.js";
44
import type { Base64, InvalidLavalinkRestRequest, LavalinkPlayer, LavaSearchQuery, LavaSearchResponse, PlayerUpdateInfo, RoutePlanner, SearchQuery, SearchResult, Session } from "./Types/Utils.js";
55
import type { NodeManager } from "./NodeManager.js";
6-
import type { BaseNodeStats, LavalinkInfo, LavalinkNodeOptions, ModifyRequest, NodeStats, SponsorBlockSegment } from "./Types/Node.js";
6+
import type { BaseNodeStats, LavalinkInfo, LavalinkNodeOptions, LyricsResult, ModifyRequest, NodeStats, SponsorBlockSegment } from "./Types/Node.js";
77
/**
88
* Lavalink Node creator class
99
*/
@@ -271,6 +271,62 @@ export declare class LavalinkNode {
271271
*/
272272
multipleTracks: (encodeds: Base64[], requester: unknown) => Promise<Track[]>;
273273
};
274+
lyrics: {
275+
/**
276+
* Get the lyrics of a track
277+
* @param track the track to get the lyrics for
278+
* @param skipTrackSource wether to skip the track source or not
279+
* @returns the lyrics of the track
280+
* @example
281+
*
282+
* ```ts
283+
* const lyrics = await player.node.lyrics.get(track, true);
284+
* // use it of player instead:
285+
* // const lyrics = await player.getLyrics(track, true);
286+
* ```
287+
*/
288+
get: (track: Track, skipTrackSource?: boolean) => Promise<LyricsResult>;
289+
/**
290+
* Get the lyrics of the current playing track
291+
*
292+
* @param guildId the guild id of the player
293+
* @param skipTrackSource wether to skip the track source or not
294+
* @returns the lyrics of the current playing track
295+
* @example
296+
* ```ts
297+
* const lyrics = await player.node.lyrics.getCurrent(guildId);
298+
* // use it of player instead:
299+
* // const lyrics = await player.getCurrentLyrics();
300+
* ```
301+
*/
302+
getCurrent: (guildId: string, skipTrackSource?: boolean) => Promise<LyricsResult>;
303+
/**
304+
* subscribe to lyrics updates for a guild
305+
* @param guildId the guild id of the player
306+
* @returns request data of the request
307+
*
308+
* @example
309+
* ```ts
310+
* await player.node.lyrics.subscribe(guildId);
311+
* // use it of player instead:
312+
* // const lyrics = await player.subscribeLyrics();
313+
* ```
314+
*/
315+
subscribe: (guildId: string) => Promise<any>;
316+
/**
317+
* unsubscribe from lyrics updates for a guild
318+
* @param guildId the guild id of the player
319+
* @returns request data of the request
320+
*
321+
* @example
322+
* ```ts
323+
* await player.node.lyrics.unsubscribe(guildId);
324+
* // use it of player instead:
325+
* // const lyrics = await player.unsubscribeLyrics();
326+
* ```
327+
*/
328+
unsubscribe: (guildId: string) => Promise<any>;
329+
};
274330
/**
275331
* Request Lavalink statistics.
276332
* @returns the lavalink node stats
@@ -432,4 +488,28 @@ export declare class LavalinkNode {
432488
deleteSponsorBlock(player: Player): Promise<void>;
433489
/** private util function for handling the queue end event */
434490
private queueEnd;
491+
/**
492+
* Emitted whenever a line of lyrics gets emitted
493+
* @event
494+
* @param {Player} player The player that emitted the event
495+
* @param {Track} track The track that emitted the event
496+
* @param {LyricsLineEvent} payload The payload of the event
497+
*/
498+
private LyricsLine;
499+
/**
500+
* Emitted whenever the lyrics for a track got found
501+
* @event
502+
* @param {Player} player The player that emitted the event
503+
* @param {Track} track The track that emitted the event
504+
* @param {LyricsFoundEvent} payload The payload of the event
505+
*/
506+
private LyricsFound;
507+
/**
508+
* Emitted whenever the lyrics for a track got not found
509+
* @event
510+
* @param {Player} player The player that emitted the event
511+
* @param {Track} track The track that emitted the event
512+
* @param {LyricsNotFoundEvent} payload The payload of the event
513+
*/
514+
private LyricsNotFound;
435515
}

dist/cjs/structures/Node.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,104 @@ class LavalinkNode {
590590
}).then((r) => r.map(track => this.NodeManager.LavalinkManager.utils.buildTrack(track, requester)));
591591
}
592592
};
593+
lyrics = {
594+
/**
595+
* Get the lyrics of a track
596+
* @param track the track to get the lyrics for
597+
* @param skipTrackSource wether to skip the track source or not
598+
* @returns the lyrics of the track
599+
* @example
600+
*
601+
* ```ts
602+
* const lyrics = await player.node.lyrics.get(track, true);
603+
* // use it of player instead:
604+
* // const lyrics = await player.getLyrics(track, true);
605+
* ```
606+
*/
607+
get: async (track, skipTrackSource = false) => {
608+
if (!this.sessionId)
609+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
610+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
611+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
612+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
613+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
614+
throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
615+
const url = `/lyrics?track=${track.encoded}&skipTrackSource=${skipTrackSource}`;
616+
return (await this.request(url));
617+
},
618+
/**
619+
* Get the lyrics of the current playing track
620+
*
621+
* @param guildId the guild id of the player
622+
* @param skipTrackSource wether to skip the track source or not
623+
* @returns the lyrics of the current playing track
624+
* @example
625+
* ```ts
626+
* const lyrics = await player.node.lyrics.getCurrent(guildId);
627+
* // use it of player instead:
628+
* // const lyrics = await player.getCurrentLyrics();
629+
* ```
630+
*/
631+
getCurrent: async (guildId, skipTrackSource = false) => {
632+
if (!this.sessionId)
633+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
634+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
635+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
636+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
637+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
638+
throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
639+
const url = `/sessions/${this.sessionId}/players/${guildId}/track/lyrics?skipTrackSource=${skipTrackSource}`;
640+
return (await this.request(url));
641+
},
642+
/**
643+
* subscribe to lyrics updates for a guild
644+
* @param guildId the guild id of the player
645+
* @returns request data of the request
646+
*
647+
* @example
648+
* ```ts
649+
* await player.node.lyrics.subscribe(guildId);
650+
* // use it of player instead:
651+
* // const lyrics = await player.subscribeLyrics();
652+
* ```
653+
*/
654+
subscribe: async (guildId) => {
655+
if (!this.sessionId)
656+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
657+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
658+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
659+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
660+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
661+
throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
662+
return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`, (options) => {
663+
options.method = "POST";
664+
}).catch(() => { });
665+
},
666+
/**
667+
* unsubscribe from lyrics updates for a guild
668+
* @param guildId the guild id of the player
669+
* @returns request data of the request
670+
*
671+
* @example
672+
* ```ts
673+
* await player.node.lyrics.unsubscribe(guildId);
674+
* // use it of player instead:
675+
* // const lyrics = await player.unsubscribeLyrics();
676+
* ```
677+
*/
678+
unsubscribe: async (guildId) => {
679+
if (!this.sessionId)
680+
throw new Error("the Lavalink-Node is either not ready, or not up to date!");
681+
if (!this.info.plugins.find(v => v.name === "lavalyrics-plugin"))
682+
throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node (required for lyrics): ${this.id}`);
683+
if (!this.info.plugins.find(v => v.name === "lavasrc-plugin") &&
684+
!this.info.plugins.find(v => v.name === "java-lyrics-plugin"))
685+
throw new RangeError(`there is no lyrics source (via lavasrc-plugin / java-lyrics-plugin) available in the lavalink node (required for lyrics): ${this.id}`);
686+
return await this.request(`/sessions/${this.sessionId}/players/${guildId}/lyrics/unsubscribe`, (options) => {
687+
options.method = "DELETE";
688+
}).catch(() => { });
689+
},
690+
};
593691
/**
594692
* Request Lavalink statistics.
595693
* @returns the lavalink node stats
@@ -986,6 +1084,15 @@ class LavalinkNode {
9861084
case "ChapterStarted":
9871085
this.SponsorBlockChapterStarted(player, player.queue.current, payload);
9881086
break;
1087+
case "LyricsLineEvent":
1088+
this.LyricsLine(player, player.queue.current, payload);
1089+
break;
1090+
case "LyricsFoundEvent":
1091+
this.LyricsFound(player, player.queue.current, payload);
1092+
break;
1093+
case "LyricsNotFoundEvent":
1094+
this.LyricsNotFound(player, player.queue.current, payload);
1095+
break;
9891096
default:
9901097
this.NodeManager.emit("error", this, new Error(`Node#event unknown event '${payload.type}'.`), payload);
9911098
break;
@@ -1326,5 +1433,35 @@ class LavalinkNode {
13261433
}
13271434
return this.NodeManager.LavalinkManager.emit("queueEnd", player, track, payload);
13281435
}
1436+
/**
1437+
* Emitted whenever a line of lyrics gets emitted
1438+
* @event
1439+
* @param {Player} player The player that emitted the event
1440+
* @param {Track} track The track that emitted the event
1441+
* @param {LyricsLineEvent} payload The payload of the event
1442+
*/
1443+
LyricsLine(player, track, payload) {
1444+
return this.NodeManager.LavalinkManager.emit("LyricsLine", player, track, payload);
1445+
}
1446+
/**
1447+
* Emitted whenever the lyrics for a track got found
1448+
* @event
1449+
* @param {Player} player The player that emitted the event
1450+
* @param {Track} track The track that emitted the event
1451+
* @param {LyricsFoundEvent} payload The payload of the event
1452+
*/
1453+
LyricsFound(player, track, payload) {
1454+
return this.NodeManager.LavalinkManager.emit("LyricsFound", player, track, payload);
1455+
}
1456+
/**
1457+
* Emitted whenever the lyrics for a track got not found
1458+
* @event
1459+
* @param {Player} player The player that emitted the event
1460+
* @param {Track} track The track that emitted the event
1461+
* @param {LyricsNotFoundEvent} payload The payload of the event
1462+
*/
1463+
LyricsNotFound(player, track, payload) {
1464+
return this.NodeManager.LavalinkManager.emit("LyricsNotFound", player, track, payload);
1465+
}
13291466
}
13301467
exports.LavalinkNode = LavalinkNode;

dist/cjs/structures/Player.d.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FilterManager } from "./Filters.js";
22
import { Queue } from "./Queue.js";
33
import type { DestroyReasons } from "./Constants.js";
4+
import type { Track } from "./Types/Track.js";
45
import type { LavalinkNode } from "./Node.js";
56
import type { SponsorBlockSegment } from "./Types/Node.js";
67
import type { PlayerJson, PlayerOptions, PlayOptions, RepeatMode } from "./Types/Player.js";
@@ -164,6 +165,48 @@ export declare class Player {
164165
* Destroy the player and disconnect from the voice channel
165166
*/
166167
destroy(reason?: DestroyReasons | string, disconnect?: boolean): Promise<this>;
168+
/**
169+
* Get the current lyrics of the track currently playing on the guild
170+
* @param guildId The guild id to get the current lyrics for
171+
* @param skipTrackSource If true, it will not try to get the lyrics from the track source
172+
* @returns The current lyrics
173+
* @example
174+
* ```ts
175+
* const lyrics = await player.getCurrentLyrics();
176+
* ```
177+
*/
178+
getCurrentLyrics(skipTrackSource?: boolean): Promise<import("./Types/Node.js").LyricsResult>;
179+
/**
180+
* Get the lyrics of a specific track
181+
* @param track The track to get the lyrics for
182+
* @param skipTrackSource If true, it will not try to get the lyrics from the track source
183+
* @returns The lyrics of the track
184+
* @example
185+
* ```ts
186+
* const lyrics = await player.getLyrics(player.queue.tracks[0], true);
187+
* ```
188+
*/
189+
getLyrics(track: Track, skipTrackSource?: boolean): Promise<import("./Types/Node.js").LyricsResult>;
190+
/**
191+
* Subscribe to the lyrics event on a specific guild to active live lyrics events
192+
* @param guildId The guild id to subscribe to
193+
* @returns The unsubscribe function
194+
* @example
195+
* ```ts
196+
* const lyrics = await player.subscribeLyrics();
197+
* ```
198+
*/
199+
subscribeLyrics(): Promise<any>;
200+
/**
201+
* Unsubscribe from the lyrics event on a specific guild to disable live lyrics events
202+
* @param guildId The guild id to unsubscribe from
203+
* @returns The unsubscribe function
204+
* @example
205+
* ```ts
206+
* const lyrics = await player.unsubscribeLyrics();
207+
* ```
208+
*/
209+
unsubscribeLyrics(guildId: string): Promise<any>;
167210
/**
168211
* Move the player on a different Audio-Node
169212
* @param newNode New Node / New Node Id

0 commit comments

Comments
 (0)