From 9e9911ec56dfbed42ab5c25aec54d2424e2c4b90 Mon Sep 17 00:00:00 2001 From: Coko7 Date: Thu, 15 Sep 2022 15:42:02 +0200 Subject: [PATCH] feat: add per manga configuration (channel, roles, threads...) --- .gitignore | 5 ++-- README.md | 64 +++++++++++++++++++++++++++++++----------------- config.json | 14 ----------- data.json | 1 - index.js | 56 ++++++++++++++++++++++++++++++------------ opus-config.json | 21 ++++++++++++++++ 6 files changed, 106 insertions(+), 55 deletions(-) delete mode 100644 config.json delete mode 100644 data.json create mode 100644 opus-config.json diff --git a/.gitignore b/.gitignore index 875e140..39ea635 100644 --- a/.gitignore +++ b/.gitignore @@ -89,5 +89,6 @@ lerna-debug.log .DS_Store Thumbs.db -# Ignore config file -config.json \ No newline at end of file +# Ignore config file and data +config.json +data.json \ No newline at end of file diff --git a/README.md b/README.md index 5dd62cf..75b5644 100644 --- a/README.md +++ b/README.md @@ -22,37 +22,57 @@ npm i ## Configuration -Before running the bot for the first time, you need to modify its configuration in [config.json](config.json). Here is what the default configuration file looks like: - +### Bot token and prefix +First, you need to create a Discord application and bot on Discord [Developer Portal](https://discord.com/developers/applications). +Then, create a file named `config.json` with the following content: ```json { "token": "YOUR_BOT_TOKEN", "prefix": "!", - "opus": { - "scanSite": "https://onepiecechapters.com/", - "mangas": ["One Piece"], - "discord": { - "autoCreateThread": true, - "notifyRole": "YOUR_ROLE_ID", - "fromChannel": "YOUR_FROM_CHANNEL", - "toChannel": "YOUR_TO_CHANNEL" - } - } } ``` +Replace `YOUR_BOT_TOKEN` with the token of your bot. -Here is the list of keys you can set: +### OPUS setup -- token: The token of your discord bot -- opus: - - mangas: The names of the mangas you are interested in - - discord: - - autoCreateThread: Whether a new thread should be created for the released chapter. The thread will be attached to channel **toChannel** - - notifyRole: The ID of the role to notify once the chapter comes out - - fromChannel: The ID of the discord channel subscribed to the TCB server #releases channel - - toChannel:The ID of the discord channel where you want the final message to appear +Now that `config.json` has been created, you need to configure the bot to listen for specific manga releases and notify users. +To do that, open the file [opus-config.json](./opus-config.json). It should have the following content by default: + +```json +{ + "scanSite": "https://onepiecechapters.com/", + "mangas": [ + { + "name": "One Piece", + "active": true, + "notifyRole": "DISCORD_ROLE_ID", + "fromChannel": "TCB_LISTEN_CHANNEL_ID", + "toChannel": "OPUS_NOTIFY_CHANNEL_ID", + "autoCreateThread": true + }, + { + "name": "Black Clover", + "active": true, + "notifyRole": "DISCORD_ROLE_ID", + "fromChannel": "TCB_LISTEN_CHANNEL_ID", + "toChannel": "OPUS_NOTIFY_CHANNEL_ID", + "autoCreateThread": true + } + ] +} +``` -**NB:** Please do remember that your bot token must remain secret, do not share them with anyone unless you really trust them. +You do not need to change `scanSite` as only TCB can be used right now. +The default configuration registers listen events for two mangas: **One Piece** and **Black Clover**. +You can register as many mangas as you want as long as the scans exist on the TCB website. + +Manga attributes: +- The `name` attribute of a manga is the most important as it is used to identify a manga on TCB. Make sure to get it right. +- The `active` attribute can be used to disable notification for a specific manga without removing its configuration. +- The `notifyRole` attribute will be used in the notification message to notify a specific Discord role. The value must be a valid Discord role ID on your Discord server. *This attribute is optional. If omitted, the notification message will not ping any role.* +- The `fromChannel` attribute is the Discord channel ID in which you receive TCB releases notifications. +- The `toChannel` attribute is the Discord channel ID of the channel where you want OPUS notifications to be sent. +- The `autoCreateThread` attribute is used to automatically create a thread to talk about a new chapter release. The thread will be attached to the `toChannel` channel. *This attribute is optional. If omitted, no thread will be created.* ## Launching the bot diff --git a/config.json b/config.json deleted file mode 100644 index 93209b8..0000000 --- a/config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "token": "YOUR_BOT_TOKEN", - "prefix": "!", - "opus": { - "scanSite": "https://onepiecechapters.com/", - "mangas": ["One Piece"], - "discord": { - "autoCreateThread": true, - "notifyRole": "YOUR_ROLE_ID", - "fromChannel": "YOUR_FROM_CHANNEL", - "toChannel": "YOUR_TO_CHANNEL" - } - } -} diff --git a/data.json b/data.json deleted file mode 100644 index 4f77a64..0000000 --- a/data.json +++ /dev/null @@ -1 +0,0 @@ -{"mangas":[{"name":"One Piece","chapter":"1056","url":"https://onepiecechapters.com/chapters/3934/one-piece-chapter-1056"}]} \ No newline at end of file diff --git a/index.js b/index.js index 5996ebb..05ea7ef 100644 --- a/index.js +++ b/index.js @@ -10,10 +10,14 @@ const scraper = require("./scraper"); // Load config and data files const config = require("./config.json"); +const opus = require("./opus-config.json"); const data = require("./data.json"); // Load the manga interests and fix their case to be title case -const mangas = config.opus.mangas.map((m) => utils.toTitleCase(m)); +const mangas = opus.mangas.map((m) => { + m.name = utils.toTitleCase(m.name); + return m; +}); client.once("ready", () => { console.log("tcb-opus module is ready!"); @@ -24,33 +28,34 @@ client.on("messageCreate", async (message) => { if (message.author.id === client.user.id) return; // If the message was not sent in input channel, ignore it - if (message.channel.id !== config.opus.discord.fromChannel) return; + if (!isListenChannel(message.channel.id)) return; // Check whether the message contains one of the desired mangas const manga = mangas.find((m) => - message.content.toLowerCase().includes(m.toLowerCase()) + message.content.toLowerCase().includes(m.name.toLowerCase()) ); - if (manga) { + if (manga && manga.active) { // Fetch the latest chapter from TCBScans website - const res = await scraper.fetchLatestChapter(manga, config.opus.scanSite); + const res = await scraper.fetchLatestChapter(manga.name, opus.scanSite); if (res.error) { - console.error(`Error occured while fetching ${manga}: ${res.error}`); + console.error(`Error occured while fetching ${manga.name}: ${res.error}`); return; } else if (res.chapter) { - // Find the output channel based on the channel Id in config - const channel = client.channels.cache.get(config.opus.discord.toChannel); + // Get the Discord output channel for the current manga + const channel = client.channels.cache.get(manga.toChannel); + const notifyPrefix = manga.notifyRole ? `<@&${manga.notifyRole}> ` : ""; // Send a message with the chapter link in the output channel await channel.send( - `<@&${config.opus.discord.notifyRole}> ${manga} chapter **${res.chapter}** is out!\n${res.url}` + `${notifyPrefix}${manga.name} chapter **${res.chapter}** is out!\n${res.url}` ); - console.log(`Successfully fetched ${manga} chapter ${res.chapter}`); + console.log(`Successfully fetched ${manga.name} chapter ${res.chapter}`); // Automatically create a thread to talk about the chapter if configured - if (config.opus.discord.autoCreateThread) { + if (manga.autoCreateThread) { const threadName = `chap-${res.chapter}-talk`; // Create thread if not exist @@ -73,7 +78,7 @@ client.on("messageCreate", async (message) => { // Update data file with latest chapter number if (!data.mangas) data.mangas = []; - const stored = data.mangas.find((m) => m.name === manga); + const stored = data.mangas.find((m) => m.name === manga.name); if (stored) { // If the stored chapter is not the latest @@ -81,7 +86,9 @@ client.on("messageCreate", async (message) => { const missed = res.chapter - stored.chapter - 1; if (missed > 0) { console.log( - `I missed ${missed} ${manga} chapter${missed > 1 ? "s" : ""}!` + `I missed ${missed} ${manga.name} chapter${ + missed > 1 ? "s" : "" + }!` ); } @@ -91,7 +98,7 @@ client.on("messageCreate", async (message) => { } } else { data.mangas.push({ - name: manga, + name: manga.name, chapter: res.chapter, url: res.url, }); @@ -111,10 +118,11 @@ client.login(config.token); * @access private * * @param {string} msg The discord message from TCB + * @param {string} manga The manga object * * @return {string} A formatted message containing the chapter link. */ -function formatTCBMessage(msg) { +function formatTCBMessage(msg, manga) { const urlStart = msg.indexOf("http"); if (urlStart === -1) @@ -123,5 +131,21 @@ function formatTCBMessage(msg) { const url = msg.slice(urlStart); const chapNum = url.slice(url.lastIndexOf("-") + 1); - return `<@&${config.opus.discord.notifyRole}> One Piece chapter **${chapNum}** is out!\n${url}`; + return `<@&${manga.notifyRole}> ${manga.name} chapter **${chapNum}** is out!\n${url}`; +} + +/** + * Fetch important elements from the TCB message and create a new message. + * + * @since 1.0.0 + * @access private + * + * @param {string} channelId The ID of the discord channel where TCB updates are sent + * + * @return {bool} True if the channel is a TCB update channel, false otherwise. + */ +function isListenChannel(channelId) { + if (mangas.find((m) => m.fromChannel === channelId)) return true; + + return false; } diff --git a/opus-config.json b/opus-config.json new file mode 100644 index 0000000..7df5221 --- /dev/null +++ b/opus-config.json @@ -0,0 +1,21 @@ +{ + "scanSite": "https://onepiecechapters.com/", + "mangas": [ + { + "name": "One Piece", + "active": true, + "notifyRole": "DISCORD_ROLE_ID", + "fromChannel": "TCB_LISTEN_CHANNEL_ID", + "toChannel": "OPUS_NOTIFY_CHANNEL_ID", + "autoCreateThread": true + }, + { + "name": "Black Clover", + "active": true, + "notifyRole": "DISCORD_ROLE_ID", + "fromChannel": "TCB_LISTEN_CHANNEL_ID", + "toChannel": "OPUS_NOTIFY_CHANNEL_ID", + "autoCreateThread": true + } + ] +}