Skip to content

Commit

Permalink
Merge pull request #15 from acdvs/develop
Browse files Browse the repository at this point in the history
Switch to DB storage for multi-server
  • Loading branch information
acdvs authored Jan 8, 2021
2 parents 1ec9bff + 604a544 commit 279e36a
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 207 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
settings.json
*.db
*.code-workspace

# Logs
Expand Down Expand Up @@ -73,7 +73,7 @@ typings/

# dotenv environment variables file
.env
.env.test
.env.*

# parcel-bundler cache (https://parceljs.org/)
.cache
Expand Down
34 changes: 10 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,26 @@

A simple Discord bot for getting game discount info from [isthereanydeal.com](https://isthereanydeal.com).

## Requirements
## Usage

- Node.js v12
- A [Discord bot token](https://discord.com/developers/applications)
- An [isthereanydeal.com API key](https://isthereanydeal.com/dev/app)
1. [Click here][invite-link] to invite the bot to your server.
2. Once the bot has joined, use the commands below in any channel!

## Setup
## Support the Project

Clone the repository to any local folder.

Create a `.env` file in the folder with the following contents:

```
BOT_TOKEN=[token]
ITAD_KEY=[key]
```

Replace `[token]` with your Discord bot token. Replace `[key]` with your ITAD API key.

Finally, run the following commands:

```sh
$ npm install
$ node lib/index.js
```
If you like what you see, consider helping with monthly server costs by clicking the "Sponsor" button on the repo or by following [this link][donate-link]. Any amount helps!

## Features

- `$help`
Help me help you!
Forgot the commands again?
- `$deals [game]`
Gets a list of current deals for the specified game. Lookup relies on spelling, so misspellings may return nothing. If an exact match is not found, the bot will attempt to suggest something similar.
- `$sellers`
Lists all sellers.
- `$ignoredsellers`
Lists all ignored sellers. Ignored sellers do not appear in `$deals` lists.
- `$ignoredsellers [add|remove] [seller]`
- `$ignoredsellers [add|remove|clear] [seller]`
Adds or removes an ignored seller. Seller must be spelled exactly as it appears in the `$sellers` command.
- `$top [waitlisted|collected|popular]`
Gets the top waitlisted, collected, or popular games.
Expand All @@ -48,3 +31,6 @@ Gets the top waitlisted, collected, or popular games.
## License

IsThereAnyDeal Lookup is licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).

[invite-link]: https://discord.com/api/oauth2/authorize?client_id=722942824999288924&permissions=93248&redirect_uri=https%3A%2F%2Fgithub.com%2Facdvs%2Fisthereanydeal-lookup&scope=bot
[donate-link]: https://www.patreon.com/acdvs
86 changes: 37 additions & 49 deletions lib/commands/deals.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const Discord = require('discord.js');
const apiUtil = require('../util/api');
const dbUtil = require('../util/db/db');

const SEARCH_EMOJIS = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣'];
const CHAR_LIMIT = 1024;
Expand All @@ -10,19 +11,18 @@ const CHAR_LIMIT = 1024;
* Get game deals
* @param {Object} msg Discord message
* @param {string} game
* @param {Array} ignoredSellers
*/
module.exports = async (msg, game, ignoredSellers) => {
module.exports = async (msg, game) => {
try {
const gameId = await apiUtil.getGameId(game);

if (gameId) {
generateEmbed(msg, game, gameId, ignoredSellers);
generateEmbed(msg, game, gameId);
} else {
let similarGames = await apiUtil.search(game, 5);

if (similarGames.length > 0) {
getAlternative(msg, similarGames, game, ignoredSellers);
getAlternative(msg, similarGames, game);
} else {
msg.channel.send(`No results were found for "${game}". Did you spell it correctly?`);
}
Expand All @@ -37,10 +37,9 @@ module.exports = async (msg, game, ignoredSellers) => {
* @param {Discord.Message} msg
* @param {Array} similarGames
* @param {string} game
* @param {Aray} ignoredSellers
* @returns {integer}
*/
async function getAlternative(msg, similarGames, game, ignoredSellers) {
async function getAlternative(msg, similarGames, game) {
const reply = await msg.channel.send(
new Discord.MessageEmbed({
author: {
Expand Down Expand Up @@ -71,7 +70,7 @@ async function getAlternative(msg, similarGames, game, ignoredSellers) {
const alternativeId = similarGames[listIndex].plain;
const alternativeName = similarGames[listIndex].title;

generateEmbed(msg, alternativeName, alternativeId, ignoredSellers);
generateEmbed(msg, alternativeName, alternativeId);
});

collector.on('end', () => reply.reactions.removeAll());
Expand All @@ -82,10 +81,10 @@ async function getAlternative(msg, similarGames, game, ignoredSellers) {
* @param {Discord.Message} msg Discord message
* @param {string} game
* @param {integer} gameId
* @param {Array} ignoredSellers
*/
async function generateEmbed(msg, game, gameId, ignoredSellers) {
async function generateEmbed(msg, game, gameId) {
try {
const ignoredSellers = await dbUtil.getIgnoredSellers(msg.guild.id);
const gameData = await apiUtil.getGameData(gameId, ignoredSellers);
const list = gameData && gameData.list.filter(x => x.price_new < x.price_old);

Expand All @@ -112,15 +111,17 @@ async function generateEmbed(msg, game, gameId, ignoredSellers) {
color: 0x23B2D5
});

let rowCount = 0;
let sellersFieldVal;

// Check for field value overflow and add an extra line
// with a link to ITAD for deals that don't fit.
if (sellers.join('\n').length > CHAR_LIMIT) {
// Overflow row needs to be predetermined to account for
// it's possible length for insertion.
const getOverflowText = rowCount => `[...and ${sellers.length - rowCount} more deals](${gameData.urls.game})`;
// its possible length for insertion.
const getOverflowText = currRowCount => `[...and ${sellers.length - currRowCount} more deals](${gameData.urls.game})`;

let charTotal = getOverflowText(100).length;
let rowCount = 0;

for (let i = 0; i < sellers.length; i++) {
charTotal += sellers[i].length;
Expand All @@ -131,46 +132,33 @@ async function generateEmbed(msg, game, gameId, ignoredSellers) {
}
}

embed.addFields([
{
name: 'Seller',
value: [
...sellers.slice(0, rowCount),
getOverflowText(rowCount)
].join('\n'),
inline: true
},
{
name: 'New Price',
value: newPrices.slice(0, rowCount).join('\n'),
inline: true
},
{
name: 'Old Price',
value: oldPrices.slice(0, rowCount).join('\n'),
inline: true
}
]);
sellersFieldVal = [
...sellers.slice(0, rowCount),
getOverflowText(rowCount)
].join('\n');
} else {
embed.addFields([
{
name: 'Seller',
value: sellers.join('\n'),
inline: true
},
{
name: 'New Price',
value: newPrices.join('\n'),
inline: true
},
{
name: 'Old Price',
value: oldPrices.join('\n'),
inline: true
}
]);
rowCount = sellers.length;
sellersFieldVal = sellers.join('\n');
}

embed.addFields([
{
name: 'Seller',
value: sellersFieldVal,
inline: true
},
{
name: 'New Price',
value: newPrices.slice(0, rowCount).join('\n'),
inline: true
},
{
name: 'Old Price',
value: oldPrices.slice(0, rowCount).join('\n'),
inline: true
}
]);

const histLowData = await apiUtil.getHistoricalLow(gameId);

if (histLowData) {
Expand Down
6 changes: 5 additions & 1 deletion lib/commands/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const Discord = require('discord.js');
module.exports = (msg, prefix) => {
const embed = new Discord.MessageEmbed({
title: 'IsThereAnyDeal Lookup Help',
description: [
'If you like the bot, consider helping with monthly server costs.',
'[Donate via Patreon](https://www.patreon.com/acdvs). Any amount helps!'
].join('\n'),
color: 0x23B2D5,
fields: [
{
Expand All @@ -32,7 +36,7 @@ module.exports = (msg, prefix) => {
].join('\n')
},
{
name: `${prefix}ignoredsellers [add|remove] [seller]`,
name: `${prefix}ignoredsellers [add|remove|clear] [seller]`,
value: [
'Adds or removes an ignored seller.',
'Seller must be spelled exactly as it appears in the `$sellers` command.'
Expand Down
39 changes: 16 additions & 23 deletions lib/commands/ignoredSellers.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
'use strict';

const Discord = require('discord.js');
const apiUtil = require('../util/api');
const settingsUtil = require('../util/settings');
const dbUtil = require('../util/db/db');

/**
* Get, add, or remove ignored sellers
* @param {Object} msg Discord message
* @param {string} options Message options
* @param {Object} settings Instance settings
*/
module.exports = async (msg, options, settings) => {
module.exports = async (msg, options) => {
if (!options) {
if (settings.ignoredSellers.length > 0) {
const ignoredSellers = await dbUtil.getIgnoredSellers(msg.guild.id);

if (ignoredSellers.length > 0) {
msg.channel.send(
new Discord.MessageEmbed({
title: `Ignored sellers (${settings.ignoredSellers.length})`,
description: settings.ignoredSellers.map(x => x.title).join('\n'),
title: `Ignored sellers (${ignoredSellers.length})`,
description: ignoredSellers.map(x => x.title).join('\n'),
color: 0x23B2D5
})
);
Expand All @@ -30,32 +30,25 @@ module.exports = async (msg, options, settings) => {
let [operation, seller] = options.split(/\s+(.*)/);
let changed = false;

try {
if (seller) {
if (operation === 'add') {
const sellerIsIgnored = !!settings.ignoredSellers.find(x => x.title === seller);
const sellers = await apiUtil.getSellers();

seller = sellers.filter(x => x.title === seller);
seller = seller && seller[0];
const sellerIsIgnored = await dbUtil.hasIgnoredSeller(msg.guild.id, seller);

if (seller && !sellerIsIgnored) {
settings.ignoredSellers.push({ id: seller.id, title: seller.title });
changed = true;
if (!sellerIsIgnored) {
changed = await dbUtil.addIgnoredSeller(msg.guild.id, seller);
}
} else if (operation === 'remove') {
const index = settings.ignoredSellers.findIndex(x => x.title === seller);
const sellerIsIgnored = await dbUtil.hasIgnoredSeller(msg.guild.id, seller);

if (index > -1) {
settings.ignoredSellers.splice(index, 1);
changed = true;
if (sellerIsIgnored) {
changed = await dbUtil.removeIgnoredSeller(msg.guild.id, seller);
}
}
} catch (e) {
console.error(e);
} else if (operation === 'clear') {
changed = await dbUtil.clearIgnoredSellers(msg.guild.id);
}

if (changed) {
settingsUtil.save(settings);
msg.react('✅');
}
};
4 changes: 3 additions & 1 deletion lib/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ module.exports = {
top: require('./top')
};

// Command prefix
module.exports.PREFIX = '$';
// Seconds before another command can run
module.exports.LIMIT_SECONDS = 2;
module.exports.LIMIT_SECONDS = 3;
4 changes: 2 additions & 2 deletions lib/commands/sellers.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
'use strict';

const Discord = require('discord.js');
const apiUtil = require('../util/api');
const dbUtil = require('../util/db/db');

/**
* Get all sellers for a region
* @param {Object} msg Discord message
*/
module.exports = async (msg) => {
try {
const sellers = await apiUtil.getSellers();
const sellers = await dbUtil.getSellers();

msg.channel.send(
new Discord.MessageEmbed({
Expand Down
Loading

0 comments on commit 279e36a

Please sign in to comment.