Migrate to slash commands (#431)

Co-authored-by: Federico fuji97 Rapetti <fuji1097@gmail.com>
This commit is contained in:
Max Isom 2022-02-05 16:16:17 -06:00 committed by GitHub
parent e883275d83
commit 56a469a999
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 1270 additions and 1294 deletions

2
src/utils/constants.ts Normal file
View file

@ -0,0 +1,2 @@
export const ONE_HOUR_IN_SECONDS = 60 * 60;
export const ONE_MINUTE_IN_SECONDS = 1 * 60;

View file

@ -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}`;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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');
};

View file

@ -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;