diff --git a/.env b/.env index 6806c45..ceeb839 100644 --- a/.env +++ b/.env @@ -7,8 +7,6 @@ BOT_DISCORD_TOKEN=undefined BOT_DISCORD_CLIENT_ID=undefined BOT_DISCORD_OVERPOWERED_ID=undefined -BOT_YOUTUBE_COOKIE=undefined - BOT_SPOTIFY_CLIENT_SECRET=undefined BOT_SPOTIFY_CLIENT_ID=undefined @@ -18,5 +16,7 @@ BOT_SOUNDCLOUD_TOKEN=undefined BOT_YANDEXMUSIC_TOKEN=undefined BOT_YANDEXMUSIC_UID=undefined +BOT_GENIUS_TOKEN=undefined + MONGO_URI=undefined MONGO_DATABASE_NAME=undefined diff --git a/icons/audioplayer/player/lyrics.png b/icons/audioplayer/player/lyrics.png new file mode 100644 index 0000000..4b39bff Binary files /dev/null and b/icons/audioplayer/player/lyrics.png differ diff --git a/package.json b/package.json index f889ea4..510680d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aicbot", - "version": "3.0.1", + "version": "3.1.0", "description": "Discord Bot for playing music", "main": "build/main.js", "scripts": { @@ -29,6 +29,7 @@ "distube-apple-music": "^0.1.0", "distube-yandex-music-plugin": "^1.0.4", "dotenv": "^16.4.5", + "genius-lyrics": "^4.4.7", "i18next": "^22.5.1", "i18next-fs-backend": "^2.3.1", "mongoose": "^7.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13bf14e..df3fb9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: dotenv: specifier: ^16.4.5 version: 16.4.5 + genius-lyrics: + specifier: ^4.4.7 + version: 4.4.7 i18next: specifier: ^22.5.1 version: 22.5.1 @@ -649,8 +652,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -758,6 +761,9 @@ packages: engines: {node: '>=10'} deprecated: This package is no longer supported. + genius-lyrics@4.4.7: + resolution: {integrity: sha512-cgO5nSeFqtLZAUyWB+8XWMRBIRzPUSUC42N3CoDGRgKX1anGAyDUhM6/RVIJXCNnQa6XHZHswKcKgHaRiyl+GQ==} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -1176,8 +1182,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.12.2: - resolution: {integrity: sha512-x+NLUpx9SYrcwXtX7ob1gnkSems4i/mGZX5SlYxwIau6RrUSODO89TR/XDGGpn5RPWSYIB+aSfuSlV5+CmbTBg==} + qs@6.12.3: + resolution: {integrity: sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==} engines: {node: '>=0.6'} querystringify@2.2.0: @@ -2112,7 +2118,7 @@ snapshots: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -2142,7 +2148,7 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 - esquery@1.5.0: + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -2252,6 +2258,11 @@ snapshots: wide-align: 1.1.5 optional: true + genius-lyrics@4.4.7: + dependencies: + node-html-parser: 6.1.13 + undici: 6.19.2 + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -2622,7 +2633,7 @@ snapshots: punycode@2.3.1: {} - qs@6.12.2: + qs@6.12.3: dependencies: side-channel: 1.0.6 @@ -2764,7 +2775,7 @@ snapshots: formidable: 1.2.6 methods: 1.1.2 mime: 2.6.0 - qs: 6.12.2 + qs: 6.12.3 readable-stream: 3.6.2 semver: 7.6.2 transitivePeerDependencies: diff --git a/src/CommandTypes.ts b/src/CommandTypes.ts index 33e0e6e..26f4d60 100644 --- a/src/CommandTypes.ts +++ b/src/CommandTypes.ts @@ -19,13 +19,22 @@ export type SlashBuilder = | SlashCommandSubcommandsOnlyBuilder | Omit; export interface ICommand { - text_data: ITextCommandData; // Related to text commands - slash_data?: ISlashCommandData; // Related to slash commands - group: ICommandGroup; // Group for better orientation in /help - user_permissions?: Array; // Permissions for user, to allow executing commands - bot_permissions: Array; // Permissions for bot, to try to execute commands - hidden?: boolean; // Hidden from everything (disable slash_data property if true) - guild_data?: IGuildData; // Guild related data such as voice settings + // Disable command registering + disable?: boolean | false; + // Related to text commands + text_data: ITextCommandData; + // Related to slash commands + slash_data?: ISlashCommandData; + // Group for better orientation in /help + group: ICommandGroup; + // Permissions for user, to allow executing commands + user_permissions?: Array; + // Permissions for bot, to try to execute commands + bot_permissions: Array; + // Hidden from everything (disable slash_data property if true) + hidden?: boolean; + // Guild related data such as voice settings + guild_data?: IGuildData; } interface ITextCommandData { diff --git a/src/EnvironmentVariables.ts b/src/EnvironmentVariables.ts index 3ebdc9f..5a816ec 100644 --- a/src/EnvironmentVariables.ts +++ b/src/EnvironmentVariables.ts @@ -41,7 +41,9 @@ const envVariables = z.object({ BOT_SPOTIFY_CLIENT_ID: z.string().optional(), BOT_YANDEXMUSIC_TOKEN: z.string().optional(), - BOT_YANDEXMUSIC_UID: z.coerce.number().optional() + BOT_YANDEXMUSIC_UID: z.coerce.number().optional(), + + BOT_GENIUS_TOKEN: z.string().optional() }); export const ENV = envVariables.parse(process.env); diff --git a/src/audioplayer/AudioPlayerCore.ts b/src/audioplayer/AudioPlayerCore.ts index b16a8db..a86a364 100644 --- a/src/audioplayer/AudioPlayerCore.ts +++ b/src/audioplayer/AudioPlayerCore.ts @@ -11,6 +11,7 @@ import { LoadPlugins } from './LoadPlugins.js'; import { generateAddedPlaylistMessage } from './util/generateAddedPlaylistMessage.js'; import { generateAddedSongMessage } from './util/generateAddedSongMessage.js'; import { + ButtonInteraction, Client, CommandInteraction, Embed, @@ -22,6 +23,7 @@ import { } from 'discord.js'; import { joinVoiceChannel } from '@discordjs/voice'; import { generateWarningEmbed } from '../utilities/generateWarningEmbed.js'; +import { generateLyricsEmbed } from './Lyrics.js'; export const queueSongsLimit = 500; @@ -218,6 +220,26 @@ export class AudioPlayerCore { } } + async showLyrics(interaction: ButtonInteraction) { + if (!interaction.guild) return; + const queue = this.distube.getQueue(interaction.guild); + if (!queue) { + return; + } + + const song = queue.songs[0]; + + let lyricsQuery: string; + + if (song.source === 'youtube') { + lyricsQuery = song.name!; + } else { + lyricsQuery = `${song.name} - ${song.uploader.name}`; + } + + await interaction.reply({ embeds: [await generateLyricsEmbed(lyricsQuery)] }); + } + async showQueue(interaction: Interaction) { if (!interaction.guild) return; const queue = this.distube.getQueue(interaction.guild); diff --git a/src/audioplayer/AudioPlayerTypes.ts b/src/audioplayer/AudioPlayerTypes.ts index 55581f3..4126c2e 100644 --- a/src/audioplayer/AudioPlayerTypes.ts +++ b/src/audioplayer/AudioPlayerTypes.ts @@ -9,7 +9,8 @@ export enum AudioPlayerIcons { previous = '<:previousbutton:1092107334542696512>', skip = '<:skipbutton:1092107438234275900>', shuffle = '<:shufflebutton:1092107651384614912>', - list = '<:songlistwhite:1014551771705782405>' + list = '<:songlistwhite:1014551771705782405>', + lyrics = '<:lyrics:1260156581794811974>' } export enum AudioSourceIcons { diff --git a/src/audioplayer/LoadPlugins.ts b/src/audioplayer/LoadPlugins.ts index 14ec0cb..9730d5c 100644 --- a/src/audioplayer/LoadPlugins.ts +++ b/src/audioplayer/LoadPlugins.ts @@ -2,7 +2,6 @@ import { ExtractorPlugin, InfoExtractorPlugin, PlayableExtractorPlugin } from 'd import { BOT_YOUTUBE_COOKIE, ENV } from '../EnvironmentVariables.js'; import { loggerSend, loggerWarn } from '../utilities/logger.js'; import { SpotifyPlugin } from '@distube/spotify'; -import { SoundCloudPlugin } from '@distube/soundcloud'; import { YtDlpPlugin } from '@distube/yt-dlp'; import { loggerPrefixAudioplayer } from './AudioPlayerCore.js'; import { YouTubePlugin } from '@distube/youtube'; @@ -10,6 +9,7 @@ import { DirectLinkPlugin } from '@distube/direct-link'; import { FilePlugin } from '@distube/file'; import { AppleMusicPlugin } from 'distube-apple-music'; import { YandexMusicPlugin } from 'distube-yandex-music-plugin'; +import { SoundCloudPlugin } from '@distube/soundcloud'; export type DistubePlugin = ExtractorPlugin | InfoExtractorPlugin | PlayableExtractorPlugin; diff --git a/src/audioplayer/Lyrics.ts b/src/audioplayer/Lyrics.ts new file mode 100644 index 0000000..b61e0d9 --- /dev/null +++ b/src/audioplayer/Lyrics.ts @@ -0,0 +1,40 @@ +import Genius from 'genius-lyrics'; +import { ENV } from '../EnvironmentVariables.js'; +import { Colors, EmbedBuilder } from 'discord.js'; +import i18next from 'i18next'; +import { loggerWarn } from '../utilities/logger.js'; +import { generateErrorEmbed } from '../utilities/generateErrorEmbed.js'; +const Lyrics = new Genius.Client(ENV.BOT_GENIUS_TOKEN); + +if (!ENV.BOT_GENIUS_TOKEN) { + loggerWarn('BOT_GENIUS_TOKEN is not provided, lyrics module disabled', 'Lyrics'); +} + +export async function getLyricsSong(searchQuery: string) { + const geniusSearch = await Lyrics.songs.search(searchQuery); + + if (geniusSearch.length === 0) { + return undefined; + } + + return geniusSearch[0]; +} + +export async function generateLyricsEmbed(songQuery: string) { + const geniusSong = await getLyricsSong(songQuery); + + if (!geniusSong) { + return generateErrorEmbed(i18next.t('commands:lyrics_embed_lyrics_not_found')); + } + + const lyrics = await geniusSong.lyrics(); + + const lyricsText = lyrics.slice(0, 4096); + + return new EmbedBuilder() + .setTitle(geniusSong.title) + .setURL(geniusSong.url) + .setDescription(lyricsText) + .setColor(Colors.Yellow) + .setFooter({ text: i18next.t('commands:lyrics_embed_text_not_correct') }); +} diff --git a/src/audioplayer/MessagePlayerButtonsHandler.ts b/src/audioplayer/MessagePlayerButtonsHandler.ts index 3e17bae..34965ce 100644 --- a/src/audioplayer/MessagePlayerButtonsHandler.ts +++ b/src/audioplayer/MessagePlayerButtonsHandler.ts @@ -24,6 +24,7 @@ import { generateEmbedAudioPlayerPrevious, generateEmbedAudioPlayerPreviousFailure } from '../commands/audio/previous.command.js'; +import { ENV } from '../EnvironmentVariables.js'; enum ButtonIDs { stopMusic = 'stopMusic', @@ -33,7 +34,8 @@ enum ButtonIDs { skipSong = 'skipSong', //downloadSong = 'downloadSong', shuffle = 'shuffle', - showQueue = 'showQueue' + showQueue = 'showQueue', + lyrics = 'lyrics' } const rowPrimary = new ActionRowBuilder().addComponents( @@ -94,6 +96,15 @@ const rowSecondary = new ActionRowBuilder().addComponents( .setEmoji(AudioPlayerIcons.list) ); +if (ENV.BOT_GENIUS_TOKEN) { + rowSecondary.addComponents( + new ButtonBuilder() + .setCustomId(ButtonIDs.lyrics) + .setStyle(ButtonStyle.Secondary) + .setEmoji(AudioPlayerIcons.lyrics) + ); +} + const rowWithOnlyStop = new ActionRowBuilder().addComponents( new ButtonBuilder() .setCustomId(ButtonIDs.stopMusic) @@ -210,6 +221,10 @@ export class MessagePlayerButtonsHandler { } break; } + + case ButtonIDs.lyrics: { + await this.client.audioPlayer.showLyrics(ButtonInteraction); + } } } catch (e) { loggerError(e); diff --git a/src/commands/audio/lyrics.command.ts b/src/commands/audio/lyrics.command.ts new file mode 100644 index 0000000..e8a97c9 --- /dev/null +++ b/src/commands/audio/lyrics.command.ts @@ -0,0 +1,43 @@ +import { CommandArgument, ICommand } from '../../CommandTypes.js'; +import { Message, PermissionsBitField, SlashCommandBuilder } from 'discord.js'; +import i18next from 'i18next'; +import { services } from './play.command.js'; +import { GroupAudio } from './AudioTypes.js'; +import { generateLyricsEmbed } from '../../audioplayer/Lyrics.js'; +import { ENV } from '../../EnvironmentVariables.js'; + +export default function (): ICommand { + return { + disable: !ENV.BOT_GENIUS_TOKEN, + text_data: { + name: 'lyrics', + description: i18next.t('commands:lyrics_desc'), + arguments: [ + new CommandArgument(i18next.t('commands:lyrics_arg_query', { services: services }), true) + ], + execute: async (message: Message, args: string[]) => { + const songQuery = args.join(' '); + + await message.reply({ embeds: [await generateLyricsEmbed(songQuery)] }); + } + }, + slash_data: { + slash_builder: new SlashCommandBuilder() + .setName('lyrics') + .setDescription(i18next.t('commands:lyrics_desc')) + .addStringOption((option) => + option + .setName('request') + .setDescription(i18next.t('commands:lyrics_arg_query', { services: services })) + .setRequired(true) + ), + execute: async (interaction) => { + const songQuery = interaction.options.getString('request')!; + + await interaction.reply({ embeds: [await generateLyricsEmbed(songQuery)] }); + } + }, + group: GroupAudio, + bot_permissions: [PermissionsBitField.Flags.SendMessages, PermissionsBitField.Flags.ViewChannel] + }; +} diff --git a/src/commands/audio/play.command.ts b/src/commands/audio/play.command.ts index 9629c7e..d202c8b 100644 --- a/src/commands/audio/play.command.ts +++ b/src/commands/audio/play.command.ts @@ -20,7 +20,7 @@ import ytsr from '@distube/ytsr'; import { queueSongsLimit } from '../../audioplayer/AudioPlayerCore.js'; import { generateWarningEmbed } from '../../utilities/generateWarningEmbed.js'; -export const services = 'Youtube, Spotify, Soundcloud, Yandex Music, HTTP-stream'; +export const services = 'Youtube, Spotify, Soundcloud, Yandex Music, Apple Music, HTTP-stream'; export default function (): ICommand { return { text_data: { @@ -30,6 +30,8 @@ export default function (): ICommand { new CommandArgument(i18next.t('commands:play_arg_link', { services: services }), true) ], execute: async (message: Message, args: string[]) => { + // Play command accept only one arg is a query string. + // In text command system we need to merge all words for request in one string const songQuery = args.join(' '); const member = message.member as GuildMember; diff --git a/src/handlers/Command.handler.ts b/src/handlers/Command.handler.ts index 19e160c..4466572 100644 --- a/src/handlers/Command.handler.ts +++ b/src/handlers/Command.handler.ts @@ -1,5 +1,5 @@ import { Client, Collection, REST, Routes } from 'discord.js'; -import { loggerError, loggerSend } from '../utilities/logger.js'; +import { loggerError, loggerSend, loggerWarn } from '../utilities/logger.js'; import { ICommand, ICommandGroup, SlashBuilder } from '../CommandTypes.js'; import * as fs from 'fs'; import * as path from 'path'; @@ -30,6 +30,12 @@ const handler = async (client: Client) => { const commandModule = await import(importPath); const command: ICommand = commandModule.default(); + + if (command.disable) { + loggerWarn(`Command is disabled: ${importPath}`, loggerPrefixCommandHandler); + continue; + } + const group: ICommandGroup = command.group; commands.set(command.text_data.name, command); diff --git a/src/locales/en/commands.json b/src/locales/en/commands.json index 763f7f0..71c52e8 100644 --- a/src/locales/en/commands.json +++ b/src/locales/en/commands.json @@ -65,5 +65,9 @@ "status_embed_cpu": "CPU", "status_embed_cpu_usage": "CPU Usage", "status_embed_ram_usage": "RAM Usage", - "status_embed_guilds_count": "Servers count" + "status_embed_guilds_count": "Servers count", + "lyrics_desc": "Searching lyrics", + "lyrics_arg_query": "title of song", + "lyrics_embed_text_not_correct": "The text may not be correct", + "lyrics_embed_lyrics_not_found": "Lyrics not found" } diff --git a/src/locales/ru/commands.json b/src/locales/ru/commands.json index 7e64d87..3485a38 100644 --- a/src/locales/ru/commands.json +++ b/src/locales/ru/commands.json @@ -65,5 +65,9 @@ "status_embed_cpu": "Процессор", "status_embed_cpu_usage": "Нагрузка на процессор", "status_embed_ram_usage": "Используется ОЗУ", - "status_embed_guilds_count": "Количество серверов" + "status_embed_guilds_count": "Количество серверов", + "lyrics_desc": "Ищет текст песни", + "lyrics_arg_query": "Название песни", + "lyrics_embed_text_not_correct": "Текст может быть неверным", + "lyrics_embed_lyrics_not_found": "Текст песни не найден" } diff --git a/wiki/API-Configure.md b/wiki/API-Configure.md index 4c13f4c..df37740 100644 --- a/wiki/API-Configure.md +++ b/wiki/API-Configure.md @@ -22,6 +22,7 @@ You can edit your application's name, description, and avatar here. Once you've ![discord-dev-enable-intents](images/api-configure/discord-dev-enable-intents.png) # YouTube Cookie (optional) + Preferable to provide cookies for YouTube. This will allow you to play 18+ videos and bypass YouTube rate limiting error (429 Error). I highly recommend that you create a new Google account from which you can get the cookie. @@ -38,23 +39,27 @@ I highly recommend that you create a new Google account from which you can get t 5. Create file yt-cookies.json and paste cookie in this file # Yandex Music (optional) + If you do not provide token and UID, Yandex Music will not work at all. > [!WARNING] > If your bot is outside Russia VDS, you must have a Yandex Plus subscription to play songs. ## Token -1. Login into [Yandex](https://passport.yandex.ru/auth) account. + +1. Login into [Yandex](https://passport.yandex.ru/auth) account. 2. Download [browser extension](https://chromewebstore.google.com/detail/yandex-music-token/lcbjeookjibfhjjopieifgjnhlegmkib) -This must look like this ![yandex-extension](images/api-configure/yandex-music-extension.png) + This must look like this ![yandex-extension](images/api-configure/yandex-music-extension.png) 3. Click "Скопировать токен" button. ## UID + 1. Login into [Yandex](https://passport.yandex.ru/auth) account. 2. You can retrieve uid by opening [Yandex Mail](https://mail.yandex.ru) and copy uid from the url in the address bar. -![yandex-uid](images/api-configure/yandex-music-uid.png) + ![yandex-uid](images/api-configure/yandex-music-uid.png) # Spotify (optional) + Spotify Module can work without provided data, but for more stability better provide custom application data. > [!WARNING] @@ -76,3 +81,12 @@ Spotify Module can work without provided data, but for more stability better pro 4. Find the request that has the name session (you can filter by typing session in the filter box) and click on it 5. Go to the Payload tab 6. You should see your client id in the Query String Parameters section, and your oauth token (access_token) in the Request Payload section + +# Genius (optional) + +> [!WARNING] +> Provide to enable /lyrics command and lyrics button in audioplayer + +1. Go to [Genius](https://genius.com/login) and login. +2. Go to [Genius Developer Dashboard](https://genius.com/api-clients/new) and create a new app +3. Generate and copy client access token diff --git a/wiki/Setup.md b/wiki/Setup.md index 351960c..bba576e 100644 --- a/wiki/Setup.md +++ b/wiki/Setup.md @@ -5,29 +5,31 @@ But in both cases, you need to configure .env file. Also you need retrieve token, client id and enable intents on Discord Developer Portal. -- Create file .env.production -- Fill all fields in .env.production. If the field is marked as (Optional), you can skip it. +- Create file .env.production (if you developer create .env.development) +- Fill all fields in .env.* If the field is marked as (Optional), you can skip it. - (Required) To get Discord Token and enable intents, follow the [Discord Developer Portal](https://github.com/AlexInCube/AlCoTest/wiki/API-Configure#discord-developer-portal-required) section. - (Optional) To get Spotify Secret and ID, follow the [Spotify](https://github.com/AlexInCube/AlCoTest/wiki/API-Configure#spotify-optional) section. - (Optional) To get Yandex Music token, follow the [Yandex Music](https://github.com/AlexInCube/AlCoTest/wiki/API-Configure#yandex-music-optional) section. - (Optional) To get SoundCloud token, follow the [Soundcloud](https://github.com/AlexInCube/AlCoTest/wiki/API-Configure#soundcloud-optional) section. - -| Name | Example | Description | Required? | -|------------------------------|-----------------------|---------------------------------------------------------------------------|-----------| -| `BOT_VERBOSE_LOGGING` | false | The bot will give more information to the console, useful for debugging | ❌ | -| `BOT_COMMAND_PREFIX` | // | Used only for text commands | ✔️ | -| `BOT_LANGUAGE` | en | Supported values: en ru | ❌ | -| `MONGO_URI` | mongodb://mongo:27017 | The public key for sending notifications | ✔️ | -| `MONGO_DATABASE_NAME` | aicbot | Database name in MongoDB | ✔️ | -| `BOT_DISCORD_TOKEN` | ODEzNzUwMTY1N... | Token from Discord Developer Portal | ✔️ | -| `BOT_DISCORD_CLIENT_ID` | 813750165783... | Application ID from Discord Developer Portal | ✔️ | -| `BOT_DISCORD_OVERPOWERED_ID` | 29016845994426.... | Discord bot owner user ID, required for having more bot control for owner | ✔️ | -| `BOT_SPOTIFY_CLIENT_SECRET` | | Used when the Spotify module cannot get the credentials automatically | ❌ | -| `BOT_SPOTIFY_CLIENT_ID` | | Used when the Spotify module get the credentials automatically | ❌ | -| `BOT_YANDEXMUSIC_TOKEN` | | Provide to enable Yandex Music module | ❌ | -| `BOT_YANDEXMUSIC_UID` | | Provide to enable Yandex Music module | ❌ | -| `BOT_SOUNDCLOUD_CLIENT_ID` | | Provide to fetch more data with SoundCloud Go+ account | ❌ | -| `BOT_SOUNDCLOUD_TOKEN` | | Provide to fetch more data with SoundCloud Go+ account | ❌ | +- (Optional) To get Genius token, follow the [Genius](https://github.com/AlexInCube/AlCoTest/wiki/API-Configure#genius-optional) section. + +| Name | Example | Description | Required | +|------------------------------|-----------------------|---------------------------------------------------------------------------|----------| +| `BOT_VERBOSE_LOGGING` | false | The bot will give more information to the console, useful for debugging | ❌ | +| `BOT_COMMAND_PREFIX` | // | Used only for text commands | ✔️ | +| `BOT_LANGUAGE` | en | Supported values: en ru | ❌ | +| `MONGO_URI` | mongodb://mongo:27017 | The public key for sending notifications | ✔️ | +| `MONGO_DATABASE_NAME` | aicbot | Database name in MongoDB | ✔️ | +| `BOT_DISCORD_TOKEN` | ODEzNzUwMTY1N... | Token from Discord Developer Portal | ✔️ | +| `BOT_DISCORD_CLIENT_ID` | 813750165783... | Application ID from Discord Developer Portal | ✔️ | +| `BOT_DISCORD_OVERPOWERED_ID` | 29016845994426.... | Discord bot owner user ID, required for having more bot control for owner | ✔️ | +| `BOT_SPOTIFY_CLIENT_SECRET` | | Used when the Spotify module cannot get the credentials automatically | ❌ | +| `BOT_SPOTIFY_CLIENT_ID` | | Used when the Spotify module get the credentials automatically | ❌ | +| `BOT_YANDEXMUSIC_TOKEN` | | Provide to enable Yandex Music module | ❌ | +| `BOT_YANDEXMUSIC_UID` | | Provide to enable Yandex Music module | ❌ | +| `BOT_SOUNDCLOUD_CLIENT_ID` | | Provide to fetch more data with SoundCloud Go+ account | ❌ | +| `BOT_SOUNDCLOUD_TOKEN` | | Provide to fetch more data with SoundCloud Go+ account | ❌ | +| `BOT_GENIUS_TOKEN` | | Provide to fetch songs lyrics from Genius | | # 🐋 Run in Docker (recommended) @@ -56,7 +58,7 @@ AICoTest/ - Install C++ compiler. Follow this [guide](https://github.com/nodejs/node-gyp#on-windows) - Install FFMpeg. Follow this [guide](https://www.wikihow.com/Install-FFmpeg-on-Windows) - Clone repository to your computer -- Follow the [Configure .env](#-configure-env) section and copy .env.production in folder with repository. +- Follow the [Configure .env](#-configure-env) section and copy .env.development in folder with repository. - (Optional) Follow the [YouTube Cookie](https://github.com/AlexInCube/AlCoTest/wiki/API-Configure#-youtube-cookie-optional) and copy yt-cookies.json in the folder with repository. - Install Node.js packages in the folder with repository @@ -75,3 +77,7 @@ npm run build ``` npm run production ``` +or if you are a developer +``` +npm run development +```