diff --git a/.github/workflows/wiki-update.yml b/.github/workflows/wiki-update.yml index 36e6c944..d341c079 100644 --- a/.github/workflows/wiki-update.yml +++ b/.github/workflows/wiki-update.yml @@ -2,8 +2,7 @@ name: Update Wiki Commands on: push: - branches: - - main + branches: [main] paths: - "src/data/commandData.csv" workflow_dispatch: diff --git a/config.json.example b/config.json.example index 73425cb6..d45f9190 100644 --- a/config.json.example +++ b/config.json.example @@ -34,10 +34,6 @@ "feedUrl" : "https://theync.com/most-recent/", "interval" : 120000, "markerOne" : "https://theync.com/media/video", - "markerTwo" : "https://theync.com", - "maxDownloadSize" : 50, - "targetDir" : "/path/to/videos/folder", - "tempDir" : "/path/to/videos/folder/transcodes", - "cdnUrl" : "https://cdn.vb2007.hu/darwin/" + "markerTwo" : "https://theync.com" } } diff --git a/package-lock.json b/package-lock.json index 34701662..3cf82b2c 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "discordbot", - "version": "4.1.1", + "version": "4.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "discordbot", - "version": "4.1.1", + "version": "4.2.0", "license": "AGPL-3.0-only", "dependencies": { "ajv": "^8.17.1", @@ -1441,9 +1441,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.29.tgz", - "integrity": "sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==", + "version": "2.8.30", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.30.tgz", + "integrity": "sha512-aTUKW4ptQhS64+v2d6IkPzymEzzhw+G0bA1g3uBRV3+ntkH+svttKseW5IOR4Ed6NUVKqnY7qT3dKvzQ7io4AA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1553,9 +1553,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001755", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", - "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", + "version": "1.0.30001756", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz", + "integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==", "dev": true, "funding": [ { @@ -1895,9 +1895,9 @@ ] }, "node_modules/discord.js": { - "version": "14.25.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.25.0.tgz", - "integrity": "sha512-9rnJWTAkfauKTieYJ3oI4oncrSzpbJPWN1/XU+2H6wsHQPtqbOrXvgM0nFhSVnIbTo7nfUF7fzcYRevvRGjpzA==", + "version": "14.25.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.25.1.tgz", + "integrity": "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==", "license": "Apache-2.0", "dependencies": { "@discordjs/builders": "^1.13.0", @@ -1998,9 +1998,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.256.tgz", - "integrity": "sha512-uqYq1IQhpXXLX+HgiXdyOZml7spy4xfy42yPxcCCRjswp0fYM2X+JwCON07lqnpLEGVCj739B7Yr+FngmHBMEQ==", + "version": "1.5.259", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.259.tgz", + "integrity": "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==", "dev": true, "license": "ISC" }, diff --git a/package.json b/package.json index 2fa15ea1..f0380cd2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discordbot", - "version": "4.2.0", + "version": "4.2.1", "description": "A simple discord bot of mine developed with discord.js (Node.js).", "type": "module", "main": "index.js", diff --git a/src/commands/fun/darwin-random.js b/src/commands/fun/darwin-random.js new file mode 100644 index 00000000..285e3e19 --- /dev/null +++ b/src/commands/fun/darwin-random.js @@ -0,0 +1,33 @@ +import { SlashCommandBuilder } from "discord.js"; +import { query } from "../../helpers/db.js"; +import { baseReplyAndLog } from "../../helpers/reply.js"; + +export default { + data: new SlashCommandBuilder() + .setName("darwin-random") + .setDescription("Sends back a random, streamable video from Darwin's database.") + .setNSFW(false) //should be true, but fucking discord forces id checks to view NSFW channel. i won't comply. + .setDMPermission(true), + async execute(interaction) { + const randomVideo = await query( + `SELECT directVideoUrl, forumPostUrl, videoTitle, processedAt + FROM darwinCache + WHERE forumPostUrl IS NOT NULL + AND videoTitle IS NOT NULL + ORDER BY RAND() + LIMIT 1` + ); + + const directVideoUrl = randomVideo[0].directVideoUrl; + const forumPostUrl = randomVideo[0].forumPostUrl; + const videoTitle = randomVideo[0].videoTitle; + const processedAt = Math.floor(new Date(randomVideo[0].processedAt).getTime() / 1000); + + const messageContent = + `[[ STREAMING & DOWNLOAD ]](${directVideoUrl}) - [[ FORUM POST ]](<${forumPostUrl}>)\n` + + `**Title**: ${videoTitle}\n` + + `**Processed at**: `; + + await baseReplyAndLog(interaction, messageContent); + }, +}; diff --git a/src/commands/fun/word-leaderboard.js b/src/commands/fun/word-leaderboard.js new file mode 100644 index 00000000..3f119bd6 --- /dev/null +++ b/src/commands/fun/word-leaderboard.js @@ -0,0 +1,74 @@ +import { SlashCommandBuilder } from "discord.js"; +import { embedReplyPrimaryColor } from "../../helpers/embeds/embed-reply.js"; +import { positionEmojis } from "../../helpers/format.js"; +import { checkIfNotInGuild } from "../../helpers/command-validation/general.js"; +import { logToFileAndDatabase } from "../../helpers/logger.js"; +import { query } from "../../helpers/db.js"; + +const commandName = "word-leaderboard"; + +export default { + data: new SlashCommandBuilder() + .setName(commandName) + // Counts a specified word in the current server and sends back a leaderboard with the users who used that word the most. + .setDescription( + "Gives back a word count leaderboard with the top users who used that word the most." + ) + .addStringOption((option) => + option + .setName("word") + .setDescription("The word that will get counted.") + .setRequired(true) + .setMinLength(2) + .setMaxLength(12) + ) + .setDMPermission(false), + async execute(interaction) { + await interaction.deferReply(); + + const guildCheck = checkIfNotInGuild(commandName, interaction); + if (guildCheck) { + return await replyAndLog(interaction, guildCheck); + } + + const targetWord = interaction.options.getString("word"); + const currentServerId = interaction.guild.id; + + const usersQuery = await query( + `SELECT senderUserId, senderUserName, COUNT(*) as wordCount + FROM messageLog + WHERE serverId = ? AND messageContent LIKE ? + GROUP BY senderUserId + ORDER BY wordCount DESC + LIMIT 10`, + [currentServerId, `%${targetWord}%`] + ); + + let leaderboardContent = ""; + for (let i = 0; i < usersQuery.length; i++) { + const userResult = usersQuery[i]; + const emoji = positionEmojis[i + 1]; + + let username; + try { + const member = await interaction.guild.members.fetch(userResult.senderUserId); + username = member.user.username; + } catch (error) { + username = userResult.senderUserName || "Unknown username"; + } + + leaderboardContent += `${emoji} <@${userResult.senderUserId}> (${username}): **#${userResult.wordCount}**\n`; + } + + const embedReply = embedReplyPrimaryColor( + `Word Leaderboard: "${targetWord}"`, + usersQuery.length !== 0 + ? `Leaderboard of users whose messages contained the word **${targetWord}** the most:\n\n${leaderboardContent}` + : `:x: No user has used the word **${targetWord}** in their messages so far.`, + interaction + ); + + await interaction.editReply({ embeds: [embedReply] }); + await logToFileAndDatabase(interaction, JSON.stringify(embedReply.toJSON())); + }, +}; diff --git a/src/data/commandData.csv b/src/data/commandData.csv index 5881c8d7..116ddc6c 100644 --- a/src/data/commandData.csv +++ b/src/data/commandData.csv @@ -25,15 +25,17 @@ 24,ban,moderation,Bans a specified member from the server. 25,purge,moderation,Purges (mass deletes) a specified amount of messages from the current channel. 26,config-autorole,administration,"Sets / modifies / disables the autorole feature. When a new member joins the server, a specified role will get assigned to them automatically." -28,config-welcome,administration,"Sets / modifies / disables the welcome messages feature. When a new member joins the server, the bot send a specified welcome message." -30,config-logging,administration,Sets / modifies / disables the channel where event on the server will get logged -32,config-bridge,administration,Sets / modifies / disables bridging all messages from one channel to another. -34,rename,administration,Renames a specified user to a specified nickname in the current server. -35,slowmode,administration,Sets / disables the slowmode for a specified channel. -36,config-goodbye,administration,"Sets / modifies / disables the goodbye messages feature. When a member leaves the server, the bot send a specified goodbye message." -82,coinflip-fun,fun,Flips a coin that has a 50/50 chance landing on heads or tails. Has an economy (*/coinflip*) version with gambling. -112,blackjack,economy,Lets you play a game of blackjack with a specified amount. You can pick **Hit** or **Stand** until the player or the house wins -192,config-darwin,administration,Sets / modifies / disables Darwin's occasional video scraping & posting feature. -193,cigany,fun,"Says ""fuj"" and sends a random pic of a ""person"" from a specific race." -194,cooldown,economy,Lets you check your or other users economy cooldowns for all or a specified economy command. -195,invite,utility,Gives you back a link for inviting the bot to any server where you have permissions to do so. +27,config-welcome,administration,"Sets / modifies / disables the welcome messages feature. When a new member joins the server, the bot send a specified welcome message." +28,config-logging,administration,Sets / modifies / disables the channel where event on the server will get logged +29,config-bridge,administration,Sets / modifies / disables bridging all messages from one channel to another. +30,rename,administration,Renames a specified user to a specified nickname in the current server. +31,slowmode,administration,Sets / disables the slowmode for a specified channel. +32,config-goodbye,administration,"Sets / modifies / disables the goodbye messages feature. When a member leaves the server, the bot send a specified goodbye message." +33,coinflip-fun,fun,Flips a coin that has a 50/50 chance landing on heads or tails. Has an economy (*/coinflip*) version with gambling. +34,blackjack,economy,Lets you play a game of blackjack with a specified amount. You can pick **Hit** or **Stand** until the player or the house wins +35,config-darwin,administration,Sets / modifies / disables Darwin's occasional video scraping & posting feature. +36,cigany,fun,"Says ""fuj"" and sends a random pic of a ""person"" from a specific race." +37,cooldown,economy,Lets you check your or other users economy cooldowns for all or a specified economy command. +38,invite,utility,Gives you back a link for inviting the bot to any server where you have permissions to do so. +39,word-leaderboard,fun,Counts a specified word in the current server and sends back a leaderboard with the users who used that word the most through all their previous messages. +40,darwin-random,fun,"Sends back a random, streamable video from Darwin's database." diff --git a/src/events/scripts/messageCreate/messageLogging.js b/src/events/scripts/messageCreate/messageLogging.js index 01c9bca3..52b52804 100644 --- a/src/events/scripts/messageCreate/messageLogging.js +++ b/src/events/scripts/messageCreate/messageLogging.js @@ -29,9 +29,9 @@ export const logToDB = async (message) => { ] ); - console.log( - `Logged message "${message.content}" to database from ${senderUserName} in ${serverName}.` - ); + // console.log( + // `Logged message "${message.content}" to database from ${senderUserName} in ${serverName}.` + // ); } } } catch (error) { diff --git a/src/helpers/darwin/darwinCache.js b/src/helpers/darwin/darwinCache.js index d3b8ca10..b462fe7e 100644 --- a/src/helpers/darwin/darwinCache.js +++ b/src/helpers/darwin/darwinCache.js @@ -32,7 +32,7 @@ export const addToCache = async (directVideoUrl, forumPostUrl, videoTitle) => { try { const exists = await isInCache(directVideoUrl); if (exists) { - console.log(`URL already in cache: ${directVideoUrl}`); + // console.log(`URL already in cache: ${directVideoUrl}`); return true; } @@ -76,7 +76,7 @@ export const addToCache = async (directVideoUrl, forumPostUrl, videoTitle) => { export const isInCache = async (url) => { try { const videoId = extractVideoId(url); - console.log(`Checking "${url}" (ID: ${videoId}) in Darwin's cache`); + // console.log(`Checking "${url}" (ID: ${videoId}) in Darwin's cache`); const result = await query( "SELECT directVideoUrl FROM darwinCache WHERE directVideoUrl = ? OR videoId = ?", diff --git a/src/helpers/darwin/darwinProcess.js b/src/helpers/darwin/darwinProcess.js index 977b2167..c517655d 100644 --- a/src/helpers/darwin/darwinProcess.js +++ b/src/helpers/darwin/darwinProcess.js @@ -77,7 +77,7 @@ const getVideoLocation = async (href, markerOne, markerTwo) => { * @returns {string} - Formatted message */ const messageGen = (title, href, comments) => { - return `[[ STREAMING & DOWNLOAD ]](${href}) - [[ FORUM POST ]](<${comments}>)\n${title}`; + return `[[ STREAMING & DOWNLOAD ]](${href}) - [[ FORUM POST ]](<${comments}>)\n**${title}**`; }; /** diff --git a/src/helpers/format.js b/src/helpers/format.js index a6744d52..a9abded9 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -15,3 +15,16 @@ export const formatRouletteColor = (color) => { console.error("The color you've provided for the formatRouletteColor() function is invalid."); } }; + +export const positionEmojis = { + 1: ":first_place:", + 2: ":second_place:", + 3: ":third_place:", + 4: ":number_4:", + 5: ":number_5:", + 6: ":number_6:", + 7: ":number_7:", + 8: ":number_8:", + 9: ":number_9:", + 10: ":number_10:", +}; diff --git a/src/helpers/reply.js b/src/helpers/reply.js index d298ff8c..f3324ba6 100644 --- a/src/helpers/reply.js +++ b/src/helpers/reply.js @@ -4,3 +4,8 @@ export const replyAndLog = async (interaction, embedReply) => { await interaction.reply({ embeds: [embedReply] }); await logToFileAndDatabase(interaction, JSON.stringify(embedReply.toJSON())); }; + +export const baseReplyAndLog = async (interaction, messageContent) => { + await interaction.reply(messageContent); + await logToFileAndDatabase(interaction, messageContent); +}; diff --git a/src/index.js b/src/index.js index b50936d9..b44fb321 100644 --- a/src/index.js +++ b/src/index.js @@ -79,7 +79,7 @@ client.once(Events.ClientReady, (readyClient) => { setInterval(() => { if (darwinProcessRunning) { - console.log("Darwin process already running, skipping this execution"); + // console.log("Darwin process already running, skipping this execution"); return; } diff --git a/src/sql/darwinCache/migrate-to-new-schema.sql b/src/sql/darwinCache/migrate-to-new-schema.sql deleted file mode 100644 index 22c9bb2a..00000000 --- a/src/sql/darwinCache/migrate-to-new-schema.sql +++ /dev/null @@ -1,14 +0,0 @@ -ALTER TABLE `darwinCache` -CHANGE COLUMN `videoUrl` `directVideoUrl` VARCHAR(255) NOT NULL; - -ALTER TABLE `darwinCache` -ADD COLUMN `forumPostUrl` VARCHAR(255) NOT NULL DEFAULT '' AFTER `directVideoUrl`, -ADD COLUMN `videoTitle` VARCHAR(180) NOT NULL DEFAULT '' AFTER `videoId`; - -ALTER TABLE `darwinCache` -DROP INDEX `videoUrl`; - -ALTER TABLE `darwinCache` -ADD UNIQUE KEY `directVideoUrl` (`directVideoUrl`); - -DESCRIBE `darwinCache`; diff --git a/src/sql/darwinCache/table.sql b/src/sql/darwinCache/table.sql index 25e4bf05..86ec5e5e 100644 --- a/src/sql/darwinCache/table.sql +++ b/src/sql/darwinCache/table.sql @@ -1,12 +1,13 @@ -- discordbot.darwinCache definition -CREATE TABLE IF NOT EXISTS `darwinCache` ( - `id` INT AUTO_INCREMENT PRIMARY KEY, - `directVideoUrl` VARCHAR(255) NOT NULL, - `forumPostUrl` VARCHAR(255) NOT NULL, - `videoId` VARCHAR(100) NOT NULL, - `videoTitle` VARCHAR(180) NOT NULL, - `processedAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE KEY (`directVideoUrl`), - UNIQUE KEY (`videoId`) +CREATE TABLE `darwinCache` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `directVideoUrl` varchar(255) NOT NULL, + `forumPostUrl` varchar(255) NOT NULL DEFAULT '', + `videoId` varchar(100) NOT NULL, + `videoTitle` varchar(180) NOT NULL DEFAULT '', + `processedAt` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`), + UNIQUE KEY `videoId` (`videoId`), + UNIQUE KEY `directVideoUrl` (`directVideoUrl`) );