aboutsummaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
authorMax Isom <[email protected]>2022-02-05 16:16:17 -0600
committerGitHub <[email protected]>2022-02-05 16:16:17 -0600
commit56a469a999774c8b8683adeb59b243fdf85b14c9 (patch)
tree2e11f067d6e4caae9301986a0b432825cc65839e /src/utils
parente883275d831f3d9bf3a57bd91e0deeeaf4951242 (diff)
downloadmuse-56a469a999774c8b8683adeb59b243fdf85b14c9.tar.xz
muse-56a469a999774c8b8683adeb59b243fdf85b14c9.zip
Migrate to slash commands (#431)
Co-authored-by: Federico fuji97 Rapetti <[email protected]>
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/constants.ts2
-rw-r--r--src/utils/error-msg.ts2
-rw-r--r--src/utils/get-youtube-and-spotify-suggestions-for.ts70
-rw-r--r--src/utils/get-youtube-suggestions-for.ts15
-rw-r--r--src/utils/loading-message.ts81
-rw-r--r--src/utils/log-banner.ts1
-rw-r--r--src/utils/update-permissions-for-guild.ts44
7 files changed, 133 insertions, 82 deletions
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
new file mode 100644
index 0000000..70d9e2c
--- /dev/null
+++ b/src/utils/constants.ts
@@ -0,0 +1,2 @@
+export const ONE_HOUR_IN_SECONDS = 60 * 60;
+export const ONE_MINUTE_IN_SECONDS = 1 * 60;
diff --git a/src/utils/error-msg.ts b/src/utils/error-msg.ts
index 832de3c..0f4e0b2 100644
--- a/src/utils/error-msg.ts
+++ b/src/utils/error-msg.ts
@@ -5,7 +5,7 @@ export default (error?: string | Error): string => {
if (typeof error === 'string') {
str = `🚫 ${error}`;
} else if (error instanceof Error) {
- str = `🚫 ope: ${error.name}`;
+ str = `🚫 ope: ${error.message}`;
}
}
diff --git a/src/utils/get-youtube-and-spotify-suggestions-for.ts b/src/utils/get-youtube-and-spotify-suggestions-for.ts
new file mode 100644
index 0000000..10f9394
--- /dev/null
+++ b/src/utils/get-youtube-and-spotify-suggestions-for.ts
@@ -0,0 +1,70 @@
+import {ApplicationCommandOptionChoice} from 'discord.js';
+import SpotifyWebApi from 'spotify-web-api-node';
+import getYouTubeSuggestionsFor from './get-youtube-suggestions-for.js';
+
+const filterDuplicates = <T extends {name: string}>(items: T[]) => {
+ const results: T[] = [];
+
+ for (const item of items) {
+ if (!results.some(result => result.name === item.name)) {
+ results.push(item);
+ }
+ }
+
+ return results;
+};
+
+const getYouTubeAndSpotifySuggestionsFor = async (query: string, spotify: SpotifyWebApi, limit = 10): Promise<ApplicationCommandOptionChoice[]> => {
+ const [youtubeSuggestions, spotifyResults] = await Promise.all([
+ getYouTubeSuggestionsFor(query),
+ spotify.search(query, ['track', 'album'], {limit: 5}),
+ ]);
+
+ const totalYouTubeResults = youtubeSuggestions.length;
+
+ const spotifyAlbums = filterDuplicates(spotifyResults.body.albums?.items ?? []);
+ const spotifyTracks = filterDuplicates(spotifyResults.body.tracks?.items ?? []);
+
+ const totalSpotifyResults = spotifyAlbums.length + spotifyTracks.length;
+
+ // Number of results for each source should be roughly the same.
+ // If we don't have enough Spotify suggestions, prioritize YouTube results.
+ const maxSpotifySuggestions = Math.floor(limit / 2);
+ const numOfSpotifySuggestions = Math.min(maxSpotifySuggestions, totalSpotifyResults);
+
+ const maxYouTubeSuggestions = limit - numOfSpotifySuggestions;
+ const numOfYouTubeSuggestions = Math.min(maxYouTubeSuggestions, totalYouTubeResults);
+
+ const suggestions: ApplicationCommandOptionChoice[] = [];
+
+ suggestions.push(
+ ...youtubeSuggestions
+ .slice(0, numOfYouTubeSuggestions)
+ .map(suggestion => ({
+ name: `YouTube: ${suggestion}`,
+ value: suggestion,
+ }),
+ ));
+
+ const maxSpotifyAlbums = Math.floor(numOfSpotifySuggestions / 2);
+ const numOfSpotifyAlbums = Math.min(maxSpotifyAlbums, spotifyResults.body.albums?.items.length ?? 0);
+ const maxSpotifyTracks = numOfSpotifySuggestions - numOfSpotifyAlbums;
+
+ suggestions.push(
+ ...spotifyAlbums.slice(0, maxSpotifyAlbums).map(album => ({
+ name: `Spotify: 💿 ${album.name}${album.artists.length > 0 ? ` - ${album.artists[0].name}` : ''}`,
+ value: `spotify:album:${album.id}`,
+ })),
+ );
+
+ suggestions.push(
+ ...spotifyTracks.slice(0, maxSpotifyTracks).map(track => ({
+ name: `Spotify: 🎵 ${track.name}${track.artists.length > 0 ? ` - ${track.artists[0].name}` : ''}`,
+ value: `spotify:track:${track.id}`,
+ })),
+ );
+
+ return suggestions;
+};
+
+export default getYouTubeAndSpotifySuggestionsFor;
diff --git a/src/utils/get-youtube-suggestions-for.ts b/src/utils/get-youtube-suggestions-for.ts
new file mode 100644
index 0000000..11977e4
--- /dev/null
+++ b/src/utils/get-youtube-suggestions-for.ts
@@ -0,0 +1,15 @@
+import got from 'got';
+
+const getYouTubeSuggestionsFor = async (query: string): Promise<string[]> => {
+ const [_, suggestions] = await got('https://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=', {
+ searchParams: {
+ client: 'firefox',
+ ds: 'yt',
+ q: query,
+ },
+ }).json<[string, string[]]>();
+
+ return suggestions;
+};
+
+export default getYouTubeSuggestionsFor;
diff --git a/src/utils/loading-message.ts b/src/utils/loading-message.ts
deleted file mode 100644
index 53a2aed..0000000
--- a/src/utils/loading-message.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import {TextChannel, Message, MessageReaction} from 'discord.js';
-import delay from 'delay';
-
-const INITAL_DELAY = 500;
-const PERIOD = 500;
-
-export default class {
- public isStopped = true;
- private readonly channel: TextChannel;
- private readonly text: string;
- private msg!: Message;
-
- constructor(channel: TextChannel, text = 'cows! count \'em') {
- this.channel = channel;
- this.text = text;
- }
-
- async start(): Promise<void> {
- this.msg = await this.channel.send(this.text);
-
- const icons = ['🐮', '🐴', '🐄'];
-
- const reactions: MessageReaction[] = [];
-
- let i = 0;
- let isRemoving = false;
-
- this.isStopped = false;
-
- (async () => {
- await delay(INITAL_DELAY);
-
- while (!this.isStopped) {
- if (reactions.length === icons.length) {
- isRemoving = true;
- }
-
- // eslint-disable-next-line no-await-in-loop
- await delay(PERIOD);
-
- if (isRemoving) {
- const reactionToRemove = reactions.shift();
-
- if (reactionToRemove) {
- // eslint-disable-next-line no-await-in-loop
- await reactionToRemove.users.remove(this.msg.client.user!.id);
- } else {
- isRemoving = false;
- }
- } else {
- if (!this.isStopped) {
- // eslint-disable-next-line no-await-in-loop
- reactions.push(await this.msg.react(icons[i % icons.length]));
- }
-
- i++;
- }
- }
- })();
- }
-
- async stop(str = 'u betcha'): Promise<Message> {
- const wasAlreadyStopped = this.isStopped;
-
- this.isStopped = true;
-
- const editPromise = str ? this.msg.edit(str) : null;
- const reactPromise = str && !wasAlreadyStopped ? (async () => {
- await this.msg.fetch();
- await Promise.all(this.msg.reactions.cache.map(async react => {
- if (react.me) {
- await react.users.remove(this.msg.client.user!.id);
- }
- }));
- })() : null;
-
- await Promise.all([editPromise, reactPromise]);
-
- return this.msg;
- }
-}
diff --git a/src/utils/log-banner.ts b/src/utils/log-banner.ts
index 0ad6466..9cde988 100644
--- a/src/utils/log-banner.ts
+++ b/src/utils/log-banner.ts
@@ -9,6 +9,7 @@ const logBanner = () => {
paypalUser: 'codetheweb',
githubSponsor: 'codetheweb',
madeByPrefix: 'Made with 🎶 by ',
+ buildDate: process.env.BUILD_DATE ? new Date(process.env.BUILD_DATE) : undefined,
}).join('\n'));
console.log('\n');
};
diff --git a/src/utils/update-permissions-for-guild.ts b/src/utils/update-permissions-for-guild.ts
new file mode 100644
index 0000000..ca7c427
--- /dev/null
+++ b/src/utils/update-permissions-for-guild.ts
@@ -0,0 +1,44 @@
+import {ApplicationCommandPermissionData, Guild} from 'discord.js';
+import {prisma} from './db.js';
+
+const COMMANDS_TO_LIMIT_TO_GUILD_OWNER = ['config'];
+
+const updatePermissionsForGuild = async (guild: Guild) => {
+ const settings = await prisma.setting.findUnique({
+ where: {
+ guildId: guild.id,
+ },
+ });
+
+ if (!settings) {
+ throw new Error('could not find settings for guild');
+ }
+
+ const permissions: ApplicationCommandPermissionData[] = [
+ {
+ id: guild.ownerId,
+ type: 'USER',
+ permission: true,
+ },
+ {
+ id: guild.roles.everyone.id,
+ type: 'ROLE',
+ permission: false,
+ },
+ ];
+ const commands = await guild.commands.fetch();
+
+ await guild.commands.permissions.set({fullPermissions: commands.map(command => ({
+ id: command.id,
+ permissions: COMMANDS_TO_LIMIT_TO_GUILD_OWNER.includes(command.name) ? permissions : [
+ ...permissions,
+ ...(settings.roleId ? [{
+ id: settings.roleId,
+ type: 'ROLE' as const,
+ permission: true,
+ }] : []),
+ ],
+ }))});
+};
+
+export default updatePermissionsForGuild;