Compare commits

...

144 commits

Author SHA1 Message Date
Benji 8ef41cdb7e
Merge pull request #8 from em92/dns-resolve-fix
Use correct attribute to resolve host
2018-09-25 23:47:49 +01:00
Eugene Molotov a9535aa974 Use correct attribute to resolve host 2018-09-19 11:38:17 +05:00
benji7425 0b4747c594 Remove tracking for .vscode folder 2018-07-07 20:13:57 +01:00
Benji 098da23326 Merge pull request #6 from bluddy/master
Handle too long articles, convert html
2018-07-03 13:53:25 +01:00
Yotam Barnoy ae44a77148 Support html-to-text for cleaning up html 2018-06-07 01:24:06 +00:00
Yotam Barnoy f764ad3dc7 Reduced message size a little 2018-06-07 01:23:01 +00:00
Yotam Barnoy dcae7ff65a aesthetic 2018-06-05 02:50:12 +00:00
Yotam Barnoy b720f4ae87 feed-data: update max message length 2018-06-05 02:49:36 +00:00
Yotam Barnoy 01a60db602 Trim articles that are too long rather than skipping them 2018-06-04 16:33:53 -04:00
Yotam Barnoy ac29bd801d Raise max char count 2018-06-04 16:27:49 -04:00
Benji b61b1748ad Update README.md 2018-04-04 23:29:50 +01:00
benji7425 d5b29adad2 3.5.2 2018-02-11 00:20:50 +00:00
benji7425 e838b60752 git subrepo pull core
subrepo:
  subdir:   "core"
  merged:   "7a3eed3"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "7a3eed3"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-02-11 00:17:01 +00:00
benji7425 5fbd288861 3.5.1 2018-01-27 20:23:24 +00:00
benji7425 1a5b15421d Remove deletion of data for removed guilds on startup
This would be bad if we started up during a discord outage, as I recently learned that discord.js counts the bot as not in the guild if that guild is inaccessible
2018-01-27 20:23:21 +00:00
benji7425 f338bced1e git subrepo pull core
subrepo:
  subdir:   "core"
  merged:   "1f14a50"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "1f14a50"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-27 20:23:04 +00:00
benji7425 78a7d4e69b 3.5.0 2018-01-27 18:15:14 +00:00
benji7425 d6866e2147 Remove unused reference causing problems 2018-01-27 18:15:14 +00:00
benji7425 8063e5959d git subrepo push core
subrepo:
  subdir:   "core"
  merged:   "bcce76f"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "bcce76f"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-27 18:05:52 +00:00
benji7425 ae16f1cce9 Fix help not indicating that the bot username needs to be mentioned 2018-01-27 18:05:52 +00:00
benji7425 c1750e0842 Update core naming to make a little more sense 2018-01-27 17:39:52 +00:00
benji7425 2c538885c6 Update camo to use new tagged version 2018-01-27 17:30:26 +00:00
benji7425 793f531c63 3.5.0-b3 2018-01-27 02:32:02 +00:00
benji7425 03737c15f3 Remove discord-bot-core direct mongodb package dep
Camo actually just loads it itself
2018-01-27 01:29:00 +00:00
benji7425 4fe1f35e92 Update defauly NeDB compaction schedule to hourly 2018-01-27 00:42:36 +00:00
benji7425 90eeddfc32 Remove auto-restart
It was a work around to reset memory usage, but as I hope mongodb support fixes that, I shall remove it. Hopefully I won't need to revert this commit and put it back!
2018-01-27 00:41:58 +00:00
benji7425 64a69af4e0 Update camo to use my fork
Increases MongoDB compatibility and adds it's own method for compacting NeDB data files
2018-01-27 00:37:17 +00:00
benji7425 80c8f6accd Update data deletion to require a reset command instead of guildDelete
guildDelete apparently gets called whenever Discord has an outage - we don't want to delete server data whenever there is a temporary outage!
2018-01-27 00:03:51 +00:00
benji7425 9c1252cfd8 Update formatting; convert tabs to 4x spaces
I believe this is the accepted method and should increase default editor compatibility
2018-01-26 23:48:07 +00:00
benji7425 b9ae3b5b26 v3.5.0-b2
Fix a couple of script errors
2018-01-26 00:35:41 +00:00
benji7425 f64d0deed1 3.5.0-b1 2018-01-26 00:29:41 +00:00
benji7425 6e26ce1f3c Merge branch 'mongodb-compatibility' 2018-01-25 23:02:50 +00:00
benji7425 388d6c6305 Update core client to support mongodb in addition to nedb 2018-01-25 23:02:46 +00:00
benji7425 eae08f526e Install mongodb 2018-01-25 22:29:51 +00:00
benji7425 c4d1247be3 Update naming and formatting for core .js files 2018-01-25 21:41:17 +00:00
benji7425 4a8c90bf7d git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "693a761"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "693a761"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-23 23:55:07 +00:00
benji7425 f904eecc50 3.4.0
Fix YouTube feeds not posting anymore
2018-01-23 23:19:48 +00:00
benji7425 9b37c3b5cd Update default NeDB compaction schedule to once per minute 2018-01-23 23:19:33 +00:00
benji7425 87016a6fb9 git subrepo push --force discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "109848a"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "109848a"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-23 00:53:44 +00:00
benji7425 1816433f19 git subrepo pull (merge) discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "71586d6"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "a0387b3"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-23 00:52:11 +00:00
benji7425 5dcb2c0f11 3.4.0-b1 2018-01-23 00:36:11 +00:00
benji7425 614bdab462 Disable a few unused websocket events
Hopefully will improve memory usage somewhat
2018-01-23 00:32:33 +00:00
benji7425 a77c9e22f5 Add daily auto restart 2018-01-23 00:30:10 +00:00
benji7425 b7f65b94b7 Add LICENSE 2018-01-20 16:22:46 +00:00
benji7425 1566223be2 3.3.0 2018-01-14 20:18:29 +00:00
benji7425 027d320e34 git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "429a85c"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "429a85c"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-14 20:12:32 +00:00
benji7425 25f2a7bd5f Switch from 'feed-read' module to 'rss-parser' 2018-01-14 20:08:05 +00:00
benji7425 9373980f94 Remove some unnecessary stuff in Client.js
- Remove message sweeping - shouldn't be needed with max cache size
- Remove console spam about db compaction
2018-01-14 19:48:40 +00:00
benji7425 f261e4e1d4 Update feed url caching to ignore 'www.' prefix
Has caused some issues with users posting links with/without www. and the RSS feed doing the opposite
Improve regex
2018-01-14 18:31:33 +00:00
benji7425 7d5ab21292 git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "4bfcf1b"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "4bfcf1b"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-07 23:53:26 +00:00
benji7425 cb718dea41 3.2.2
asdf
2018-01-07 23:48:29 +00:00
Benji 0cd4cbcc4e Update README.md 2018-01-03 21:06:37 +00:00
benji7425 8b8a4b4c68 Remove useless node launch argument 2018-01-03 17:01:04 +00:00
benji7425 7b8dc6fb4c Update .gitignore 2018-01-03 03:30:58 +00:00
benji7425 39ffcc3764 3.2.1 2018-01-03 01:47:52 +00:00
benji7425 05da2d694e git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "70b150f"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "70b150f"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2018-01-03 01:47:02 +00:00
benji7425 6f5ccb5eca Update d.js message caching settings 2018-01-03 01:45:47 +00:00
benji7425 2852cb5bcb Update README.md 2017-12-11 01:18:36 +00:00
benji7425 8ddb9f7f9f 3.2.0 2017-12-11 01:11:52 +00:00
benji7425 355bc92717 git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "0bab27a"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "0bab27a"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-12-11 01:06:10 +00:00
benji7425 4dd6171549 Refactor for efficiency and improved readability 2017-12-11 01:05:43 +00:00
benji7425 556971f3b2 git subrepo pull (merge) discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "cf92dea"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "b19d4b2"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-12-09 05:39:04 +00:00
benji7425 f54f610c01 3.2.0-b3
Fix some race conditions with the 3.2 update
2017-12-09 01:38:42 +00:00
benji7425 30ed030b62 3.2.0-b2
Fix some issues with 3.2 upgrades
2017-12-08 22:54:45 +00:00
benji7425 553344a416 3.2.0-b1 2017-12-08 00:57:44 +00:00
benji7425 bb86035a21 git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "900f1f5"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "900f1f5"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-12-08 00:54:42 +00:00
benji7425 041c3464f9 Add legacy json file upgrader 2017-12-08 00:54:07 +00:00
benji7425 20fa9d09af Update feed error handling 2017-12-08 00:29:16 +00:00
benji7425 da1edc57f0 Add removal of data on startup for guilds deleted during downtime 2017-12-08 00:09:07 +00:00
benji7425 8dfbab0122 Add guild iteration for feed checking
Update default feed check interval to be 10 seconds between guilds
2017-12-08 00:09:03 +00:00
benji7425 78eec753f1 Fix links not being properly cached with camo integration 2017-12-07 22:48:49 +00:00
benji7425 a64c3eeefb Merge branch 'camo-integration' 2017-12-07 22:29:01 +00:00
benji7425 8fdb13887f git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "be39d24"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "be39d24"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-12-07 22:27:54 +00:00
benji7425 52e3399b75 Integrate rss bot with camo 2017-12-07 22:26:45 +00:00
benji7425 72b7db32ab Fix various issues in core 2017-12-07 22:26:45 +00:00
benji7425 65d2745cdc Revert removal of restart on unhandled exception
Turns out maybe it is actually somewhat useful after all
2017-12-07 00:19:16 +00:00
benji7425 9c0602bbb6 git subrepo pull (merge) discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "75f5044"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "eca1499"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-12-07 00:11:14 +00:00
benji7425 695f42348a Tidy up some feed error spam 2017-12-03 16:04:15 +00:00
benji7425 cc5e74e46e Fix crash if articles contain urls with invalid host names 2017-12-03 15:53:12 +00:00
benji7425 990cd60425 Fix crash if feed used with articles without links
Didn't realise this was possible...
2017-11-27 09:35:36 +00:00
benji7425 f3ef44b76a git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "a1a9b30"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "a1a9b30"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-11-27 00:17:15 +00:00
benji7425 9901b3dc19 Housekeeping 2017-11-27 00:16:54 +00:00
benji7425 3433674c41 3.1.3 2017-11-27 00:10:27 +00:00
benji7425 b114725ded Merge branch 'fix-message-length' 2017-11-27 00:09:20 +00:00
benji7425 dc2d66dd35 Fix changelog 2017-11-27 00:08:53 +00:00
benji7425 3e24a63a86 Add pagination limit to config 2017-11-27 00:07:29 +00:00
benji7425 4c7d826b52 Add rudimentary pagination for viewing feeds 2017-11-27 00:02:39 +00:00
benji7425 8f1c840447 Fix articles not posting if content too long for discord
Also fix incorrect name in example commands
2017-11-26 23:38:01 +00:00
benji7425 863eac6375 Revert "Removed ignoring of certain debug message in debug.log"
This reverts commit 1e4016ffd4d78d3a85c9161ab702b97979155753 in discord-bot-core subrepo
2017-11-26 23:36:23 +00:00
benji7425 6da6d1256c git subrepo pull discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "a25486f"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "a25486f"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-11-26 23:29:16 +00:00
benji7425 68680d624f Quickfix deleted channels with feeds causing reconnect loop 2017-11-14 22:28:04 +00:00
benji7425 f1c12c8a19 Fix empty RSS feed crash 2017-11-14 01:31:46 +00:00
benji7425 4c557127d2 git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "5c4a0b8"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "5c4a0b8"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-11-12 20:01:35 +00:00
benji7425 9386b754fb 3.1.0 2017-11-12 19:50:22 +00:00
benji7425 9b23e70e87 Add removal of data on startup if the bot has left the guild 2017-11-12 19:44:19 +00:00
benji7425 c3a55a6c5b Fix wrong feed being removed when the remove-feed command used 2017-11-12 19:34:04 +00:00
benji7425 5ab4464df7 3.1.0-b1 2017-11-11 04:17:18 +00:00
benji7425 014e19220b Add support for optional command parameters 2017-11-11 03:44:44 +00:00
benji7425 c1be0ff0e6 Add rss element content into posted message 2017-11-11 03:21:05 +00:00
benji7425 3877aa5c59 Add feed validity checking before adding 2017-11-11 01:59:00 +00:00
benji7425 0d5e3dcd81 Update changelog 2017-11-11 01:35:26 +00:00
benji7425 7d433e9354 Add max-old-space-size constraint of 64MB 2017-11-11 01:32:50 +00:00
benji7425 4bb676d136 Add removal of data when bot kicked from guild
Along with join/leave console messages
2017-11-11 01:28:38 +00:00
benji7425 3cfddd1f58 git subrepo pull (merge) discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "5fd4a43"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "5fd4a43"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-11-11 01:13:18 +00:00
Benji 65e7d05aad Update README.md 2017-10-31 22:56:49 +00:00
benji7425 753d636318 3.0.1 2017-10-19 00:20:42 +01:00
benji7425 f8fc7d76ac git subrepo pull discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "8efb033"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "8efb033"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-10-19 00:14:01 +01:00
benji7425 91df5ef7ea 3.0.0 2017-10-05 23:25:19 +01:00
benji7425 74a7a5d569 Fix user posted links not being detected if setup done after b5 update 2017-10-05 23:06:19 +01:00
Benji a489726eb6 3.0.0-b7
Fix crash restart when bot received DM
2017-10-02 11:49:58 +01:00
benji7425 e3c102aa5b 3.0.0-b6
Remove 'BODY is not RSS or ATOM' error from console logging'
2017-10-02 02:08:13 +01:00
benji7425 8c6462e1b7 3.0.0-b5 2017-10-02 01:00:16 +01:00
benji7425 fd650dd981 Prevent checking of feeds for guilds the bot is no longer in
Plus fix a couple related issues
2017-10-02 00:52:36 +01:00
benji7425 ef5f455d4d Add upgrading of json data on startup 2017-10-02 00:42:01 +01:00
benji7425 f1f3b4a8df git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "1ed6225"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "1ed6225"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-10-02 00:20:31 +01:00
benji7425 71e61663e2 Fix exception if bot mentioned without a command 2017-10-02 00:18:05 +01:00
benji7425 ec8b165c96 Re-implement help message 2017-10-02 00:09:36 +01:00
benji7425 8f9acdb455 Merge branch 'command-framework' 2017-10-01 23:27:51 +01:00
benji7425 b3deb2a640 Refactor multiple areas for simplicity and readability
This is a squash commit of many commits
2017-10-01 23:20:06 +01:00
benji7425 5b2916bf77 I changed my mind, we're going back to promises
Require command invoke methods to return a promise
2017-09-24 22:46:58 +01:00
benji7425 60efeeebe8 git subrepo pull discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "9f209e1"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "9f209e1"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-09-24 22:01:23 +01:00
benji7425 c8a314c6c2 git subrepo push discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "0bf4f9d"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "0bf4f9d"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-09-24 21:39:53 +01:00
benji7425 b682b8af5c Update commands to use message.reply, rather than promises
The promise method was just too annoying, better to go back to .reply
2017-09-24 21:39:34 +01:00
benji7425 dc889096a5 Fix incorrect parameter being passed to internal command handling 2017-09-24 21:39:05 +01:00
benji7425 a744b1c69c Separate commands into separate files for command framework compatibility 2017-09-24 21:31:30 +01:00
benji7425 0c2eafcb6c Add client as a parameter to command invokation 2017-09-24 21:20:12 +01:00
benji7425 d6bc7b631b git subrepo pull discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "180d069"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "180d069"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-09-24 21:07:35 +01:00
benji7425 64ea3d596f 3.0.0-b4 2017-09-20 23:46:29 +01:00
benji7425 bcc24e5ac5 git subrepo pull discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "81a8c67"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "81a8c67"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-09-20 23:44:33 +01:00
benji7425 d30f4f6c1b Fix old package.json references that would have caused problems eventaully 2017-09-20 01:23:44 +01:00
benji7425 e02c3bbc8d 3.0.0-b3 2017-09-20 01:18:47 +01:00
benji7425 44d69cd12d Add some error handling 2017-09-20 01:18:44 +01:00
benji7425 ed427fe3b2 Fix misleading logged error if just "youtube.com" pasted in chat 2017-09-20 00:56:05 +01:00
benji7425 265f81197c Merge branch 'core-update' 2017-09-20 00:44:55 +01:00
benji7425 f25dae8e93 Fix (actually this time) youtube feature urls not being properly converted 2017-09-20 00:43:59 +01:00
benji7425 332a48f841 Fix past links not being checked when a new feed is added 2017-09-20 00:43:42 +01:00
benji7425 a46046393b Fix readme and changelog being gone 2017-09-20 00:07:23 +01:00
benji7425 39df448016 Update for proper compatibility with current core code 2017-09-20 00:04:04 +01:00
benji7425 8414532044 git subrepo commit (merge) discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "77cb9dd"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "8e6d6ce"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-09-19 23:26:30 +01:00
benji7425 6398e39359 Add passing in of token file 2017-09-14 21:57:15 +01:00
benji7425 cf33b8b14d git subrepo pull (merge) discord-bot-core
subrepo:
  subdir:   "discord-bot-core"
  merged:   "d1f015c"
upstream:
  origin:   "git@github.com:benji7425/discord-bot-core.git"
  branch:   "master"
  commit:   "c4f07d0"
git-subrepo:
  version:  "0.3.1"
  origin:   "???"
  commit:   "???"
2017-09-14 21:54:21 +01:00
Benji 8e03504cd6 Refactor some areas for simplicity 2017-09-14 14:02:38 +01:00
Benji 2489909da4 Sqaush merge and adapt for template update using shared core code 2017-09-14 13:09:47 +01:00
Benji 7eae7c3484 Update vscode file explorer excludes 2017-09-14 12:45:59 +01:00
39 changed files with 2919 additions and 479 deletions

35
.eslintrc Normal file
View file

@ -0,0 +1,35 @@
{
"env": {
"browser": true,
"node": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"indent": [
"warn",
4,
{
"SwitchCase": 1
}
],
"quotes": [
"warn",
"double"
],
"semi": [
"error",
"always"
],
"no-undef": "error",
"no-unused-vars": "warn",
"eqeqeq": [
"error",
"always"
]
}
}

22
.gitignore vendored
View file

@ -1,10 +1,9 @@
### Discord bots ####
guilds.json
token.json
log
.vscode/
update.sh
guilds-data/*
token.json*
# Created by https://www.gitignore.io/api/node,visualstudiocode
# Created by https://www.gitignore.io/api/node
### Node ###
# Logs
@ -67,13 +66,4 @@ typings/
# dotenv environment variables file
.env
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
# End of https://www.gitignore.io/api/node,visualstudiocode
# End of https://www.gitignore.io/api/node

3
.npmrc
View file

@ -1,3 +1,2 @@
save=true
save-exact=true
cache=node_cache
save-exact=true

14
.vscode/launch.json vendored
View file

@ -1,14 +0,0 @@
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceRoot}/bootstrap.js"
}
]
}

View file

@ -1,9 +0,0 @@
{
"files.exclude": {
"log": true,
".npmrc": true,
"node_modules": true,
"node_cache": true,
"token.json": true
}
}

View file

@ -1,22 +1,119 @@
# Changelog
## v3.0.0-b2
## v3.5.2
### Added
- Added bot name to version command
- Added stats command
### Fixed
- Fixed reset command not being admin only
- Full and short youtube urls not being properly converted
## v3.0.0-b1
### Added
- Fancy new @bot help command
## v3.5.1
### Fixed
- Fixed reset command not working
### Updated
- Removed deletion of data for removed guilds on startup, as Discord outages can wrongly report the bot as being removed
## v3.5.0
### Added
- MongoDB support
- Reset command to clear all data for a guild
### Updated
- Removed automatic daily restart (I think it shouldn't be needed now that MongoDB support is working)
### Fixed
- Guild data being deleted on a Discord outage
## v3.4.0
### Added
- Added automatic daily restart
### Updated
- Disabled a few unused websocket events
- Update database compaction to be more frequent
### Fixed
- Fixed YouTube feeds not updating
## v3.3.0
### Updated
- Updated RSS parser to now use [rss-parser](https://www.npmjs.com/package/rss-parser) module to increase compatibility with feeds
- Updated RSS entry caching to exclude 'www.' prefix to avoid certain mis-caches
## v3.2.2
### Fixed
- Fixed a couple of edge case errors
## v3.2.1
### Fixed
- Fixed memory leak due to unconfigured discord.js caching
## v3.2.0
### Updated
- Updated data storage to use a NeDB database rather than a json file
- Updated feed checking interval to check one guild every 10 seconds (this may slow down the time it takes to post, but will improve performance)
- Improve stability of feed checking
- Tidy up some console spam
### Fixed
- Fix bot crash if feed article contains link with invalid host name
- Temporary fix for bot crash if used with a feed without links in the articles (didn't realise this was possible...)
- Attempt fix for issues caused by every feed of every guild being checked at the same time
## v3.1.3
### Added
- Add rudimentary pagination for viewing feeds when there are more than 10
### Fixed
- Fix articles not posting if contents too long for a single discord message
## v3.1.2
### Fixed
- Deleted channels with feeds sending the bot into a reconnect loop
## v3.1.1
### Fixed
- Empty RSS feed crash
## v3.1.0
### Added
- RSS element content is now included in the post the bot makes when there is a new feed
- Warning message after setup command if supplied URL does not return valid RSS
- Guild join and leave messages in the console
- Removal of guild data if the bot leaves a guild
### Updated
- Route a lot of mostly irrelevant console spam to a file instead of the console
- Updated launch command to pass max-old-space-size parameter to limit memory usage
### Fixed
- Fixed syntax error when role omitted in feed setup command; it is now properly optional
- Fixed the wrong feed sometimes being removed when using the remove-feed command
## v3.0.1
### Fixed
- Fixed nicknamed bot not responding to users on android
- Fixed "playing" message including "https://" in front of site url
## v3.0.0
### Added
- Significantly more debug logging
- Fancy new @bot help command
### Updatd
- Significant back-end updates
- Commands now invoked with an @mention to the bot
- Updated error handling for Discord API errors
- Removed "Body is not RSS or ATOM" error from being console logged
- These seem to happen quite a lot, but don't actually impair the functionality, so just cause un-necessary spam
- Removed "command not recognised" response, it caused 'fake' errors if multiple bots being run off the same token
### Fixed
- Fixed full and short youtube urls not being properly converted
- Fixed "multiple instance" issue
- Fixed a couple of occasional memory leaks
## v2.0.0-b1
### Added
- Multi-guild support
- In-chat commands for setup and configuration
@ -25,47 +122,35 @@
- Remove an existing feed
### Updated
- Make save file configurable to allow use as a module with other bots
- Update config file structure
- Now uses discord.js instead of discord.io
- YouTube links automatically handled; no more separate "YouTube mode" config item
### Fixed
- Crash if trying to view feeds list before any feeds have been set up
## v1.4.0
### Added
- Support for posting links from multiple feeds
- Tagging of separate roles for each feed being checked
### Updated
- Updated bot connection code to use my discord-bot-wrapper
### Removed
- !logsplease command removed as the OTT logging was just being annoying
## v1.3.2
### Fixed
- Fixed list posting channel messages being ignored
## v1.3.1
### Fixed
- Developer commands can now be used from any channel or PM
## v1.3.0
### Added
- Deletion of "You have successfully subscribed" messages after a short delay (configurable)
- 'Developer' commands that can only be accessed by specified users
- !cacheList developer command to view the cached URLs
@ -78,44 +163,34 @@
- The role is mentioned when the link is posted, rather than a long chain of user IDs
## v1.2.1
### Fixed
- Fixed multiple users being unsubscribed when one user unsubscribes
## v1.2.0
### Added
- Chat message/command to request a list of subscribed users
- The ability for users to 'subscribe' so they are tagged whenever a new link is posted
- Logging to a file
- Ability for user to request an upload of the logs file
### Updated
- Added basic spam reduction when logging so the same message won't get logged multiple times in a row
- Refactored a bunch of code to improve efficiency
- Updated timer logic to only ever use a single timer, and share it between posting and reconnecting
## v1.1.2
### Updated
- Updated reconnect logic to hopefully be more stable
## v1.1.1
### Added
- Reconnect timer to repeatedly try reconnect at intervals
### Updated
- Updated support for https conversion to http to hopefully be more consistent
## v1.1.0
### Added
- Added togglable YouTube mode
- Converts full URLs to YouTube share URLs
- Checks against both YouTube full and share URLs to ensure same video not posted twice
@ -126,4 +201,4 @@
- Changed expected name for bot config file to bot-config.json rather than botConfig.json
### Fixed
- New timer being created every time the bot reconnected
- New timer being created every time the bot reconnected

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Benjamin Higgins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,4 +1,4 @@
# Discord rss bot
# Discord RSS Bot
<!--summary-->
Posts the latest URLs from an RSS feed, optionally @mention-ing a role when posted
@ -18,46 +18,48 @@ Posts the latest URLs from an RSS feed, optionally @mention-ing a role when post
## Invite
By inviting this bot to your server you agree to the [terms and conditions](#privacy-statement) laid out in the privacy section of this document.
If you agree, invite to your server with [this link](https://discordapp.com/oauth2/authorize?client_id=343909688045469698&scope=bot&permissions=0x00010c00).
~~If you agree, invite to your server with this link~~.
*Temporarily unavailable due to scaling issues and the large amount of attention recently.*
## Setup
You can ask the bot for help with commands by typing `@RSS_Bot help`
You can ask the bot for help with commands by typing `@RSS Bot help`
### Add a new feed
`@RSS_Bot add-feed <url> <#channel> [@role]`
`@RSS Bot add-feed <url> <#channel> [@role]`
- *url* must be an RSS feed URL
- *#channel* must be a channel mention
- *@role* must be a role mention (make sure "Anyone can mention this role" is turned on during setup)
Example:
`@RSS_Bot add-feed http://lorem-rss.herokuapp.com/feed?unit=second&interval=30 #rss-posts @subscribers`
`@RSS Bot add-feed http://lorem-rss.herokuapp.com/feed?unit=second&interval=30 #rss-posts @subscribers`
### View feeds configured for this server
`@RSS_Bot view-feeds`
`@RSS Bot view-feeds`
This will display a list of RSS feeds configured for this server, along with a unique ID for each
### Remove a configured feed
`@RSS_Bot remove-feed <feed-id>`
`@RSS Bot remove-feed <feed-id>`
To remove a feed you will need it's unique ID, which you can find by running the above *view-feeds* command
Example:
`@RSS_Bot remove-feed ABc-123dEF`
`@RSS Bot remove-feed ABc-123dEF`
## Permissions
The bot requires certain permissions, which you are prompted for on the invite screen.
Each permission has a reason for being required, explained below.
| Permission | Reason |
|----------------------|-------------------------------------------------------------|
| Read messages | Detect when you use commands |
| Send messages | Respond when you use commands; post new RSS links |
| Read message history | Check if any new RSS links have been posted during downtime |
| Permission | Reason |
|----------------------|--------------------------------------------------------------|
| Read messages | Detect when you use commands |
| Send messages | Respond when you use commands; post new RSS links |
| Read message history | Check if any new RSS links have been posted during downtime |
| Embed links | Responses to 'help' requests use message embeds for nice formatting |
## Privacy statement
@ -78,9 +80,12 @@ Should you wish for the data stored about your server to be removed, please cont
1. Clone the repository, or download and extract the zip file (preferrably from the release page)
2. Make sure you have *npm* and *git* installed
3. Run `npm install`
4. Add *token.json* in the root folder: `{ "token": "your-token-goes-here" }`
4. Add *token.json* in the root folder (make sure to include the quotes ""): `"your-token-goes-here"`
5. Run `npm start`
**Note for git users**
If you cloned the repository with git, make sure you `git reset --hard vX.Y` to a specific version, as latest master isn't always production ready!
## Need help?
I am available for contact via my [support Discord server](https://discordapp.com/invite/SSkbwSJ). I will always do my best to respond, however I am often busy so can't always be available right away, and as this is a free service I may not always be able to resolve your query.

View file

@ -1,108 +0,0 @@
//external lib imports
const GetUrls = require("get-urls"); //for extracting urls from messages
//my imports
const DiscordUtil = require("discordjs-util");
//app component imports
const GuildData = require("./models/guild-data.js");
const FeedData = require("./models/feed-data.js");
module.exports = {
onReady(client, guildsData, config) {
return new Promise((resolve, reject) => {
parseLinksInGuilds(client.guilds, guildsData)
.then(() => checkFeedsInGuilds(client.guilds, guildsData))
.then(() => setInterval(() => checkFeedsInGuilds(client.guilds, guildsData), config.feedCheckIntervalSec * 1000)); //set up an interval to check all the feeds
});
},
onCommand(commandObj, commandsObj, params, guildData, message, config, client, botName) {
switch (commandObj.command) {
case commandsObj.addFeed.command:
return addFeed(client, guildData, message, config.maxCacheSize);
case commandsObj.removeFeed.command:
return removeFeed(guildData, message, botName);
case commandsObj.viewFeeds.command:
return viewFeeds(guildData);
}
},
onNonCommandMsg(message, guildData) {
guildData.feeds.forEach(feedData => {
if (message.channel.name === feedData.channelName)
feedData.cachedLinks.push(...GetUrls(message.content)); //spread the urlSet returned by GetUrls into the cache array
});
}
};
function addFeed(client, guildData, message, maxCacheSize) {
return new Promise((resolve, reject) => {
const feedUrl = [...GetUrls(message.content)][0];
const channel = message.mentions.channels.first();
if (!feedUrl || !channel)
reject("Please provide both a channel and an RSS feed URL. You can optionally @mention a role also.");
const role = message.mentions.roles.first();
const feedData = new FeedData({
url: feedUrl,
channelName: channel.name,
roleName: role ? role.name : null,
maxCacheSize: maxCacheSize
});
//ask the user if they're happy with the details they set up, save if yes, don't if no
DiscordUtil.ask(client, message.channel, message.member, "Are you happy with this?\n" + feedData.toString())
.then(responseMessage => {
//if they responded yes, save the feed and let them know, else tell them to start again
if (responseMessage.content.toLowerCase() === "yes") {
if (!guildData)
guildData = new GuildData({ id: message.guild.id, feeds: [] });
guildData.feeds.push(feedData);
resolve("Your new feed has been saved!");
}
else
reject("Your feed has not been saved, please add it again with the correct details");
});
});
}
function removeFeed(guildData, message, botName) {
return new Promise((resolve, reject) => {
const parameters = message.content.split(" ");
if (parameters.length !== 3)
resolve(`Please use the command as such:\n\`\`\` ${botName} remove-feed feedid\`\`\``);
else {
const idx = guildData.feeds.findIndex(feed => feed.id === parameters[2]);
if (!Number.isInteger(idx))
reject("Can't find feed with id " + parameters[2]);
else {
guildData.feeds.splice(idx, 1);
resolve("Feed removed!");
}
}
});
}
function viewFeeds(guildData) {
if (!guildData)
return Promise.reject("Guild not setup");
return Promise.resolve(guildData.feeds.map(f => f.toString()).join("\n"));
}
function checkFeedsInGuilds(guilds, guildsData) {
Object.keys(guildsData).forEach(key => guildsData[key].checkFeeds(guilds));
}
function parseLinksInGuilds(guilds, guildsData) {
const promises = [];
for (let guildId of guilds.keys()) {
const guildData = guildsData[guildId];
if (guildData)
promises.push(guildData.cachePastPostedLinks(guilds.get(guildId)));
}
return Promise.all(promises);
}

51
app/commands/add-feed.js Normal file
View file

@ -0,0 +1,51 @@
const { promisify } = require("util");
const Config = require("../config.json");
const Core = require("../../core");
const FeedData = require("../models/feed-data.js");
const GetUrls = require("get-urls");
const ShortID = require("shortid");
// @ts-ignore
const readFeed = url => promisify(require("rss-parser").parseURL)(url);
module.exports = new Core.Command({
name: "add-feed",
description: "Add an RSS feed to be posted in a channel, with an optional role to tag",
syntax: "add-feed <url> <#channel> [@role]",
admin: true,
invoke: invoke
});
function invoke({ message, params, guildData, client }) {
const feedUrl = [...GetUrls(message.content)][0],
channel = message.mentions.channels.first();
if (!feedUrl || !channel)
return Promise.reject("Please provide both a channel and an RSS feed URL. You can optionally @mention a role also.");
const role = message.mentions.roles.first(),
feedData = FeedData.create({
feedID: ShortID.generate(),
url: feedUrl,
channelID: channel.id,
roleID: role ? role.id : null,
maxCacheSize: Config.maxCacheSize
});
return new Promise((resolve, reject) => {
readFeed(feedUrl)
.then(() => {
Core.util.ask(client, message.channel, message.member, "Are you happy with this (yes/no)?\n" + feedData.toString())
.then(responseMessage => {
if (responseMessage.content.toLowerCase() === "yes") {
guildData.feeds.push(feedData);
guildData.cachePastPostedLinks(message.guild)
.then(() => resolve("Your new feed has been saved!"));
}
else
reject("Your feed has not been saved, please add it again with the correct details");
});
})
.catch(err => reject(`Unable to add the feed due to the following error:\n${err.message}`));
});
}

View file

@ -0,0 +1,18 @@
const Core = require("../../core");
module.exports = new Core.Command({
name: "remove-feed",
description: "Remove an RSS feed by it's ID",
syntax: "remove-feed <dir>",
admin: true,
invoke: invoke
});
function invoke({ message, params, guildData, client }) {
const idx = guildData.feeds.findIndex(feed => feed.feedID === params[0]);
if (!Number.isInteger(idx))
return Promise.reject("Can't find feed with id " + params[0]);
guildData.feeds.splice(idx, 1);
return Promise.resolve("Feed removed!");
}

View file

@ -0,0 +1,23 @@
const Core = require("../../core");
const Config = require("../config.json");
module.exports = new Core.Command({
name: "view-feeds",
description: "View a list of configured feeds and their associated details",
syntax: "view-feed",
admin: true,
invoke: invoke
});
function invoke({ message, params, guildData, client }) {
if (!guildData)
return Promise.reject("Guild not setup");
const startIdx = params[0] ? (params[0] - 1) * Config.viewFeedsPaginationLimit : 0;
const endIdx = startIdx + Config.viewFeedsPaginationLimit + 1;
let responseStr = guildData.feeds.map(f => f.toString()).slice(startIdx, endIdx).join("\n");
if (guildData.feeds.length > endIdx)
responseStr += `Use *view-feeds ${startIdx + 2}* to view more`;
return Promise.resolve(responseStr || "No feeds configured");
}

View file

@ -1,43 +1,6 @@
{
"generic": {
"saveFile": "./guilds.json",
"saveIntervalSec": 60,
"website": "https://benji7425.github.io",
"discordInvite": "https://discord.gg/SSkbwSJ",
"defaultDMResponse": "This bot does not have any handling for direct messages. To learn more or get help please visit %s, or join my Discord server here: %s"
},
"maxCacheSize": 100,
"feedCheckIntervalSec": 30,
"commands": {
"version": {
"command": "version",
"description": "Returns the bot version",
"syntax": "version",
"admin": false
},
"help": {
"command": "help",
"description": "Display information about commands available to you",
"syntax": "help",
"admin": false
},
"addFeed": {
"command": "add-feed",
"description": "Add an RSS feed to be posted in a channel, with an optional role to tag",
"syntax": "add-feed <url> <#channel> [@role]",
"admin": true
},
"removeFeed": {
"command": "remove-feed",
"description": "Remove an RSS feed by it's ID",
"syntax": "remove-feed <id>",
"admin": true
},
"viewFeeds": {
"command": "view-feeds",
"description": "View a list of configured feeds and their associated details",
"syntax": "view-feed",
"admin": true
}
}
}
"feedCheckInterval": 10000,
"charLimit": 1920,
"viewFeedsPaginationLimit": 10
}

View file

@ -1,123 +1,74 @@
//node imports
const FileSystem = require("fs"); //manage files
const Util = require("util"); //various node utilities
const Core = require("../core");
const GetUrls = require("get-urls");
const GuildData = require("./models/guild-data.js");
// @ts-ignore
const Config = require("./config.json");
//external lib imports
const Discord = require("discord.js");
const JsonFile = require("jsonfile"); //save/load data to/from json
const guildsIterator = (function* () {
while (true) {
if (client.guilds.size === 0)
yield null;
else
for (let i = 0; i < client.guilds.size; i++)
yield [...client.guilds.values()][i];
}
})();
//my imports
const DiscordUtil = require("discordjs-util"); //some discordjs helper functions of mine
// @ts-ignore
const client = new Core.Client(require("../token.json"), __dirname + "/commands", GuildData);
//app components
const GuildData = require("./models/guild-data.js"); //data structure for guilds
const PackageJSON = require("../package.json"); //used to provide some info about the bot
const Bot = require("./bot.js");
client.on("beforeLogin", () =>
setInterval(doGuildIteration, Config.feedCheckInterval));
//global vars
let writeFile = null;
client.on("ready", () => {
parseLinksInGuilds().then(doGuildIteration);
require("./legacy-upgrader.js")(); //upgrade legacy json into new database format
});
//use module.exports as a psuedo "onready" function
module.exports = (client, config = null) => {
config = config || require("./config.json"); //load config file
const guildsData = FileSystem.existsSync(config.generic.saveFile) ? fromJSON(JsonFile.readFileSync(config.generic.saveFile)) : {}; //read data from file, or generate new one if file doesn't exist
client.on("message", message => {
if (message.channel.type !== "text" || !message.member)
return;
//create our writeFile function that will allow other functions to save data to json without needing access to the full guildsData or config objects
//then set an interval to automatically save data to file
writeFile = () => JsonFile.writeFile(config.generic.saveFile, guildsData, err => { if (err) DiscordUtil.dateError("Error writing file", err); });
setInterval(() => writeFile(), config.generic.saveIntervalSec * 1000);
client.guildDataModel.findOne({ guildID: message.guild.id })
.then(guildData => guildData && cacheUrlsInMessage(message, guildData));
});
//handle messages
client.on("message", message => {
if (message.author.id !== client.user.id) { //check the bot isn't triggering itself
client.bootstrap();
//check whether we need to use DM or text channel handling
if (message.channel.type === "dm")
HandleMessage.dm(client, config, message);
else if (message.channel.type === "text" && message.member)
HandleMessage.text(client, config, message, guildsData);
}
});
//INTERNAL FUNCTIONS//
function parseLinksInGuilds() {
const promises = [];
Bot.onReady(client, guildsData, config).then(() => writeFile).catch(err => DiscordUtil.dateError(err));
};
client.guildDataModel.find().then(guildDatas =>
guildDatas
.filter(guildData => client.guilds.get(guildData.guildID))
.map(guildData => ({ guildData, guild: client.guilds.get(guildData.guildID) }))
.forEach(({ guildData, guild }) => promises.push(guildData.cachePastPostedLinks(guild).catch()))
);
const HandleMessage = {
dm: (client, config, message) => {
message.reply(Util.format(config.generic.defaultDMResponse, config.generic.website, config.generic.discordInvite));
},
text: (client, config, message, guildsData) => {
const isCommand = message.content.startsWith(message.guild.me.toString());
let guildData = guildsData[message.guild.id];
if (!guildData)
guildData = guildsData[message.guild.id] = new GuildData({ id: message.guild.id });
if (isCommand) {
const userIsAdmin = message.member.permissions.has("ADMINISTRATOR");
const botName = "@" + (message.guild.me.nickname || client.user.username);
const split = message.content.toLowerCase().split(/\ +/); //split the message at whitespace
const command = split[1]; //extract the command used
const commandObj = config.commands[Object.keys(config.commands).find(x => config.commands[x].command.toLowerCase() === command)]; //find the matching command object
if (!commandObj || (!commandObj.admin && !userIsAdmin))
return;
const params = split.slice(2, split.length); //extract the parameters passed for the command
const expectedParamCount = commandObj.syntax.split(/\ +/).length - 1; //calculate the number of expected command params
let finalisedParams;
if (params.length > expectedParamCount) //if we have more params than needed
finalisedParams = params.slice(0, expectedParamCount - 1).concat([params.slice(expectedParamCount - 1, params.length).join(" ")]);
else //else we either have exactly the right amount, or not enough
finalisedParams = params;
//find which command was used and handle it
switch (command) {
case config.commands.version.command:
message.reply(`${PackageJSON.name} v${PackageJSON.version}`);
break;
case config.commands.help.command:
message.channel.send(createHelpEmbed(botName, config, userIsAdmin));
break;
default:
if (finalisedParams.length >= expectedParamCount)
Bot.onCommand(commandObj, config.commands, finalisedParams, guildData, message, config, client, botName)
.then(msg => {
message.reply(msg);
writeFile();
})
.catch(err => {
message.reply(err);
DiscordUtil.dateError(err);
});
else
message.reply(`Incorrect syntax!\n**Expected:** *${botName} ${commandObj.syntax}*\n**Need help?** *${botName} ${config.commands.help.command}*`);
break;
}
}
else
Bot.onNonCommandMsg(message, guildData);
}
};
function fromJSON(json) {
const guildsData = Object.keys(json);
guildsData.forEach(guildID => { json[guildID] = new GuildData(json[guildID]); });
return json;
return Promise.all(promises);
}
function createHelpEmbed(name, config, userIsAdmin) {
const commandsArr = Object.keys(config.commands).map(x => config.commands[x]).filter(x => userIsAdmin || !x.admin);
function doGuildIteration() {
const guild = guildsIterator.next().value;
const embed = new Discord.RichEmbed().setTitle("__Help__");
if (guild)
client.guildDataModel.findOne({ guildID: guild.id })
.then(guildData => guildData && checkGuildFeeds(guild, guildData));
}
commandsArr.forEach(command => {
embed.addField(command.command, `${command.description}\n**Usage:** *${name} ${command.syntax}*${userIsAdmin && command.admin ? "\n***Admin only***" : ""}`);
});
function checkGuildFeeds(guild, guildData) {
guildData.checkFeeds(guild)
.then(values => values.some(x => x) && guildData.save());
}
embed.addField("__Need more help?__", `[Visit my website](${config.generic.website}) or [Join my Discord](${config.generic.discordInvite})`, true);
function cacheUrlsInMessage(message, guildData) {
const anyNewLinksPosted = [];
return { embed };
guildData.feeds
.filter(feedData => message.channel.id === feedData.channelID)
.forEach(feedData => anyNewLinksPosted.push(feedData.cache(...GetUrls(message.content))));
if (anyNewLinksPosted.some(x => x))
guildData.save();
}

30
app/legacy-upgrader.js Normal file
View file

@ -0,0 +1,30 @@
// @ts-nocheck
const NewGuildData = require("./models/guild-data.js");
const NewFeedData = require("./models/feed-data.js");
const FileSystem = require("fs");
module.exports = function () {
if (!FileSystem.existsSync("./guilds.json"))
return;
const legacyJson = require("../guilds.json");
for (let guildID of Object.keys(legacyJson)) {
const guildData = NewGuildData.create({ guildID });
for (let feed of legacyJson[guildID].feeds) {
guildData.feeds.push(NewFeedData.create({
feedID: feed.id,
url: feed.url,
roleID: feed.roleID,
channelID: feed.channelID,
cachedLinks: feed.cachedLinks,
maxCacheSize: feed.maxCacheSize
}));
}
guildData.save();
}
FileSystem.rename("./guilds.json", "./guilds.json.backup");
};

View file

@ -1,89 +1,150 @@
//my imports
const DiscordUtil = require("discordjs-util");
// @ts-ignore
const Config = require("../config.json");
//external lib imports
const Dns = require("dns"); //for host resolution checking
const Url = require("url"); //for url parsing
const FeedRead = require("feed-read"); //for extracing new links from RSS feeds
const GetUrls = require("get-urls"); //for extracting urls from messages
const ShortID = require("shortid"); //to provide ids for each feed, allowing guilds to remove them
const { promisify } = require("util");
const Core = require("../../core");
const DiscordUtil = require("../../core").util;
const GetUrls = require("get-urls");
const Url = require("url");
const HtmlToText = require("html-to-text");
module.exports = class FeedData {
constructor({ id, url, channelName, roleName, cachedLinks, maxCacheSize }) {
this.id = id || ShortID.generate();
this.url = url;
this.channelName = channelName;
this.roleName = roleName;
this.cachedLinks = cachedLinks || [];
this.maxCacheSize = maxCacheSize || 10;
// @ts-ignore
const readFeed = url => promisify(require("rss-parser").parseURL)(url);
const resolveDns = promisify(require("dns").resolve);
this.cachedLinks.push = (...elements) => {
const unique = elements
.map(el => normaliseUrl(el)) //normalise all the urls
.filter(el => !this.cachedLinks.includes(el)); //filter out any already cached
Array.prototype.push.apply(this.cachedLinks, unique);
module.exports = class FeedData extends Core.BaseEmbeddedData {
constructor() {
super();
if (this.cachedLinks.length > this.maxCacheSize)
this.cachedLinks.splice(0, this.cachedLinks.length - this.maxCacheSize); //remove the # of elements above the max from the beginning
};
}
this.feedID = "";
this.url = "";
this.channelID = "";
this.roleID = "";
this.cachedLinks = [];
this.maxCacheSize = 100;
/**
* Returns a promise providing all the links posted in the last 100 messages
* @param {Discord.Guild} guild The guild this feed belongs to
* @returns {Promise<string[]>} Links posted in last 100 messages
*/
updatePastPostedLinks(guild) {
const channel = guild.channels.find(ch => ch.type === "text" && ch.name === this.channelName);
// @ts-ignore
this.schema({
feedID: String,
url: String,
channelID: String,
roleID: String,
cachedLinks: [String],
maxCacheSize: Number
});
}
return new Promise((resolve, reject) => {
channel.fetchMessages({ limit: 100 })
.then(messages => {
new Map([...messages].reverse()).forEach(m => this.cachedLinks.push(...GetUrls(m.content))); //push all the links in each message into our links array
resolve(this);
})
.catch(reject);
});
}
cache(...elements) {
const newArticles = elements
.map(el => normaliseUrlForCache(el))
.filter(el => !this._isCached(el));
check(guild) {
Dns.resolve(Url.parse(this.url).host || "", err => { //check we can resolve the host, so we can throw an appropriate error if it fails
if (err)
DiscordUtil.dateError("Connection Error: Can't resolve host", err); //log our error if we can't resolve the host
else
FeedRead(this.url, (err, articles) => { //check the feed
if (err)
DiscordUtil.dateError(err);
else {
let latest = articles[0].link; //extract the latest link
latest = normaliseUrl(latest); //standardise it a bit
Array.prototype.push.apply(this.cachedLinks, newArticles);
//if we don't have it cached already, cache it and callback
if (!this.cachedLinks.includes(latest)) {
this.cachedLinks.push(latest);
this.cachedLinks.splice(0, this.cachedLinks.length - this.maxCacheSize); //seeing as new links come in at the end of the array, we need to remove the old links from the beginning
const channel = guild.channels.find(ch => ch.type === "text" && ch.name.toLowerCase() === this.channelName.toLowerCase());
const role = this.roleName ? guild.roles.find(role => role.name.toLowerCase() === this.roleName.toLowerCase()) : null;
channel.send((role ? role + " " : "") + latest);
}
}
});
});
}
return elements.length > 0;
}
toString() {
const blacklist = ["cachedLinks", "maxCacheSize"];
return `\`\`\`JavaScript\n ${JSON.stringify(this, (k, v) => !blacklist.includes(k) ? v : undefined, "\t")} \`\`\``;
}
updatePastPostedLinks(guild) {
const channel = guild.channels.get(this.channelID);
if (!channel)
return Promise.reject("Channel not found!");
return new Promise((resolve, reject) => {
channel.fetchMessages({ limit: 100 })
.then(messages => {
/* we want to push the links in oldest first, but discord.js returns messages newest first, so we need to reverse them
* discord.js returns a map, and maps don't have .reverse methods, hence needing to spread the elements into an array first */
[...messages.values()].reverse().forEach(m => this.cache(...GetUrls(m.content)));
resolve();
})
.catch(reject);
});
}
fetchLatest(guild) {
const dnsPromise = resolveDns(Url.parse(this.url).hostname).then(() => this._doFetchRSS(guild));
dnsPromise.catch(err => DiscordUtil.dateDebugError("Connection error: Can't resolve host", err.message || err));
return dnsPromise;
}
toString() {
const blacklist = ["cachedLinks", "maxCacheSize"];
return `\`\`\`JavaScript\n ${JSON.stringify(this, (k, v) => !blacklist.find(x => x === k) ? v : undefined, "\t")} \`\`\``;
}
_isCached(url) {
return this.cachedLinks.indexOf(normaliseUrlForCache(url)) > -1;
}
_doFetchRSS(guild) {
const feedPromise = readFeed(this.url).then(parsed => this._processLatestArticle(guild, parsed.feed.entries));
feedPromise.catch(err => DiscordUtil.dateDebugError([`Error reading feed ${this.url}`, err]));
return feedPromise;
}
_processLatestArticle(guild, entries) {
if (entries.length === 0 || !entries[0].link)
return false;
if (this._isCached(entries[0].link))
return false;
this.cache(entries[0].link);
const channel = guild.channels.get(this.channelID),
role = guild.roles.get(this.roleID);
channel.send((role || "") + formatPost(entries[0]))
.catch(err => DiscordUtil.dateDebugError(`Error posting in ${channel.id}: ${err.message || err}`));
return true;
}
};
function normaliseUrl(url) {
url = url.replace("https://", "http://"); //hacky way to treat http and https the same
function formatPost(article) {
let message = "";
let link = "";
let title = "";
if (Url.parse(url).host.startsWith("http://youtu"))
url = url.split("?")[0]; //quick way to chop off stuff like ?feature=youtube
if (article.title) title = `\n**${article.title}**`;
if (article.link) link = `\n\n${normaliseUrlForDiscord(article.link)}`;
url = url.replace(/(www.)?youtube.com\/watch\?v=/, "youtu.be/"); //convert youtube full url to short
message += title;
return url;
}
if (article.content) {
let maxLen = Config.charLimit - title.length - link.length - 4;
let sanitized = HtmlToText.fromString(article.content);
message += sanitized.length > maxLen ? `\n${sanitized.substr(0, maxLen)}...` : `\n${sanitized}`;
}
message += link;
return message;
}
function normaliseUrlForDiscord(url) {
const parsedUrl = Url.parse(url);
if (parsedUrl.host && parsedUrl.host.includes("youtube.com"))
url = normaliseYouTubeUrl(url, parsedUrl);
return url;
}
function normaliseYouTubeUrl(origUrl, parsedUrl) {
const videoIDParam = parsedUrl.query ? parsedUrl.query.split("&").find(x => x.startsWith("v=")) : null;
if (!videoIDParam)
return origUrl;
const videoID = videoIDParam.substring(videoIDParam.indexOf("=") + 1, videoIDParam.length);
return `http://youtu.be/${videoID}`
}
function normaliseUrlForCache(url) {
return normaliseUrlForDiscord(url).replace(/^((https?:\/\/)?(www.)?)/, "");
}

View file

@ -1,23 +1,34 @@
const Core = require("../../core");
const FeedData = require("./feed-data.js");
const Util = require("discordjs-util");
module.exports = class GuildData {
constructor({ id, feeds }) {
this.id = id;
this.feeds = (feeds || []).map(feed => new FeedData(feed));
}
module.exports = class GuildData extends Core.BaseGuildData {
constructor() {
super();
cachePastPostedLinks(guild) {
const promises = [];
this.feeds = [];
this.feeds.forEach(feed => {
promises.push(feed.updatePastPostedLinks(guild).catch(Util.dateError));
});
this.schema({
feeds: [FeedData]
});
}
return Promise.all(promises);
}
cachePastPostedLinks(guild) {
return Promise.all(
this.feeds
.filter(feed => feedIsActive(feed, guild))
.map(feed => feed.updatePastPostedLinks(guild).catch(err => null))
);
}
checkFeeds(guilds) {
this.feeds.forEach(feed => feed.check(guilds.get(this.id)));
}
};
checkFeeds(guild) {
return Promise.all(
this.feeds
.filter(feed => feedIsActive(feed, guild))
.map(feed => feed.fetchLatest(guild).catch(err => null))
);
}
};
function feedIsActive(feed, guild) {
return guild.channels.get(feed.channelID);
}

20
bootstrap.js vendored
View file

@ -1,20 +0,0 @@
const Discord = require("discord.js");
const DiscordUtil = require("discordjs-util");
const client = new Discord.Client();
process.on("uncaughtException", (err) => {
DiscordUtil.dateError("Uncaught exception!", err);
});
client.login(require("./token.json").token);
client.on("ready", () => {
DiscordUtil.dateLog("Registered bot " + client.user.username);
require("./app/index.js")(client);
client.user.setPresence({ game: { name: "benji7425.github.io", type: 0 } });
});
client.on("disconnect", eventData => {
DiscordUtil.dateError("Bot was disconnected!", eventData.code, eventData.reason);
});

79
core/.gitignore vendored Normal file
View file

@ -0,0 +1,79 @@
### Discord bots ####
guilds.json
token.json
log
# Created by https://www.gitignore.io/api/node,visualstudiocode
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_cache
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
# End of https://www.gitignore.io/api/node,visualstudiocode

12
core/.gitrepo Normal file
View file

@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
;
[subrepo]
remote = git@github.com:benji7425/discord-bot-core.git
branch = master
commit = 7a3eed3eff576ed51cfdfbbad18df07d4fcf52a7
parent = 09cf5233db442fa0af452e84e90289619532418a
method = merge
cmdver = 0.3.1

2
core/.npmrc Normal file
View file

@ -0,0 +1,2 @@
save=true
save-exact=true

21
core/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Benjamin Higgins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

27
core/README.md Normal file
View file

@ -0,0 +1,27 @@
# Discord bot core
Core code for connection and command handling for my Discord bots.
This is not actually a Discord bot. To learn about some of my available Discord bots please visit [my website](https://benji7425.github.io/)
This code is included in the repo for each bot using [git subrepo](https://github.com/ingydotnet/git-subrepo), which I prefer over submodules and subtrees.
This code does not function on it's own, it simply provides common functionality my Discord bots can make use of.
To test/modify this code, it needs to be run in the context of an actual bot.
A good candidate is my [template project](https://github.com/benji7425/discord-bot-template), which should run and connect just fine, just won't do much.
## Built with
- [discord.js](https://discord.js.org/#/)
- [NeDB](https://github.com/louischatriot/nedb)
- [camo](https://github.com/scottwrobinson/camo)
## Contributing
The easiest way to get setup would be a fork of this repo, and the fork of a bot to use as a development context.
I suggest using my [template project](https://github.com/benji7425/discord-bot-template) as a development context, along with [git subrepo](https://github.com/ingydotnet/git-subrepo) to push back to your core fork.
If you are uncomfortable using git subrepo, you could just as easily copy/paste your child `core` directory back into your fork.
My [template project](https://github.com/benji7425/discord-bot-template) has more in-depth details about how to setup and test.
If you have a completed change, please submit a pull request from your `core` fork back to this repo.
Whilst this is very easy to use once you know how, I appreciate this might be a little tricky if you aren't familiar with developing in this way.
Feel free to contact me if you would like assistance. Find contact details [here](https://benji7425.github.io/contact).

View file

@ -0,0 +1,8 @@
const Camo = require("camo");
// @ts-ignore
module.exports = class BaseEmbeddedData extends Camo.EmbeddedDocument {
constructor() {
super();
}
};

9
core/base-guild-data.js Normal file
View file

@ -0,0 +1,9 @@
const Camo = require("camo");
module.exports = class BaseGuildData extends Camo.Document {
constructor() {
super();
this.guildID = String;
}
};

83
core/client.js Normal file
View file

@ -0,0 +1,83 @@
const CoreUtil = require("./util.js");
const Camo = require("camo");
const CronJob = require("cron").CronJob;
const Discord = require("discord.js");
const HandleGuildMessage = require("./handle-guild-message.js");
// @ts-ignore
const InternalConfig = require("./internal-config.json");
const RequireAll = require("require-all");
let database;
module.exports = class Client extends Discord.Client {
/**
* Construct a new Discord.Client with some added functionality
* @param {string} token bot token
* @param {string} commandsDir location of dir containing commands .js files
* @param {*} guildDataModel GuildData model to be used for app; must extend BaseGuildData
*/
constructor(token, commandsDir, guildDataModel) {
super({
messageCacheMaxSize: 16,
disabledEvents: InternalConfig.disabledEvents
});
this._token = token;
this.commandsDir = commandsDir;
this.guildDataModel = guildDataModel;
this.commands = RequireAll(this.commandsDir);
this.on("ready", this._onReady);
this.on("message", this._onMessage);
this.on("debug", this._onDebug);
this.on("guildCreate", this._onGuildCreate);
process.on("uncaughtException", err => this._onUnhandledException(this, err));
}
_onReady() {
this.user.setGame(InternalConfig.website.replace(/^https?:\/\//, ""));
CoreUtil.dateLog(`Registered bot ${this.user.username}`);
}
_onMessage(message) {
if (message.channel.type === "text" && message.member)
HandleGuildMessage(this, message, this.commands);
}
_onDebug(info) {
info = info.replace(/Authenticated using token [^ ]+/, "Authenticated using token [redacted]");
if (!InternalConfig.debugIgnores.some(x => info.startsWith(x)))
CoreUtil.dateDebug(info);
}
_onGuildCreate(guild) {
CoreUtil.dateLog(`Added to guild ${guild.name}`);
}
_onUnhandledException(client, err) {
CoreUtil.dateError("Unhandled exception!\n", err);
CoreUtil.dateLog("Destroying existing client...");
client.destroy().then(() => {
CoreUtil.dateLog("Client destroyed, recreating...");
setTimeout(() => client.login(client._token), InternalConfig.reconnectTimeout);
});
}
bootstrap() {
Camo.connect(InternalConfig.dbConnectionString).then(db => {
database = db;
const dbProtocol = InternalConfig.dbConnectionString.match(/^(.+):\/\//)[1];
CoreUtil.dateLog(`Database protocol: ${dbProtocol}`);
if (dbProtocol === "nedb") {
CoreUtil.dateLog(`Seting up NeDB collection compaction cron job; schedule: ${InternalConfig.neDBCompactionSchedule}`);
new CronJob(InternalConfig.neDBCompactionSchedule, () => database.compactCollectionFiles(), null, true);
}
this.emit("beforeLogin");
this.login(this._token);
});
}
};

15
core/command.js Normal file
View file

@ -0,0 +1,15 @@
module.exports = class Command {
constructor({ name, description, syntax, admin, invoke }) {
this.name = name;
this.description = description;
this.syntax = syntax;
this.admin = admin;
this.invoke = invoke;
const params = this.syntax.split(/ +/);
const optionalParams = params.filter(x => x.match(/^\[.+\]$/));
this.maxParamCount = params.length - 1;
this.expectedParamCount = this.maxParamCount - optionalParams.length;
}
};

30
core/commands/help.js Normal file
View file

@ -0,0 +1,30 @@
const Command = require("../command.js");
const Discord = require("discord.js");
const InternalConfig = require("../internal-config.json");
const ParentPackageJson = require("../../package.json");
module.exports = new Command({
name: "help",
description: "Display available commands with descriptions",
syntax: "help",
admin: false,
invoke
});
function invoke({ commands, isMemberAdmin, client }) {
return Promise.resolve(createHelpEmbed(ParentPackageJson.name, commands, isMemberAdmin, client.user.username));
}
function createHelpEmbed(name, commands, userIsAdmin, username) {
const commandsArr = Object.keys(commands).map(x => commands[x]).filter(x => userIsAdmin || !x.admin);
const embed = new Discord.RichEmbed().setTitle(`__${(ParentPackageJson.name + "").replace("discord-bot-", "")} help__`);
commandsArr.forEach(command => {
embed.addField(command.name, `${command.description}\n**Usage:** *@${username} ${command.syntax}*${userIsAdmin && command.admin ? "\n***Admin only***" : ""}`);
});
embed.addField("__Need more help?__", `[Visit my website](${InternalConfig.website}) or [Join my Discord](${InternalConfig.discordInvite})`, true);
return { embed };
}

31
core/commands/reset.js Normal file
View file

@ -0,0 +1,31 @@
const Command = require("../command.js");
const Util = require("../util.js");
module.exports = new Command({
name: "reset",
description: "Reset all data for this Discord server. WARNING: YOU WILL LOSE ALL YOUR SETTINGS!",
syntax: "reset",
admin: true,
invoke
});
function invoke({ guildData, client, message }) {
return new Promise((resolve, reject) => {
/* this is a very hacky way of doing this, but when using .resolve()
the guildData object gets saved back to the database straight away,
meaning it'd be deleted and instnantly re-created. Using .reject
means that .save doesn't get called by the parent. Very hacky but works. */
Util.ask(client, message.channel, message.member, "Are you sure you want to delete all the data for this server? (yes/no)")
.then(response => {
if (response.toLowerCase() === "yes")
guildData
.delete()
.then(() => reject("Data for this server successfully deleted"));
else
reject("Guild data was not deleted");
});
// .then(() => resolve("Data for this server successfully deleted"))
// .catch(() => reject("Error deleting data for this server"));
});
}

31
core/commands/stats.js Normal file
View file

@ -0,0 +1,31 @@
const Command = require("../command.js");
module.exports = new Command({
name: "stats",
description: "Show some stats about the bot",
syntax: "stats",
admin: false,
invoke
});
function invoke({ message, params, guildData, client }) {
return Promise.resolve(`
**Server count:** ${client.guilds.size}
**Cached users:** ${client.users.size}
**Uptime:** ${toHHMMSS(client.uptime)}
`);
}
function toHHMMSS(ms) {
const secsTruncated = Math.trunc(ms / 1000); // don't forget the second param
const hrs = Math.floor(secsTruncated / 3600);
const mins = Math.floor((secsTruncated - (hrs * 3600)) / 60);
const secs = secsTruncated - (hrs * 3600) - (mins * 60);
let hoursStr = hrs.toString(), minsStr = mins.toString(), secsStr = secs.toString();
if (hrs < 10) { hoursStr = "0" + hrs; }
if (mins < 10) { minsStr = "0" + mins; }
if (secs < 10) { secsStr = "0" + secs; }
return hoursStr + ":" + minsStr + ":" + secsStr;
}

15
core/commands/version.js Normal file
View file

@ -0,0 +1,15 @@
const Command = require("../command.js");
// @ts-ignore
const ParentPackageJson = require("../../package.json");
module.exports = new Command({
name: "version",
description: "Return version number",
syntax: "version",
admin: false,
invoke
});
function invoke() {
return Promise.resolve(`${(ParentPackageJson.name + "").replace("discord-bot-", "")} v${ParentPackageJson.version}`);
}

View file

@ -0,0 +1,54 @@
const RequireAll = require("require-all");
const internalCommands = RequireAll(__dirname + "/commands");
function handleGuildMessage(client, message, commands) {
if (isCommand(message))
client.guildDataModel.findOne({ guildID: message.guild.id })
.then(guildData =>
handleGuildCommand(
client,
message,
Object.assign({}, internalCommands, commands),
guildData || client.guildDataModel.create({ guildID: message.guild.id })
));
}
function handleGuildCommand(client, message, commands, guildData) {
const { botName, isMemberAdmin, params, command } = parseDetails(message, commands);
if (!command)
return;
if (params.length < command.expectedParamCount)
message.reply(`Incorrect syntax!\n**Expected:** *${botName} ${command.syntax}*\n**Need help?** *${botName} help*`);
else if (isMemberAdmin || !command.admin)
command.invoke({ message, params, guildData, client, commands, isMemberAdmin })
.then(response => {
guildData.save()
.then(() => response && message.reply(response))
.catch(() => message.reply("Error saving"));
})
.catch(err => err && message.reply(err));
}
function parseDetails(message, commands) {
const split = message.content.split(/ +/);
const commandName = Object.keys(commands).find(x =>
/**/ commands[x].name.toLowerCase() === (split[1] || "").toLowerCase());
return {
botName: "@" + (message.guild.me.nickname || message.guild.me.user.username),
isMemberAdmin: message.member.permissions.has("ADMINISTRATOR"),
params: split.slice(2, split.length),
command: commands[commandName]
};
}
function isCommand(message) {
//criteria for a command is bot being mentioned
return new RegExp(`^<@!?${/[0-9]{18}/.exec(message.guild.me.toString())[0]}>`).exec(message.content);
}
module.exports = handleGuildMessage;

14
core/index.js Normal file
View file

@ -0,0 +1,14 @@
// @ts-ignore
const InternalConfig = require("./internal-config.json");
module.exports = {
Client: require("./client.js"),
BaseGuildData: require("./base-guild-data.js"),
BaseEmbeddedData: require("./base-embedded-data.js"),
Command: require("./command.js"),
util: require("./util.js"),
details: {
website: InternalConfig.website,
discordInvite: InternalConfig.discordInvite
}
};

20
core/internal-config.json Normal file
View file

@ -0,0 +1,20 @@
{
"dbConnectionString": "nedb://guilds-data",
"neDBCompactionSchedule": "0 0 * * * *",
"website": "https://benji7425.github.io",
"discordInvite": "https://discord.gg/SSkbwSJ",
"debugIgnores": [
"[ws] [connection] Sending a heartbeat",
"[ws] [connection] Heartbeat acknowledged"
],
"disabledEvents": [
"CHANNEL_PINS_UPDATE",
"GUILD_BAN_ADD",
"GUILD_BAN_REMOVE",
"PRESENCE_UPDATE",
"TYPING_START",
"USER_NOTE_UPDATE",
"USER_SETTINGS_UPDATE"
],
"askTimeout": 60000
}

475
core/package-lock.json generated Normal file
View file

@ -0,0 +1,475 @@
{
"name": "discord-bot-core",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "8.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.1.tgz",
"integrity": "sha512-4JFGIC1RSoFngVsT5EZcL793/uRi/OJ3ilsp9DQUr4LZOaMhNM1pPrt9TqlXOnXj3h73hl6NF31v87eQAPXYTg=="
},
"acorn": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz",
"integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ="
},
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
},
"ast-types": {
"version": "0.8.15",
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz",
"integrity": "sha1-ju8IJ/BN/w7IhXupJavj/qYZTlI="
},
"async": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
"integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg="
},
"base62": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/base62/-/base62-0.1.1.tgz",
"integrity": "sha1-e0F0wvlESXU7EcJlHAg9qEGnsIQ="
},
"binary-search-tree": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/binary-search-tree/-/binary-search-tree-0.2.5.tgz",
"integrity": "sha1-fbs7IQ/coIJFDa0jNMMErzm9x4Q=",
"requires": {
"underscore": "1.4.4"
}
},
"bson": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz",
"integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw=",
"optional": true
},
"buffer-shims": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
"integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=",
"optional": true
},
"camo": {
"version": "git+https://github.com/benji7425/camo.git#51d63d2441827b430884400f511ae911f1961727",
"requires": {
"depd": "1.1.0",
"lodash": "3.9.3",
"mongodb": "2.2.34",
"nedb": "1.8.0"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cron": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/cron/-/cron-1.3.0.tgz",
"integrity": "sha512-K/SF7JlgMmNjcThWxkKvsHhey2EDB4CeOEWJ9aXWj3fbQJppsvTPIeyLdHfNq5IbbsMUUjRW1nr5dSO95f2E4w==",
"requires": {
"moment-timezone": "0.5.14"
}
},
"depd": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
"integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM="
},
"discord.js": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.2.0.tgz",
"integrity": "sha1-qt3iuGtpuQUWa4O8Sc/ENSOOGus=",
"requires": {
"long": "3.2.0",
"prism-media": "0.0.1",
"snekfetch": "3.6.1",
"tweetnacl": "1.0.0",
"ws": "3.3.2"
}
},
"es3ify": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/es3ify/-/es3ify-0.1.4.tgz",
"integrity": "sha1-rZ+l3xrjTz8x4SEbWBiy1RB439E=",
"requires": {
"esprima-fb": "3001.1.0-dev-harmony-fb",
"jstransform": "3.0.0",
"through": "2.3.8"
}
},
"es6-promise": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
"integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=",
"optional": true
},
"esmangle-evaluator": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/esmangle-evaluator/-/esmangle-evaluator-1.0.1.tgz",
"integrity": "sha1-Yg2GbvSGGzMR91dm1SqFcrs8YzY="
},
"esprima-fb": {
"version": "3001.1.0-dev-harmony-fb",
"resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-3001.0001.0000-dev-harmony-fb.tgz",
"integrity": "sha1-t303q8046gt3Qmu4vCkizmtCZBE="
},
"falafel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/falafel/-/falafel-1.2.0.tgz",
"integrity": "sha1-wY0k71CRF0pJfzGM0ksCaiXN2rQ=",
"requires": {
"acorn": "1.2.2",
"foreach": "2.0.5",
"isarray": "0.0.1",
"object-keys": "1.0.11"
}
},
"foreach": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"inline-process-browser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/inline-process-browser/-/inline-process-browser-1.0.0.tgz",
"integrity": "sha1-RqYbFT3TybFiSxoAYm7bT39BTyI=",
"requires": {
"falafel": "1.2.0",
"through2": "0.6.5"
}
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"jstransform": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/jstransform/-/jstransform-3.0.0.tgz",
"integrity": "sha1-olkats7o2XvzvoMNv6IxO4fNZAs=",
"requires": {
"base62": "0.1.1",
"esprima-fb": "3001.1.0-dev-harmony-fb",
"source-map": "0.1.31"
}
},
"lie": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.0.2.tgz",
"integrity": "sha1-/9oh17uibzd8rYZdNkmy/Izjn+o=",
"requires": {
"es3ify": "0.1.4",
"immediate": "3.0.6",
"inline-process-browser": "1.0.0",
"unreachable-branch-transform": "0.3.0"
}
},
"localforage": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.5.5.tgz",
"integrity": "sha1-VfwcOoikf2f1+sbxIxsl/xNVZCM=",
"requires": {
"lie": "3.0.2"
}
},
"lodash": {
"version": "3.9.3",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.9.3.tgz",
"integrity": "sha1-AVnoaDL+/8bWHYUrEqlTuZSWvTI="
},
"long": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s="
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"moment": {
"version": "2.19.3",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.19.3.tgz",
"integrity": "sha1-vbmdJw1tf9p4zA+6zoVeJ/59pp8="
},
"moment-timezone": {
"version": "0.5.14",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz",
"integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=",
"requires": {
"moment": "2.19.3"
}
},
"mongodb": {
"version": "2.2.34",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.34.tgz",
"integrity": "sha1-o09Zu+thdUrsQy3nLD/iFSakTBo=",
"optional": true,
"requires": {
"es6-promise": "3.2.1",
"mongodb-core": "2.1.18",
"readable-stream": "2.2.7"
}
},
"mongodb-core": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.18.tgz",
"integrity": "sha1-TEYTm986HwMt7ZHbSfOO7AFlkFA=",
"optional": true,
"requires": {
"bson": "1.0.4",
"require_optional": "1.0.1"
}
},
"nedb": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/nedb/-/nedb-1.8.0.tgz",
"integrity": "sha1-DjUCzYLABNU1WkPJ5VV3vXvZHYg=",
"requires": {
"async": "0.2.10",
"binary-search-tree": "0.2.5",
"localforage": "1.5.5",
"mkdirp": "0.5.1",
"underscore": "1.4.4"
}
},
"object-keys": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
"integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0="
},
"parent-package-json": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/parent-package-json/-/parent-package-json-2.0.1.tgz",
"integrity": "sha1-SbVUqeLcyu1F1+GiXqjOyde7axI="
},
"prism-media": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.1.tgz",
"integrity": "sha1-o0JcnKvVDRxsAuVDlBoRiVZnvRA="
},
"private": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
"integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
"optional": true
},
"readable-stream": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz",
"integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE=",
"optional": true,
"requires": {
"buffer-shims": "1.0.0",
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"string_decoder": "1.0.3",
"util-deprecate": "1.0.2"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"optional": true,
"requires": {
"safe-buffer": "5.1.1"
}
}
}
},
"recast": {
"version": "0.10.43",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz",
"integrity": "sha1-uV1Q9tYHYaX2JS4V2AZ4FoSRzn8=",
"requires": {
"ast-types": "0.8.15",
"esprima-fb": "15001.1001.0-dev-harmony-fb",
"private": "0.1.8",
"source-map": "0.5.7"
},
"dependencies": {
"esprima-fb": {
"version": "15001.1001.0-dev-harmony-fb",
"resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz",
"integrity": "sha1-Q761fsJujPI3092LM+QlM1d/Jlk="
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
}
}
},
"require-all": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/require-all/-/require-all-2.2.0.tgz",
"integrity": "sha1-tEIMIzrAKC0P9Jsnf7iAqLXeCJQ="
},
"require_optional": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
"optional": true,
"requires": {
"resolve-from": "2.0.0",
"semver": "5.5.0"
}
},
"resolve-from": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=",
"optional": true
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM="
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"optional": true
},
"simple-file-writer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/simple-file-writer/-/simple-file-writer-2.0.0.tgz",
"integrity": "sha1-4oPAoghoptQhnX7aGUwe9eK1gvo="
},
"snekfetch": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.1.tgz",
"integrity": "sha512-aLEvf1YR440pINb0LEo/SL2Q2s/A26+YEqPlx09A0XpGH7qWp8iqIFFolVILHn2yudWXJne9QWyQu+lzDp+ksQ=="
},
"source-map": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz",
"integrity": "sha1-n3BNDWnZ4TioG63267T94z0VHGE=",
"requires": {
"amdefine": "1.0.1"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
"requires": {
"readable-stream": "1.0.34",
"xtend": "4.0.1"
},
"dependencies": {
"readable-stream": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "0.0.1",
"string_decoder": "0.10.31"
}
}
}
},
"tweetnacl": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz",
"integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins="
},
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
},
"underscore": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz",
"integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ="
},
"unreachable-branch-transform": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unreachable-branch-transform/-/unreachable-branch-transform-0.3.0.tgz",
"integrity": "sha1-2ZzExudG0mSSiEW2EdtUsPNHTKo=",
"requires": {
"esmangle-evaluator": "1.0.1",
"recast": "0.10.43",
"through2": "0.6.5"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"optional": true
},
"ws": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz",
"integrity": "sha512-t+WGpsNxhMR4v6EClXS8r8km5ZljKJzyGhJf7goJz9k5Ye3+b5Bvno5rjqPuIBn5mnn5GBb7o8IrIWHxX1qOLQ==",
"requires": {
"async-limiter": "1.0.0",
"safe-buffer": "5.1.1",
"ultron": "1.1.1"
}
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
}
}
}

26
core/package.json Normal file
View file

@ -0,0 +1,26 @@
{
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@types/node": "8.9.1",
"camo": "git+https://github.com/benji7425/camo.git#v0.12.4",
"cron": "1.3.0",
"discord.js": "11.2.0",
"nedb": "1.8.0",
"parent-package-json": "2.0.1",
"require-all": "2.2.0",
"simple-file-writer": "2.0.0"
},
"name": "discord-bot-core",
"repository": {
"type": "git",
"url": "git+https://github.com/benji7425/discord-bot-core.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/benji7425/discord-bot-core/issues"
},
"homepage": "https://github.com/benji7425/discord-bot-core#readme",
"description": "Core code shared amongst my Discord bots"
}

74
core/util.js Normal file
View file

@ -0,0 +1,74 @@
// @ts-ignore
const InternalConfig = require("./internal-config.json");
const Console = require("console");
const SimpleFileWriter = require("simple-file-writer");
const logWriter = new SimpleFileWriter("./console.log");
const debugLogWriter = new SimpleFileWriter("./debug.log");
function ask(client, textChannel, member, question) {
//return a promise which will resolve once the user next sends a message in this textChannel
return new Promise((resolve, reject) => {
const cancelAsk = () => {
client.removeListener("message", handler);
textChannel.send("Response to question timed out");
};
const askTimeout = setTimeout(cancelAsk, InternalConfig.askTimeout);
const handler = responseMessage => {
if (responseMessage.channel.id === textChannel.id && responseMessage.member && responseMessage.member.id === member.id) {
clearTimeout(askTimeout);
resolve(responseMessage);
}
};
client.on("message", handler);
textChannel.send(member.toString() + " " + question).catch(reject);
});
}
function dateLog(...args) {
doDateLog(Console.log, logWriter, args, "INFO");
}
function dateError(...args) {
doDateLog(Console.error, logWriter, args, "ERROR");
}
function dateDebugError(...args) {
doDateLog(null, null, args, "DEBUG ERROR");
}
function dateDebug(...args) {
doDateLog(null, null, args, "DEBUG");
}
function doDateLog(consoleMethod, fileWriter, args, prefix = "") {
args = formatArgs([`[${prefix}]`].concat(args));
if (consoleMethod !== null)
consoleMethod.apply(this, args);
if (fileWriter !== null)
fileWriter.write(formatArgsForFile(args));
debugLogWriter.write(formatArgsForFile(args));
}
function formatArgs(args) {
return [`[${new Date().toUTCString()}]`].concat(args);
}
function formatArgsForFile(args) {
return args.join(" ") + "\n";
}
module.exports = {
dateError,
dateLog,
dateDebug,
dateDebugError,
ask
};

1329
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,28 +1,31 @@
{
"version": "3.0.0-b2",
"main": "app/index.js",
"scripts": {
"start": "node bootstrap.js"
},
"dependencies": {
"discord.js": "11.1.0",
"discordjs-util": "git+https://github.com/benji7425/discordjs-util.git",
"feed-read": "0.0.1",
"get-urls": "7.0.0",
"jsonfile": "3.0.1",
"shortid": "2.2.8"
},
"name": "discord-bot-rss-feed",
"devDependencies": {},
"repository": {
"type": "git",
"url": "git+https://github.com/benji7425/discord-bot-rss-feed.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/benji7425/discord-bot-rss-feed/issues"
},
"homepage": "https://github.com/benji7425/discord-bot-rss-feed#readme",
"description": ""
"version": "3.5.2",
"main": "app/index.js",
"scripts": {
"postinstall": "cd ./core && npm install",
"start": "node ./app/index.js --name=rss-feed"
},
"dependencies": {
"@types/node": "9.3.0",
"discord.js": "11.2.0",
"eslint": "4.19.1",
"get-urls": "7.0.0",
"jsonfile": "3.0.1",
"rss-parser": "2.12.0",
"shortid": "2.2.8",
"html-to-text": "3.3.0"
},
"name": "discord-bot-rss-feed",
"devDependencies": {},
"repository": {
"type": "git",
"url": "git+https://github.com/benji7425/discord-bot-rss-feed.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/benji7425/discord-bot-rss-feed/issues"
},
"homepage": "https://github.com/benji7425/discord-bot-rss-feed#readme",
"description": ""
}