Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lyrics command #719

Merged
merged 11 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ AUTO_NODE=" false" # true for auto node. It is given from lavainfo-api (https://
SEARCH_ENGINE= "YouTubeMusic" # Search engine to be used when playing the song. You can use: YouTube, YouTubeMusic, SoundCloud, Spotify, Apple, Deezer, Yandex and JioSaavn
MAX_PLAYLIST_SIZE= "100" # Max playlist size.
MAX_QUEUE_SIZE= "100" # Max queue size.
GENIUS_API= "" # Sign up and get your own api at (https://genius.com/) to fetch your lyrics (CLIENT TOKEN)

# Configuration for multiple Lavalink servers
LAVALINK_SERVERS = '[
{"url":"localhost:2333","auth":"youshallnotpass","name":"Local Node","secure":false},
{"url":"localhost:2333","auth":"youshallnotpass2","name":"Another Node","secure":false}
]'
]'
12 changes: 11 additions & 1 deletion locales/EnglishUS.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,16 @@
"looping_queue": "**Looping the queue.**",
"looping_off": "**Looping is now off.**"
},
"lyrics": {
"description": "Get's the lyrics of the currently playing track.",
"lyrics_track": "### Lyrics for: [{trackTitle}]({trackUrl})\n**`{lyrics}`**",
"searching": "`🔍` Searching for **{trackTitle}** lyrics...",
"errors": {
"no_results": "No lyrics found for the current track.",
"no_playing": "No track is currently playing.",
"lyrics_error": "An error occurred while getting the lyrics."
}
},
"nowplaying": {
"description": "Shows the currently playing song",
"now_playing": "Now Playing",
Expand Down Expand Up @@ -629,4 +639,4 @@
"Leave a guild": "Leave a guild",
"List all guilds the bot is in": "List all guilds the bot is in",
"Restart the bot": "Restart the bot"
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@top-gg/sdk": "^3.1.6",
"discord.js": "^14.16.1",
"dotenv": "^16.4.5",
"genius-lyrics-api": "^3.2.1",
"i18n": "^0.15.1",
"node-system-stats": "^1.3.0",
"shoukaku": "github:shipgirlproject/Shoukaku#master",
Expand Down
183 changes: 183 additions & 0 deletions src/commands/music/Lyrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { Command, type Context, type Lavamusic } from "../../structures/index.js";
import { getLyrics } from "genius-lyrics-api";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } from "discord.js";

export default class Lyrics extends Command {
constructor(client: Lavamusic) {
super(client, {
name: "lyrics",
description: {
content: "cmd.lyrics.description",
examples: ["lyrics"],
usage: "lyrics",
},
category: "music",
aliases: ["ly"],
cooldown: 3,
args: false,
vote: false,
player: {
voice: true,
dj: false,
active: true,
djPerm: null,
},
permissions: {
dev: false,
client: ["SendMessages", "ReadMessageHistory", "ViewChannel", "EmbedLinks"],
user: [],
},
slashCommand: true,
options: [],
});
}

public async run(client: Lavamusic, ctx: Context): Promise<any> {
const player = client.queue.get(ctx.guild!.id);
const embed = this.client.embed();

if (!(player && !player.isPlaying)) {
return await ctx.sendMessage({
embeds: [embed.setColor(client.color.red).setDescription(ctx.locale("cmd.lyrics.errors.no_playing"))],
});
}

const currentTrack = player.current;
const trackTitle = currentTrack.info.title.replace(/\[.*?\]/g, "").trim();
const artistName = currentTrack.info.author.replace(/\[.*?\]/g, "").trim();
const trackUrl = currentTrack.info.uri;
const artworkUrl = currentTrack.info.artworkUrl;

await ctx.sendDeferMessage(ctx.locale("cmd.lyrics.searching", { trackTitle }));

const options = {
apiKey: client.config.lyricsApi,
title: trackTitle,
artist: artistName,
optimizeQuery: true,
};

try {
const lyrics = await getLyrics(options);
if (lyrics) {
const lyricsPages = this.paginateLyrics(lyrics);
let currentPage = 0;

const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId("prev")
.setEmoji(this.client.emoji.page.back)
.setStyle(ButtonStyle.Secondary)
.setDisabled(true),
new ButtonBuilder().setCustomId("stop").setEmoji(this.client.emoji.page.cancel).setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId("next")
.setEmoji(this.client.emoji.page.next)
.setStyle(ButtonStyle.Secondary)
.setDisabled(lyricsPages.length <= 1),
);

await ctx.editMessage({
embeds: [
embed
.setColor(client.color.main)
.setDescription(
ctx.locale("cmd.lyrics.lyrics_track", { trackTitle, trackUrl, lyrics: lyricsPages[currentPage] }),
)
.setThumbnail(artworkUrl)
.setTimestamp(),
],
components: [row],
});

const filter = (interaction) => interaction.user.id === ctx.author.id;
const collector = ctx.channel.createMessageComponentCollector({
filter,
componentType: ComponentType.Button,
time: 60000,
});

collector.on("collect", async (interaction) => {
if (interaction.customId === "prev") {
currentPage--;
} else if (interaction.customId === "next") {
currentPage++;
} else if (interaction.customId === "stop") {
collector.stop();
return interaction.update({ components: [] });
}

await interaction.update({
embeds: [
embed
.setDescription(
ctx.locale("cmd.lyrics.lyrics_track", { trackTitle, trackUrl, lyrics: lyricsPages[currentPage] }),
)
.setThumbnail(artworkUrl)
.setTimestamp(),
],
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId("prev")
.setEmoji(this.client.emoji.page.back)
.setStyle(ButtonStyle.Secondary)
.setDisabled(currentPage === 0),
new ButtonBuilder()
.setCustomId("stop")
.setEmoji(this.client.emoji.page.cancel)
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId("next")
.setEmoji(this.client.emoji.page.next)
.setStyle(ButtonStyle.Secondary)
.setDisabled(currentPage === lyricsPages.length - 1),
),
],
});
});

collector.on("end", () => {
ctx.editMessage({ components: [] });
});
} else {
await ctx.editMessage({
embeds: [embed.setColor(client.color.red).setDescription(ctx.locale("cmd.lyrics.errors.no_results"))],
});
}
} catch (error) {
console.error(error);
await ctx.editMessage({
embeds: [embed.setColor(client.color.red).setDescription(ctx.locale("cmd.lyrics.errors.lyrics_error"))],
});
}
}

paginateLyrics(lyrics) {
const lines = lyrics.split("\n");
const pages = [];
let page = "";

for (const line of lines) {
if (page.length + line.length > 2048) {
pages.push(page);
page = "";
}
page += `${line}\n`;
}

if (page) pages.push(page);
return pages;
}
}

/**
* Project: lavamusic
* Author: Appu
* Main Contributor: LucasB25
* Company: Coders
* Copyright (c) 2024. All rights reserved.
* This code is the property of Coder and may not be reproduced or
* modified without permission. For more information, contact us at
* https://discord.gg/ns8CTk9J3e
*/
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default {
guildId: process.env.GUILD_ID,
logChannelId: process.env.LOG_CHANNEL_ID,
commandLogs: process.env.LOG_COMMANDS_ID,
lyricsApi: process.env.GENIUS_API,
links: {
img: process.env.IMG_LINK || "https://i.imgur.com/ud3EWNh.jpg",
},
Expand Down
2 changes: 1 addition & 1 deletion src/events/client/VoiceStateUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ export default class VoiceStateUpdate extends Event {
* This code is the property of Coder and may not be reproduced or
* modified without permission. For more information, contact us at
* https://discord.gg/ns8CTk9J3e
*/
*/
2 changes: 1 addition & 1 deletion src/structures/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class Context {
this.message = ctx instanceof Message ? ctx : null;

if (ctx.channel && ctx.channel.type !== ChannelType.GroupDM) {
this.channel = ctx.channel
this.channel = ctx.channel;
} else {
this.channel = null;
}
Expand Down