Compare commits

...

291 Commits

Author SHA1 Message Date
lamp ab43d009b0 masto auto reconnect stream 2022-07-18 13:02:23 -07:00
lamp b18c90996e fix 2022-07-17 22:21:01 -07:00
lamp 1f4dec517f masto bridge v1 2022-07-17 22:17:24 -07:00
lamp 1704537a13 fix missing eval emoji 2022-07-17 21:28:15 -07:00
lamp 69c5a106b5 2022-07-17 21:27:40 -07:00
lamp a2966b1475 fix [object Object] 2022-07-17 21:26:54 -07:00
lamp d04200742d fix undefined unhandled rejection 2022-07-17 21:24:35 -07:00
lamp fbb082fee8 init masto stream (testing) 2022-07-17 21:21:13 -07:00
lamp bb80d22568 2022-07-17 21:07:05 -07:00
lamp 721435f039 icon thing 2022-05-20 19:15:30 -07:00
lamp e85d88de69 delete masto 2022-05-20 19:13:11 -07:00
lamp a4730289a0 fuk u type explicicy 2022-05-10 22:21:10 -07:00
lamp 02be479a15 fix size options 2022-05-10 22:18:38 -07:00
lamp 1b2df7a1cb fix formatting break embed 2022-05-10 14:20:26 -07:00
lamp 7eb01dda9d command to get emoji url 2022-05-10 14:03:15 -07:00
lamp c130ef1506 fix bug 2022-05-08 00:13:50 -07:00
lamp 660234acfd delete archive command and permissions set 2022-05-07 22:36:08 -07:00
lamp c0470e89b6 mastodon pixiv bot 2022-05-07 22:32:09 -07:00
lamp 823c398a5a disable verification 2022-04-11 22:58:36 -07:00
lamp 9b84e4ff7c delay the welcome message 2022-04-06 01:52:04 -07:00
lamp e19f11acae command to change server icon 2022-04-06 01:25:03 -07:00
lamp 0fcd5f125c rm vrchat 2022-04-06 01:22:30 -07:00
lamp 1316460838 vrchat command only 2022-03-31 17:37:49 -07:00
lamp ed76ad6044 small refactor 2022-03-31 17:33:48 -07:00
lamp c0036e7471 fix 2022-03-31 17:28:01 -07:00
lamp 55812d6422 ok.. 2022-03-31 17:04:51 -07:00
lamp 93b40700e0 vrc user monitor 2022-03-31 17:01:08 -07:00
lamp 345e368faa fix 2022-03-31 13:23:12 -07:00
lamp 523f057ea3 enable pinging deactivated members by role 2022-03-31 13:20:46 -07:00
lamp a0a9383d32 undot am pm 2022-03-31 12:27:54 -07:00
lamp 06685d0ad4 phlag 2022-03-19 12:39:35 -07:00
lamp 17d295043f welcome message 2022-03-14 16:43:54 -05:00
lamp e069b80a1d regular pin 2022-03-08 14:23:09 -06:00
lamp a016217a06 update channel ids 2022-03-08 14:13:47 -06:00
lamp 6dcd1b2665 fking discord 2022-01-18 16:26:16 -06:00
lamp 6f369ee441 :sGrimace:
also allow removing role icon
2022-01-13 19:28:15 -08:00
lamp 79611c34ae update discord.js 2022-01-13 19:22:06 -08:00
lamp bec6a886b1 /setbanner 2022-01-13 19:14:04 -08:00
lamp 0cd23ff738 Merge branch 'master' of gitea.moe:lamp/lampdiscordbot 2022-01-10 14:05:01 -08:00
lamp ba8d2f5cb9 fix detection url abuse 2022-01-10 14:04:57 -08:00
lamp fdbf05b846 fix t %% 2022-01-03 21:36:02 -06:00
lamp 25ec6a1906 rename tr to tolang 2022-01-03 16:13:48 -08:00
lamp f73217e282 normalization broke other lang 2022-01-03 16:01:37 -08:00
lamp e0122e5365 fix 2022-01-03 15:56:33 -08:00
lamp 7ccfe95b33 show detected lang if no flag 2022-01-03 15:51:46 -08:00
lamp eb48b90c96 rename to to tr because it can't be used without clicking 2022-01-03 15:44:18 -08:00
lamp f62d629b1f bruh 2022-01-03 15:37:32 -08:00
lamp 2772a16525 d 2022-01-03 15:34:22 -08:00
lamp 502cffbf06 flags 2022-01-03 15:23:54 -08:00
lamp 8fde14112b wrong key :sGrimace: 2022-01-03 14:37:48 -08:00
lamp dd159fa854 max 25 options 2022-01-03 14:34:26 -08:00
lamp dec7d3a50a add /to 2021-12-31 21:25:51 -08:00
lamp 978e08b713 bruh
also update .gitignore
%%
2021-12-23 10:40:25 -08:00
lamp fd9cc47836 un-simplify 2021-12-23 00:27:04 -08:00
lamp 75fa8fce66 bruh 2021-12-22 21:25:51 -08:00
lamp 51691595ce simplified 2021-12-22 21:24:45 -08:00
lamp 3f64f2e8e5 aaaa api message order is reversed 2021-12-22 21:09:23 -08:00
lamp 8db44d917c bug 2021-12-22 20:57:27 -08:00
lamp bb66625541 i test backup.js %% 2021-12-22 20:44:24 -08:00
lamp 81a73d519f add voice deps 2021-12-21 22:57:27 -08:00
lamp b44a3c482e fix bug 2021-12-21 22:48:54 -08:00
lamp b02ac22ab7 incl. t of j %% 2021-12-21 20:31:32 -08:00
lamp bfd9f8be0d not dupe join but handle delete 2021-12-21 20:19:24 -08:00
lamp 54840a409a delete pixiv proxy 2021-12-03 20:29:13 -08:00
lamp a4cbd51dd6 wrong domain drrr 2021-12-03 20:11:01 -08:00
lamp a215a981aa use cloudflare worker pixiv proxy 2021-12-03 20:09:00 -08:00
lamp af43453a84 count cmd 2021-12-03 15:24:54 -08:00
lamp 732a9c1ee7 巡音ルカ%% 2021-12-03 13:49:19 -08:00
lamp 32cc7389e3 save deleted emojis %% 2021-12-03 00:46:23 -08:00
lamp 13fb466144 make pin quote things use attached avatar now that it's possible 2021-12-03 00:39:31 -08:00
lamp 606aa4b72f /avatar user default self 2021-12-03 00:31:42 -08:00
lamp c788a1ff04 wrong user drr 2021-12-03 00:26:55 -08:00
lamp 4fe8f05ce7 f&c 2021-12-03 00:26:05 -08:00
lamp 16a4c78441 avatar command 2021-12-03 00:17:25 -08:00
lamp bc12b7aff8 not ephemeral /archive reply %% 2021-12-02 12:13:54 -08:00
lamp ec6e6e0f60 thing for access archived channls 2021-12-02 12:11:29 -08:00
lamp 028395b9b2 t 2021-12-02 11:59:57 -08:00
lamp 4821faef3b disable message on reactivation 2021-12-02 11:51:53 -08:00
lamp ae1eb37784 Merge branch 'master' of gitea.moe:lamp/lampdiscordbot 2021-12-02 11:49:09 -08:00
lamp 776b6b7b3e delete kanji game 2021-12-02 11:46:44 -08:00
lamp 0e48ee306f delete madlibs 2021-12-02 11:46:27 -08:00
lamp 6f285c730a delete unused magicchannel.js 2021-12-02 11:43:49 -08:00
lamp dbe7bba3fe move msg send out of deactivateMember() 2021-11-19 16:00:21 -06:00
lamp 03378d23df OOP 2021-11-18 17:45:43 -08:00
lamp ba38b60d4e include title in pixiv embed 2021-11-18 17:44:25 -08:00
lamp 5bd4b3da19 ASDF 2021-10-30 13:34:29 -07:00
lamp ecbdfae381 asdfdfghuidfghuisdfg 2021-10-30 13:30:21 -07:00
lamp 2d4426fb5a hmm scope 2021-10-30 13:19:49 -07:00
lamp 71768f7b19 more pixiv subscriptions 2021-10-30 13:14:02 -07:00
lamp 8345cb60f6 fix 2021-10-20 20:56:13 -07:00
lamp fdc52f6a5f systemd auto restart 2021-10-20 20:38:25 -07:00
lamp 3a705d7024 bruh 2021-10-20 20:36:17 -07:00
lamp 39f7dc147c subscribe to pixiv miku 2021-10-20 20:34:06 -07:00
Lamp f8f6844924 fix typo 2021-10-11 15:15:00 -07:00
Lamp 5522d0f81e i stop using docker
%%
2021-10-11 15:09:14 -07:00
lamp 8a9d9b8f15 stupid 2021-10-10 23:05:56 -07:00
lamp 2e1e19bd55 fix path 2021-10-10 23:03:08 -07:00
lamp 493d260d44 "finish" madlibs 2021-10-10 23:01:40 -07:00
lamp 75f455e27f fix command 2021-10-10 22:49:03 -07:00
lamp 7818dd69b1 Required cannot be configured for this type of option 2021-10-10 22:43:35 -07:00
lamp c59b2f88c8 AAAAAAAAAAAAAAAA 2021-10-10 22:39:03 -07:00
lamp 472bee74d6 oops 2021-10-10 22:37:42 -07:00
lamp ae9d4b6517 wip madlibs 2021-10-10 22:37:06 -07:00
lamp cc846ac132 fix and thing 2021-10-10 22:07:15 -07:00
lamp 53f327acdc wip madlibs 2021-10-10 21:28:15 -07:00
lamp 5d6dcbf8c1 add idk 2021-10-10 20:18:45 -07:00
lamp 82d55023b4 fix 2021-10-10 20:10:13 -07:00
lamp 2d9bd9d717 disable kanji game and 2021-10-10 20:04:36 -07:00
lamp 881bd240c0 change format and fix bug 2021-10-10 19:59:58 -07:00
lamp bf532fe639 fix 2021-10-10 19:53:52 -07:00
lamp c21ca1bc81 fix 2021-10-10 19:51:55 -07:00
lamp 430a6b6584 vocabulary game 2021-10-10 19:49:14 -07:00
lamp c7d490334e plug hole
ブーイさんありがとう
2021-10-10 12:03:01 -07:00
lamp e1d5140b28 update pixiv regex 2021-10-05 13:03:22 -07:00
lamp 28fcdf2dc7 change activity timeout to 72 hours 2021-10-05 12:43:43 -07:00
lamp 0fc7ae09df say when reactivate 2021-09-29 15:48:03 -07:00
lamp 1a741833bc FIX!!!! 2021-09-29 15:43:16 -07:00
lamp 69e64d6422 fix 2021-09-29 15:31:59 -07:00
lamp c68e12d965 fix 2021-09-29 15:20:26 -07:00
lamp bb9349bd1a AAA ignore bot 2021-09-29 15:03:03 -07:00
lamp ec51b5d5ec The "data" argument must be of type string or an instance of Buffer, TypedArray, or Da
taView. Received type number
2021-09-29 14:58:24 -07:00
lamp e73bd3af92 fak bug 2021-09-29 14:57:25 -07:00
lamp 171bc65bf4 activitytracker is ready? 2021-09-29 14:56:36 -07:00
lamp 9dd975cf89 ashfuguisdfhglisdhfg wip 2021-09-29 13:38:26 -07:00
lamp 4dc8fb19fb datastore, url reset 2021-09-29 12:38:37 -07:00
lamp bcfd056790 t 2021-09-29 11:55:07 -07:00
lamp 170bb431f5 fix and 2021-09-29 11:44:04 -07:00
lamp 1188883f20 Merge branch 'master' of gitea.moe:lamp/lampdiscordbot 2021-09-29 11:39:01 -07:00
lamp 4fea681a5f magicchannel1 2021-09-29 11:38:46 -07:00
lamp 513a9f76aa fix bug 2021-09-29 02:27:01 -05:00
lamp 5445802fe1 add settitle, make setcolor not ephemeral 2021-09-28 22:58:40 -07:00
lamp 6ddae9982f fix 2021-09-28 22:44:31 -07:00
lamp 2e1e7b2b97 support unicode 2021-09-28 22:39:19 -07:00
lamp 8fa3f489b2 seticon command 2021-09-28 22:23:25 -07:00
lamp d9ae24c8c1 use bleeding edge discord.js pr for role icons that aint even merged yet 2021-09-28 21:38:42 -07:00
lamp 09cb02c622 durr 2021-09-24 20:04:19 -07:00
lamp 4fbde804e2 make translate global command 2021-09-24 20:02:47 -07:00
lamp a5b2280d95 case-insensitive reverse 2021-09-24 19:50:28 -07:00
lamp 8fd6f072ac fix 2021-09-24 19:47:14 -07:00
lamp dd46202817 fix bug 2021-09-24 19:43:14 -07:00
lamp dedfc1e59a hmm 2021-09-24 19:41:12 -07:00
lamp 67fa789c37 separate reverse translation, and romaji for it 2021-09-24 19:39:10 -07:00
lamp cb6134ce35 no edit if not different 2021-09-24 19:28:17 -07:00
lamp eac4015e5e reverse translation 2021-09-24 19:14:49 -07:00
lamp e96e97c846 aasdasdfasdfasdfasf 2021-09-20 15:23:31 -07:00
lamp befc8352f4 pixiv embedder ignore bot 2021-09-20 15:21:22 -07:00
lamp a8f8834095 fix 2021-09-20 13:59:39 -07:00
lamp 94920c469b fukin m bot 2021-09-19 22:02:38 -07:00
lamp 93aeb20fe1 FUCK THIS SHIT 2021-09-19 21:52:52 -07:00
lamp a8d8fafcc6 FUUCK 2021-09-19 21:48:45 -07:00
lamp d3a04a0304 fix 2021-09-19 21:44:13 -07:00
lamp 5b7d8ecdc5 fix 2021-09-19 21:38:00 -07:00
lamp 6909b6fe45 wtf wher fluffy bols go 2021-09-19 21:32:09 -07:00
lamp 6e200cf3af asdf 2021-09-19 21:28:17 -07:00
lamp d732ef2c1b asd 2021-09-19 21:26:08 -07:00
lamp 272a3503a0 Hmm 2021-09-19 21:24:48 -07:00
lamp d7ef17724d custom color 2021-09-19 21:23:17 -07:00
lamp 8d1384cd33 asdfuihasiudfhiuasdhgiusahdlskgd 2021-09-19 20:16:46 -07:00
lamp d225fae91d a 2021-09-19 20:15:55 -07:00
lamp c2c14b461f ASFJGUSADUFISHADFI 2021-09-19 20:12:14 -07:00
lamp 52543c40c1 asd 2021-09-19 20:07:57 -07:00
lamp dd63afbf4c try same command for context menu 2021-09-19 20:07:05 -07:00
lamp d8354cd2de sdfgusdfguilhsdifhgu 2021-09-19 17:42:28 -07:00
lamp 30ec46ff75 asiodfgjio;sdfgiosdgidfg 2021-09-19 17:34:38 -07:00
lamp 9e210dcc09 command to steal emoji 2021-09-19 17:31:52 -07:00
lamp 20d8b65534 make third button blue 2021-09-19 16:51:29 -07:00
lamp f415202f28 adfuigiausldfhliusadfguis %% 2021-09-19 16:49:17 -07:00
lamp ecbb7156a2 i forgot button types 2021-09-19 16:47:22 -07:00
lamp dc0ead189d wait lets allow unvoting also fix 2021-09-19 16:45:34 -07:00
lamp cce2db6a71 fix 2021-09-19 16:42:32 -07:00
lamp 9640abd7bb button thing 2021-09-19 16:41:00 -07:00
lamp dbfdd6525a agaga BaseCommandInteraction not exported in stable yet 2021-09-19 15:37:40 -07:00
lamp 047bdb98da BaseCommandInteraction 2021-09-19 15:19:53 -07:00
lamp f18c7e8b11 oh 2021-09-19 15:12:16 -07:00
lamp 7567c9b98f asdfuasdfuasdfuasdhuashdgusdfghuisdfg 2021-09-19 14:13:45 -07:00
lamp 70f1eeaa03 a 2021-09-17 12:33:30 -07:00
lamp e3a0260e61 oh 2021-09-17 12:27:02 -07:00
lamp 5e29c0422b a 2021-09-17 12:25:48 -07:00
lamp 6230f9f0d1 context menu archive command 2021-09-16 23:47:38 -07:00
lamp bcd51de025 fix bug with dm 2021-09-16 00:02:32 -07:00
lamp 218c9f22e5 mi attachment 2021-09-15 22:49:41 -07:00
lamp 5a94678f8d ki 2021-09-15 22:42:37 -07:00
lamp 4723ef657c mi 2021-09-15 22:29:53 -07:00
lamp 785259166e change clock to hours only because there is a rate limit 2021-09-15 21:40:03 -07:00
lamp 573705066f wait durrr 2021-09-15 20:29:19 -07:00
lamp a2ac1de7c8 hack 2021-09-15 20:28:40 -07:00
lamp 7350f2f7b9 FIX 2021-09-15 20:14:32 -07:00
lamp dbc65a006c world clock 2021-09-15 20:13:47 -07:00
lamp 9ecc7d4d29 without content it just says sending forever 2021-09-15 19:01:50 -07:00
lamp e41db72c22 ashudif 2021-09-15 18:37:39 -07:00
lamp 67e45f3bac finish archive cmd 2021-09-15 18:35:20 -07:00
lamp 6a2d8b4eda move ?. 2021-09-15 18:30:30 -07:00
lamp dc604ff4a9 fix! 2021-09-15 18:27:37 -07:00
lamp a39dfb7d6e fix? 2021-09-15 18:26:29 -07:00
lamp 351dcee051 update launch.json 2021-09-15 18:21:29 -07:00
lamp ad014ffc39 fix 2021-09-15 18:19:15 -07:00
lamp e5c2a4aad9 filter commands with permissions 2021-09-15 18:17:40 -07:00
lamp e198b6b9cd command permissions 2021-09-15 18:16:07 -07:00
lamp a5ffb8c7ac test, wip 2021-09-15 18:04:49 -07:00
lamp 6371dc8b84 test 2021-09-15 16:32:04 -07:00
lamp 0b2611bf3d %%%%%%% 2021-09-15 16:13:04 -07:00
lamp c6e984e411 delete translate1 2021-09-15 16:12:30 -07:00
lamp 1a37e13aa9 fix 2021-09-15 15:48:28 -07:00
lamp 46f94fe075 fix line break 2021-09-15 15:45:06 -07:00
lamp 752ce397de have to hard reset to origin/master explicitly 2021-09-15 15:42:58 -07:00
lamp fbfc614dc9 romaji for input 2021-09-15 15:42:06 -07:00
lamp d04de003d3 hard reset to origin 2021-09-15 15:27:55 -07:00
lamp 51952c4dfe fix grouping 2021-09-15 15:25:40 -07:00
lamp a559a55abd use git hard reset 2021-09-15 15:24:29 -07:00
lamp 5cb2d91873 romaji 2021-09-15 15:23:29 -07:00
lamp c3e880cc0a fix 2021-09-15 14:47:27 -07:00
lamp 67b42021c7 translate2 2021-09-15 14:43:01 -07:00
lamp f3659e07b0 fix 2021-09-15 14:19:13 -07:00
lamp d792487489 refactor %% 2021-09-15 14:09:10 -07:00
lamp 77abdd9d0f fix 2021-09-11 23:21:54 -07:00
lamp 971b3d0e8f gah 2021-09-11 23:18:59 -07:00
lamp 0609867fc0 fix 2021-09-11 23:12:19 -07:00
lamp 93c0ee7f21 tranchan 2021-09-11 23:10:30 -07:00
lamp e950e31a99 m 2021-09-03 23:57:22 -07:00
lamp 9f9647cfe7 a 2021-09-03 23:43:56 -07:00
lamp 2ebd4b3208 a 2021-09-03 23:40:10 -07:00
lamp 267427cdf6 kanji game 2021-09-03 23:37:42 -07:00
lamp faff65eb82 AAAAAAAAAAAA fix bug 2021-09-03 22:48:20 -07:00
lamp 2b483c3fda pixiv embedder send typing 2021-09-03 15:42:00 -07:00
lamp 1c7b992464 FUCC 2021-08-26 21:22:38 -07:00
lamp 11e6130148 miku defer reply 2021-08-26 21:18:13 -07:00
lamp fc54fdcf33 can pls not commit suicide on unhandled rejection 2021-08-26 21:04:45 -07:00
lamp fa7770ea44 refactor pixiv-proxy for slash command 2021-08-26 20:58:24 -07:00
lamp 712bc0933a d 2021-08-26 19:34:27 -07:00
lamp 574990c9ed owo slash command 2021-08-26 19:11:18 -07:00
lamp c5ef41c5ca FUC 2021-08-26 19:03:26 -07:00
lamp 1ed4d70e89 slash commands without REST 2021-08-26 19:02:43 -07:00
lamp 82a262c2b7 application id in conf 2021-08-26 18:37:40 -07:00
lamp 02796cf10f experimental slash commands 2021-08-26 18:35:42 -07:00
lamp 35701510fa auto thread on announcements 2021-08-26 16:31:45 -07:00
lamp 0626be1ec3 spoiler only in non-nsfw 2021-08-26 14:02:03 -07:00
lamp 56bdca8c21 !miku include url 2021-08-26 14:00:16 -07:00
lamp 491af971dc fix 2021-08-24 22:06:14 -07:00
lamp 6bfb2f028f miku hack 2021-08-24 22:03:22 -07:00
lamp 453aa99f7d oops bug 2021-08-23 22:17:59 -07:00
lamp 426e30bb9b spoiler r18 2021-08-23 22:09:32 -07:00
lamp 105884e862 edit string 2021-08-23 21:47:02 -07:00
lamp 5363f91d2b make it even more complicated
include url if message had more than one url, include note if illust is an animation
2021-08-23 21:42:00 -07:00
lamp be78ea71c6 fix to-cache error and handle >2000 2021-08-23 21:08:09 -07:00
lamp 397454468b fuqq 2021-08-23 20:47:39 -07:00
lamp 09fd78bd79 no auto update if DOES include thing because i keep forgetting
!@
2021-08-23 20:44:44 -07:00
lamp bb4049ac5e somehow had some undefined image data 2021-08-23 20:43:15 -07:00
lamp 0eee329d3a fix bad await causing super misleading runtime syntaxerror !@ 2021-08-23 19:51:16 -07:00
lamp 3b8270e9a7 !@ 2021-08-23 19:18:32 -07:00
lamp f5ba580eb1 optimize
save data already downloaded so proxy doesnt have to download it again
2021-08-23 19:17:47 -07:00
lamp ace5721457 fix 2021-08-23 18:54:53 -07:00
lamp 72891fc374 try upload pixiv images to discord, use pixiv proxy if too large
because pixiv cache using a lot of my disk
2021-08-23 18:40:34 -07:00
lamp 348ee8ea2a revert pixiv-embedded to using html because ajax not work on R-18
infer all "page" urls based on pageCount

!@
2021-08-23 17:08:14 -07:00
lamp 47d33f6667 commit wip before reverse plan 2021-08-23 16:53:38 -07:00
lamp ce435d01a1 oops !@ 2021-08-23 15:43:52 -07:00
lamp 71031af2ce extra debug !@ 2021-08-23 15:40:40 -07:00
lamp 684c6b2377 REMOVE ignored files from git
grrrr
2021-08-23 15:30:18 -07:00
lamp 894e0bfab8 ignore data dir 2021-08-23 15:27:08 -07:00
lamp 38b2331eb6 better updater error message 2021-08-23 15:25:11 -07:00
lamp ba5e53e4ff use pixiv ajax with post id instead of parsing html; embed all artwork urls !@ 2021-08-23 15:23:28 -07:00
lamp bc90f41268 gitkeep data/avatars 2021-08-21 19:10:27 -07:00
lamp 097d186f58 avatar server in app 2021-08-21 19:09:08 -07:00
lamp cf3adae647 dockerfile volume dont persist rebuilds 2021-08-21 19:00:52 -07:00
lamp 6926e6c7e5 dockerfile volume statement is relative of / not of workdir 2021-08-21 18:47:19 -07:00
lamp 2c166ecdb2 mistake again 2021-08-21 18:32:34 -07:00
lamp ebbaec9e0e filter querystring !@ 2021-08-21 18:32:05 -07:00
lamp 53db080d92 wrong name 2021-08-21 18:24:57 -07:00
lamp 0b989fb317 pixiv proxy 2021-08-21 18:18:31 -07:00
lamp c3c1a39227 make auto update only if commit message contains !@ 2021-08-21 17:59:09 -07:00
lamp abaf60e259 forgot to end the request 2021-08-21 15:00:37 -07:00
lamp 7bc66164f4 fix updater 2021-08-21 14:56:06 -07:00
lamp 1f05770a2d fix docker networking 2021-08-21 14:45:33 -07:00
lamp ff3fb6756c oops 2021-08-21 14:34:47 -07:00
lamp 9548ff3a54 add web server and update webhook 2021-08-21 14:32:49 -07:00
lamp e4ecdfb84f Update 'pixiv-embedder.js' 2021-08-21 15:38:56 -05:00
lamp 70ef295b3b enable pixiv embed in any channel 2021-08-21 15:00:38 -05:00
lamp 9ae9db12a2 update embed syntax 2021-08-20 00:01:57 -05:00
lamp 5deb5935c7 suppress embed again after update 2021-08-19 18:38:40 -07:00
lamp 17e2e0a18b preserve pixiv filename 2021-08-19 18:17:44 -07:00
lamp 43efb787f8 fix dum 2021-08-19 18:12:33 -07:00
lamp 0cb95e2b0a typo 2021-08-19 18:02:47 -07:00
lamp 43d19d0808 Add pixiv embedder
not tested
2021-08-19 17:59:53 -07:00
lamp 9fe5943675 fucking bigint 2021-08-17 21:14:05 -07:00
lamp 6cfb2fdedb docker build no cache 2021-08-17 21:05:12 -07:00
lamp 14ec1867d5 fix split 2021-08-17 21:03:59 -07:00
lamp 7ff1e84f21 add join/leave 2021-08-17 20:49:45 -07:00
lamp 083095e636 fix role create 2021-08-17 20:32:07 -07:00
lamp d147167682 v13 2021-08-16 16:29:58 -07:00
lamp f82bce62ff improve owo 2021-08-16 16:14:38 -07:00
lamp 417e582fa7 FYC REGEX
added owo cmd
2021-08-16 16:05:51 -07:00
lamp 0dfd5d4f94 make case insensitive 2021-08-16 15:10:58 -07:00
32 changed files with 3276 additions and 242 deletions
-2
View File
@@ -1,2 +0,0 @@
node_modules
secrets.env
+2
View File
@@ -1,2 +1,4 @@
node_modules node_modules
secrets.env secrets.env
data
tokens.txt
+2 -1
View File
@@ -11,7 +11,8 @@
"skipFiles": [ "skipFiles": [
"<node_internals>/**" "<node_internals>/**"
], ],
"program": "${workspaceFolder}\\main.js" "program": "${workspaceFolder}\\index.js",
"envFile": "${workspaceFolder}\\secrets.env"
} }
] ]
} }
-5
View File
@@ -1,5 +0,0 @@
FROM node:latest
ADD . /app
WORKDIR /app
RUN npm ci
CMD ["node", "main.js"]
+116
View File
@@ -0,0 +1,116 @@
var client = require("./client");
var config = require("./config");
var app = require("./www");
var DataStore = require("./datastore");
var ds = new DataStore("activity");
app.get("/detect/:code", (req, res) => {
res.sendFile(process.cwd() + "/track-image.png");
if (req.headers["user-agent"].includes("Discordbot")) return;
onActivity(ds.get(req.params.code));
ds.del(req.params.code);
});
client.on("messageCreate", async m => m.guildId == config.guild && onActivity(m.author.id));
client.on("interactionCreate", async i => i.guildId == config.guild && onActivity(i.user.id));
client.on("typingStart", async t => t.guild?.id == config.guild && onActivity(t.user.id));
client.on("guildMemberAdd", async m => m.guild.id == config.guild && onActivity(m.user.id));
client.on("messageReactionAdd", async (r, user) => r.message?.guild?.id == config.guild && onActivity(user.id));
client.on("messageReactionRemove", async (r, user) => r.message?.guild?.id == config.guild && onActivity(user.id));
client.on("messageUpdate", async (oldMessage, newMessage) => newMessage.guild?.id == config.guild && (oldMessage.editedAt != newMessage.editedAt) && onActivity(newMessage.author.id));
async function onActivity(user_id) {
if (!user_id) return;
let user = client.users.resolve(user_id);
if (!user || user.bot) return;
ds.put(user_id, Date.now());
if (ds.get(user_id + "deactivated")) {
let member = client.guilds.resolve(config.guild).members.resolve(user_id);
await reactivateMember(member);
/*await client.channels.resolve(config.default_channel)?.send(random([
`${member.displayName} bacc`,
`${member.displayName} is bacc`,
`hi ${member.displayName}`
]));*/
}
}
module.exports.interval = setInterval(async () => {
var guild = client.guilds.resolve(config.guild);
if (!guild) return;
guild.members.cache.filter(m => !m.user.bot).forEach(member => {
let lastActivityTime = ds.get(member.user.id);
if (!lastActivityTime) return;
if (Date.now() - lastActivityTime > 1000*60*60*72) { // if last activity > 72 hours ago
if (!ds.get(member.id + "deactivated"))
deactivateMember(member);
}
});
}, 60*60*1000); // every hour i guess
async function deactivateMember(member) {
await member.roles.add(config.inactive_role);
ds.put(member.id + "deactivated");
ds.put(member.id, Date.now());
var magic_channel = client.channels.resolve(ds.get(member.id + "magicchannelid"));
if (!magic_channel) {
magic_channel = await member.guild.channels.create("inactive", {
permissionOverwrites: [
{
id: member.guild.roles.everyone,
deny: "VIEW_CHANNEL"
},
{
id: client.user,
allow: "VIEW_CHANNEL"
},
{
id: member,
allow: "VIEW_CHANNEL"
}
]
});
ds.put(member.id + "magicchannelid", magic_channel.id);
} else {
magic_channel.permissionOverwrites.edit(member, {"VIEW_CHANNEL": true});
}
var magic_channel_message_id = ds.get(member.id + "magicchannelmessage");
var unique_code = Math.random().toString();
ds.put(unique_code, member.id);
var content = `${config.base_uri}/detect/${unique_code}`;
if (!magic_channel_message_id) {
var magic_channel_message = await magic_channel.send({content});
ds.put(member.id + "magicchannelmessage", magic_channel_message.id)
} else {
await magic_channel.messages.edit(magic_channel_message_id, {content});
}
}
async function reactivateMember(member) {
await member.roles.remove(config.inactive_role);
ds.del(member.id + "deactivated");
var magic_channel = client.channels.resolve(ds.get(member.id + "magicchannelid"));
if (magic_channel) await magic_channel.permissionOverwrites.edit(member, {"VIEW_CHANNEL": false});
}
module.exports.deactivateMember = deactivateMember;
module.exports.reactivateMember = reactivateMember;
client.on("messageCreate", async message => {
if (message.guildId != config.guild) return;
let deactivatedMembersMentionedViaRoles = [...new Set(message.mentions.roles.flatMap(r => r.members).values())].filter(x => ds.get(x.id + "deactivated"));
if (deactivatedMembersMentionedViaRoles.length) {
for (let m of deactivatedMembersMentionedViaRoles) await reactivateMember(m);
await message.reply({content: deactivatedMembersMentionedViaRoles.map(String).join(' '), allowedMentions:{repliedUser: false}});
}
});
+47
View File
@@ -0,0 +1,47 @@
module.exports = class DiscordBackup {
constructor(guild) {
this.guild = guild;
this.data = {};
}
async backupGuild() {
// includes emojis, stickers, roles
this.data.guild = await this.guild.client.api.guilds(this.guild.id).get();
}
async backupMembers() {
this.data.members = await this.guild.client.api.guilds(this.guild.id).members.get({query: {limit: 1000}});
}
async backupChannel(channelId) {
var data = {
channel: await this.guild.client.api.channels[channelId].get(),
messages: []
};
this.data.channels ||= [];
this.data.channels.push(data);
do {
var messages = await this.guild.client.api.channels[channelId].messages.get({query: {
before: messages?.at(-1)?.id, limit: 100
}});
data.messages.push(...messages);
} while (messages.length > 0);
}
async backupEverything() {
await this.backupGuild();
await this.backupMembers();
for (let channelId of this.guild.channels.cache.keys()) {
try {
await this.backupChannel(channelId);
} catch (error) {
console.error(error.stack);
}
}
}
serialize() {
return JSON.stringify(this.data);
}
}
+77
View File
@@ -0,0 +1,77 @@
var client = require("./client");
var config = require("./config");
var fs = require("fs");
var data = fs.existsSync("data/buttonthing.json") ? JSON.parse(fs.readFileSync("data/buttonthing.json", "utf8")) : ({
userVoteMap: {},
votes: {
miku: 0,
teto: 0,
both: 0,
what: 0
}
});
function setVote(user, vote) {
var existingVote = data.userVoteMap[user];
if (vote == existingVote) {
data.votes[existingVote]--;
data.userVoteMap[user] = undefined;
} else {
if (existingVote) data.votes[existingVote]--;
data.votes[vote]++;
data.userVoteMap[user] = vote;
}
fs.writeFileSync("data/buttonthing.json", JSON.stringify(data));
}
var thing = () => ({
content: "Miku or Teto?",
components: [
{
type: "ACTION_ROW",
components: [
{
type: "BUTTON",
label: `Miku (${data.votes.miku})`,
customId: "miku",
style: "SUCCESS",
emoji: "<:MikuSquish:868670741518888961>"
},
{
type: "BUTTON",
label: `Teto (${data.votes.teto})`,
customId: "teto",
style: "DANGER",
emoji: "<:tetodrill2:705605869571801120>"
},
{
type: "BUTTON",
label: `both/idk (${data.votes.both})`,
customId: "both",
style: "PRIMARY",
emoji: "<:squee:707727925587345490>"
},
{
type: "BUTTON",
label: `what/idk (${data.votes.what})`,
customId: "what",
style: "SECONDARY",
emoji: "😕"
}
]
}
]
});
module.exports.init = function(channel = client.channels.resolve(config.announcement_channel)) {
channel.send(thing());
}
client.on("interactionCreate", i => {
if (!Object.keys(data.votes).includes(i.customId)) return;
setVote(i.user.id, i.customId);
i.update(thing());
});
+12
View File
@@ -0,0 +1,12 @@
var Discord = require("discord.js");
var config = require("./config");
var client = module.exports = new Discord.Client({
partials: ['MESSAGE','REACTION'],
intents: 32767 //all
});
client.login(config.token).then(async () => {
console.log("ready");
(await client.channels.fetch(config.bot_channel))?.send('a');
});
+139 -12
View File
@@ -1,33 +1,160 @@
var fetch = require("node-fetch");
var {getAverageColor} = require("fast-average-color-node");
var fs = require("fs");
var Discord = require("discord.js");
var client = require("./client");
var config = require("./config");
var commands = require("./commands");
function getColorRoleFor(user_id) {
try {
return client.guilds.resolve(config.guild)?.roles.fetch(
fs.readFileSync(config.data_dir + "color/" + user_id, "utf8")
);
} catch (e) {}
}
module.exports.getColorRoleFor = getColorRoleFor;
client.on("guildMemberAdd", async function (member) { client.on("guildMemberAdd", async function (member) {
member.roles.add(await member.guild.roles.create({data:{ if (member.guild.id != config.guild) return;
var role = await member.guild.roles.create({
name: member.user.username, name: member.user.username,
color: await user2color(member.user) || "#FF0000", color: await user2color(member.user) || "#FF0000",
mentionable: true, mentionable: true,
permissions: 0 permissions: 0n
}})); });
member.roles.add(role);
fs.writeFileSync(config.data_dir + "color/" + member.id, role.id);
}); });
client.on("userUpdate", async function (oldUser, user) { client.on("userUpdate", async function (oldUser, user) {
var colorRole = client.guilds.resolve(config.guild)?.members.resolve(user)?.roles.color; var colorRole = await getColorRoleFor(user.id);
if (!colorRole) return; if (!colorRole) return;
if (oldUser.username != user.username) await colorRole.setName(user.username); if (oldUser.username != user.username)
if (!fs.existsSync(`${config.data_dir}color/${user.id}_custom-name`))
await colorRole.setName(user.username);
if (oldUser.avatar != user.avatar) { if (oldUser.avatar != user.avatar) {
if (fs.existsSync(`${config.data_dir}color/${user.id}_custom`)) return;
let c = await user2color(user); let c = await user2color(user);
await colorRole.setColor(c); await colorRole.setColor(c);
if (!colorRole.color) {
console.warn("role color set fail:", colorRole.name, c);
await colorRole.setColor("#FF0000");
}
} }
}); });
client.on("guildMemberRemove", async function (member) { client.on("guildMemberRemove", async function (member) {
var colorRole = member.roles.color; if (member.guild.id != config.guild) return;
var colorRole = await getColorRoleFor(member.user.id);
if (!colorRole) return; if (!colorRole) return;
if (!colorRole.members.size) colorRole.delete(); if (!colorRole.members.size) colorRole.delete();
}); });
commands.push({
name: "setcolor",
description: "Set yourself to a custom color",
options: [
{
name: "color",
description: "Hex string or color name.",
type: "STRING",
required: true
}
],
exec: async i => {
var colorRole = await getColorRoleFor(i.user.id);
if (!colorRole) return void i.reply({content: "You don't have color role!"});
let x = i.options.getString("color");
if (x) {
// if (/^[a-zA-Z_]+$/.test(x))
x = x.toUpperCase();
// else if (!/^#?[a-fA-F0-9]{6}$/.test(x)) {
// let m = x.match(/(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
// if (m) x = [Number(x[1]), Number(x[2]), Number(x[3])];
// }
}
try {
await colorRole.setColor(x);
} catch(error) {
return void await i.reply({content: error.message});
}
fs.writeFileSync(`${config.data_dir}color/${i.user.id}_custom`, '');
await i.reply({content: colorRole.toString()});
}
});
commands.push({
name: "settitle",
description: "Change your color role name",
options: [
{
name: "name",
description: "Name of role",
type: "STRING",
required: true
}
],
exec: async i => {
var colorRole = await getColorRoleFor(i.user.id);
if (!colorRole) return void i.reply({content: "You don't have color role!"});
try {
await colorRole.setName(i.options.getString("name"));
} catch(error) {
await i.reply({content: error.message});
return;
}
fs.writeFileSync(`${config.data_dir}color/${i.user.id}_custom-name`, '');
await i.reply({content: colorRole.toString()});
}
});
commands.push({
name: "seticon",
description: "Set your role icon",
options: [
{
name: "icon",
description: "Image URL or an emoji",
type: "STRING"
}
],
exec: async i => {
await i.deferReply();
var colorRole = await getColorRoleFor(i.user.id);
if (!colorRole) return void i.editReply({content: "You don't have color role!"});
try {
let icon = i.options.getString("icon");
if (/^https?:\/\//i.test(icon)) {
await colorRole.setIcon(icon);
await i.editReply({files: [{
attachment: icon,
name: icon.match(/\/(\w*(?:\.png|\.jpg|\.jpeg|\.gif|\.webp))$/i)?.[1] || "icon.png"
}]});
} else if (icon) {
var emoji = Discord.Util.parseEmoji(icon);
if (emoji?.id) {
await colorRole.setIcon(i.client.rest.cdn.Emoji(emoji.id, emoji.animated ? 'gif' : 'png'));
} else {
await colorRole.setUnicodeEmoji(icon);
}
await i.editReply({content: icon});
} else {
await colorRole.setIcon(null);
await i.editReply({content: "icon removed"});
}
} catch (error) {
await i.editReply({content: error.message});
}
}
});
async function user2color(user) { async function user2color(user) {
var avatarURL = user.avatarURL({format:'png', size: 16}) || user.defaultAvatarURL; var avatarURL = user.avatarURL({format:'png', size: 16}) || user.defaultAvatarURL;
var image = await (await require("node-fetch")(avatarURL)).buffer(); var image = await (await fetch(avatarURL)).buffer();
return (await require("fast-average-color-node").getAverageColor(image)).value; return (await getAverageColor(image)).value;
} }
+212 -36
View File
@@ -1,44 +1,220 @@
client.on("message", async function (message) { var client = require("./client");
var config = require("./config");
var Discord = require("discord.js");
var BaseCommandInteraction = require("discord.js/src/structures/BaseCommandInteraction.js")
let match = message.content.match(/^!(.*?)(?: (.*))?$/i); var commands = module.exports = [
if (!match) return; {
name: "say",
let [content, cmd, query] = match; description: "test command",
let say = message.channel.send.bind(message.channel); options: [
{
switch (cmd) { name: "text",
case "ping": return void say("pong"); description: "text to say",
type: 3, // string
required: true
} }
],
exec: i => {
if (!message.member?.roles.cache.has(config.admin_role)) return; i.reply(i.options.getString("text") || "bruh");
}
if (message.content.startsWith("!>")) { },
with (message) { {
name: "owo",
description: "random owo",
options: [
{
name: "length",
description: "length of owo",
type: 4, // integer
required: false
}
],
exec: i => {
let owo = Math.round(Math.random()) ? 'O' : 'o';
let n = Math.min(i.options.getInteger("length") || 9, 1998);
for (let i = 0; i < n; i++) owo += ['o','w','O','W'][Math.floor(Math.random() * 4)];
owo += owo = Math.round(Math.random()) ? 'O' : 'o';
i.reply(owo);
}
},
{
name: "avatar",
description: "View a user's original avatar (and save permanently as attachment)",
options: [
{
name: "user",
description: "can i not leave some obvious descriptions blank?",
type: "USER"
}
],
exec: async i => {
var user = i.options.getUser("user") || i.user;
var au = user.avatarURL({size:4096, dynamic: true});
var an = au.split('/').pop(); an = an.substring(0, an.indexOf('?'));
i.reply({files: [{attachment: au, name: an}], embeds: [{
title: `Avatar for ${user.tag}`,
url: au,
image: {url: `attachment://${an}`},
color: (await require('./colors').getColorRoleFor(user.id)).color
}]});
}
},
{
name: "steal",
description: "Copy an emoji to this server",
options: [
{
name: "emoji",
description: "The emoji to steal",
type: "STRING",
required: true
},
{
name: "name",
description: "Optional rename of stolen emoji",
type: "STRING",
required: false
}
],
exec: async i => {
await i.deferReply();
try { try {
var x = await eval(message.content.substr(2).trim()); var input = i.options.getString("emoji") || (await i.channel.messages.fetch(i.targetId))?.content;
} catch(e) { var emoji = Discord.Util.parseEmoji(input);
var x = e.message; if (!emoji.id || !emoji.name) return void await i.editReply({content: `Invalid emoji input: ${input}`});
var url = client.rest.cdn.Emoji(emoji.id, emoji.animated ? 'gif' : 'png');
var emoji2 = await i.guild.emojis.create(url, i.options.getString("name") || emoji.name);
await i.editReply({content: emoji2.toString()});
} catch (error) {
await i.editReply({content: error.message});
} }
} }
if (typeof x == "undefined") return void await message.react(config.eval_undefined_emoji); },
let t = typeof x == 'string' ? 'txt' : 'js'; {
if (typeof x != 'string' && typeof x != "function") x = require('util').inspect(x, {depth: 1}); name: "Steal Emoji",
message.channel.send(`\`\`\`${t}\n${x}\`\`\``, {split:{maxLength:2000,prepend:`\`\`\`${t}\n`,append:'```'}}); type: "MESSAGE",
} exec: i => commands.find(x => x.name == "steal").exec(i)
},
else if (message.content.startsWith("!$")) { {
let cp = require("child_process").spawn("bash", ["-c", message.content.substr(2).trim()]); name: "setserverbanner",
cp.stdout.on("data", data => { description: "Set the server banner image",
message.channel.send(data.toString(), {split:{char:'\n',length:2000}}).catch(()=>{ options: [
message.channel.send(data.toString(), {split:{char:'',length:2000}}); {
}); name: "url",
}); description: "HTTP(S) URL to an image",
cp.stderr.on("data", data => { type: "STRING"
message.channel.send(data.toString(), {split:{char:'\n',length:2000}}).catch(()=>{
message.channel.send(data.toString(), {split:{char:'',length:2000}});
});
});
} }
],
exec: async i => {
var url = i.options.getString("url");
try {
if (!url) {
await i.guild.setBanner(null);
await i.reply("cleared the server banner");
} else {
if (/^https?:\/\//i.test(url)) {
await i.guild.setBanner(url);
await i.reply(url);
} else {
await i.reply("http image url only!");
}
}
} catch (error) {
await i.reply(error.message);
}
}
},
{
name: "setservericon",
description: "Change the server icon",
options: [
{
name: "url",
description: "HTTP(S) URL to an image",
type: "STRING"
}
],
exec: async i => {
var url = i.options.getString("url");
try {
if (!url) {
await i.guild.setIcon(null);
await i.reply("cleared the server icon");
} else {
if (/^https?:\/\//i.test(url)) {
await i.guild.setIcon(url);
await i.reply(url);
} else {
await i.reply("http image url only!");
}
}
} catch (error) {
await i.reply(error.message);
}
}
},
{
name: "getemoji",
description: "Generate a URL for an emoji",
options: [
{
name: "emoji",
description: "The emoji (code) or the name of the emoji (case-sensitive)",
type: "STRING",
required: true
},
{
name: "format",
description: "choose image format",
type: "STRING",
choices: [
{name: "PNG", value: "png"},
{name: "JPG", value: "jpg"},
{name: "WEBP", value: "webp"},
{name: "GIF", value: "gif"}
]
},
{
name: "size",
description: "choose image size",
type: "INTEGER",
choices: "16,20,22,24,28,32,40,44,48,56,60,64,80,96,100,128".split(',').map(s => ({name: s, value: Number(s)}))
}
],
exec: i => {
var emojiname = i.options.getString("emoji");
if (emojiname.startsWith('<') && emojiname.endsWith('>')) emoji = Discord.Util.parseEmoji(emojiname);
else {
if (emojiname.startsWith(':')) emojiname = emojiname.slice(1);
if (emojiname.endsWith(':')) emojiname = emojiname.slice(-1);
var emoji = client.emojis.cache.find(e => e.name == emojiname);
if (!emoji) emoji = client.emojis.cache.find(e => e.name.toLowerCase() == emojiname.toLowerCase());
if (!emoji) return void i.reply(`could not find emoji named ${emojiname}`);
}
if (!emoji.id) return void i.reply(`invalid input`);
var qs = [];
var size = i.options.getInteger("size");
if (size) qs.push(`size=${size}`);
var format = i.options.getString("format");
if (!format) format = emoji.animated ? "gif" : "png";
if (format == "gif" && !emoji.animated) return void i.reply(`Non-animated emoji is not available as GIF.`);
if (format == "webp") qs.push(`quality=lossless`);
var url = `https://media.discordapp.net/emojis/${emoji.id}.${format}`;
if (qs.length > 0) url += '?' + qs.join('&');
i.reply(`${emoji.name}.${format}\n${url}`);
}
}
];
client.on("interactionCreate", interaction => {
if (interaction instanceof BaseCommandInteraction)
commands.find(x => x.name == interaction.commandName)?.exec?.(interaction);
});
client.once("ready", async () => {
let global_commands = commands.filter(x => x.global);
let guild_commands = commands.filter(x => !x.global);
let guild = client.guilds.resolve(config.guild);
await guild.commands.set(guild_commands);
await client.application.commands.set(global_commands);
}); });
+80 -5
View File
@@ -1,13 +1,88 @@
module.exports = { module.exports = {
token: process.env.TOKEN, token: process.env.TOKEN,
secret: process.env.SECRET,
deepl_auth_key: process.env.DEEPL_KEY,
application_id: "707451582454824980",
guild: "672956423545815040", guild: "672956423545815040",
admin_role: "776899554603565116", admin_role: "776899554603565116",
human_role: "672956630962274306", human_role: "672956630962274306",
bot_role: "673671040010027034", bot_role: "673671040010027034",
eval_undefined_emoji: "707729833601531935", inactive_role: "892869309603389500",
verified_role: "949064806030254130",
view_archived_channels_role: "916056534402863125",
eval_undefined_emoji: "🅱️",
mi_emoji: "887931046086185060",
ki_emoji: "887935846710394910",
default_channel: "949831184957980722",
bot_channel: "949831221981097984",
archive_channel: "802280618636869663", archive_channel: "802280618636869663",
porn_channel: "835734868427669574", moe_channel: "871864787213111366",
avatar_cache_dir: "/srv/www/ldb/avatars/", porn_channel: "949831237927862333",
avatar_cache_url: "https://ldb.owo69.me/avatars/", announcement_channel: "876010629490683955",
miku_channel: "900583427483516938",
archive_category: "887838689533771776",
archive_portal_voice_channel: "916057450313023508",
data_dir: process.cwd() + "/data/",
base_uri: "https://ldb.owo69.me",
world_clock: [
{
flag: "🇺🇸",
timezone: "America/Los_Angeles",
channel: "887897732428226660"
},
{
flag: "🇺🇸",
timezone: "America/New_York",
channel: "888507872932143155"
},
{
flag: "🇩🇪",
timezone: "Europe/Berlin",
channel: "887897886879281203"
},
{
flag: "🇷🇺",
timezone: "Europe/Moscow",
channel: "887897904738599002"
},
{
flag: "🇵🇭",
timezone: "Asia/Manila",
channel: "888505937315389451"
},
{
flag: "🇯🇵",
timezone: "Asia/Tokyo",
channel: "887897753198419999"
}
],
pixiv_subscriptions: [
{
tag: "初音ミク",
channel: "900583427483516938"
},
{
tag: "鏡音リン",
channel: "904093976615849996"
},
{
tag: "重音テト",
channel: "904093991224627270"
},
{
tag: "巡音ルカ",
channel: "916444961958928394"
}
],
vrchat_status_category: "959236139913445376",
vrchat_configuration: {
username: process.env.VRCHAT_USERNAME,
password: process.env.VRCHAT_PASSWORD
},
masto: {
url: "https://mastodong.lol",
accessToken: process.env.MASTO_TOKEN
},
masto_account_id: "108643271047165149",
masto_webhook: process.env.DISCORD_WEBHOOK_FOR_MASTO
} }
+25
View File
@@ -0,0 +1,25 @@
var commands = require("./commands");
var app = require("./www");
var config = require("./config");
var mediaProxyUAs = [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11.6; rv:92.0) Gecko/20100101 Firefox/92.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0"
];
var img = Buffer.from("iVBORw0KGgoAAAANSUhEUgAAACMAAAAhCAYAAABTERJSAAACpUlEQVRYCa2XvW7bQAzH6SRApyJAkSHwlqHoJHSNgSx+lQx9iD5AH6KDX0VLAHctNHboFmQoCnTs0Kb40yJL8cg7WY4A43Q8fvxM8k7Sik64rq/ePtfMn358W9XW/dqFF7TmFuBxuKPV9S40eX66p3VHCjsHbDa5QDx+viTadCFAKtwPtP7wi5drULNgALIIwtONUBlQE+bFQASsAlSFURAi2n78K+507D+dHV8yWCdAKYyCbDrabr8qQHSzCCoAOoucWxC7jqB9//7wQ1bGK8qarKXjpiP0IWKJTpgZhhnuRCcf94OWD5BLrnX3QNLQBUyWFdTZZmBRaSJaU6740AvOEQsCn5j3feSdwh5LM8exHtjR/8LHfo+WZs0OebYmQSYwWiJZPWHkMgb2EZA08gSGbYMSQe6d+7nEld3myxr5EBt5vJQ9sx/ig2zTpT2iTls3mQ/EJKISxjm0aU2b0NksnZZlMp4Awmk3B5xZrt76Mvp5ZBxnZjxT1AH3Uf2RUDjPSuIVxxJBHMLwGdJ6CLpDUGLwH0g2gehkY1Gm319+HnStQ0MvjqLdgjXIbZ+JfjiOfiXmJDN4Rtzs8CI1ZYwCh82cZKsGgrWb3Tk/nyYwOPTeXb2Otzb+deNVAo5DSE8TZBoqCqOnry3P6GRugCiDngMPXHsdSnTOIoapgVjD6n1rxzkI8SUlwvziZBDTJ0UGEwABsVlhGF4ISiMGdsx6Rs+jRnDrCyA2K1jTnrGK2b3+c38oZgaJPAKB6nQPJ8aFeGYmCzsiykCge1RmYJCVKgrsZTUQ6B4yc0StUSrtER8tmQMCn7e+R7w6v5Av2VF4q/9+/4de3b7xPnkuWZBF+QKQeTTq1wGAoND8pjZv82ITOYZsDoC1VRgRtgIsCSK+W+M/mSFEURCM3rAAAAAASUVORK5CYII=","base64");
commands.push({
name: "count",
description: "Estimate how many clients are looking at the channel",
exec: async i => {
var count = 0;
var route = `/tmp/${Math.random()}`;
app.get(route, (req, res) => {
if (mediaProxyUAs.includes(req.headers["user-agent"])) count++;
res.type("png").send(img);
});
await i.reply(config.base_uri + route);
await new Promise(r => setTimeout(r, 1000));
await i.editReply(`It appears there might be **${count}** clients viewing this channel right now.`);
}
});
+31
View File
@@ -0,0 +1,31 @@
var fs = require("fs");
var config = require("./config");
module.exports = class DataStore {
constructor(id) {
if (id.includes('/')) throw new Error("NO");
this.dir = `${config.data_dir}/${id}/`;
if (!fs.existsSync(this.dir)) fs.mkdirSync(this.dir);
}
get(key) {
if (key.includes('/')) throw new Error("NO");
try {
return fs.readFileSync(this.dir + key, "utf8") || true;
} catch (error) {
if (error.code == "ENOENT") return false;
else throw error;
}
}
put(key, value) {
if (key.includes('/')) throw new Error("NO");
return fs.writeFileSync(this.dir + key, String(value) || '');
}
del(key) {
if (key.includes('/')) throw new Error("NO");
try {
return fs.unlinkSync(this.dir + key);
} catch (error) {
if (error.code != "ENOENT") throw error;
}
}
}
+81
View File
@@ -0,0 +1,81 @@
var client = require("./client.js");
var config = require("./config");
client.on("guildMemberAdd", member => {
if (member.guild.id != config.guild) return;
// add role
member.roles.add(member.user.bot ? config.bot_role : config.human_role);
// welcome message
/*setTimeout(() => {
client.channels.resolve(config.default_channel)?.send(
`Welcome ${member}. Please tell from where you entered this server and some other info about yourself in order to gain access to message history.`
);
}, 3000);*/
member.roles.add(config.verified_role);
});
// join message
/*client.on("messageDelete", message => {
if (message.channel.id != config.default_channel) return;
if (message.type != "GUILD_MEMBER_JOIN") return;
client.channels.resolve(config.default_channel)?.send(
`sussy baka ${message.author} deleted their join message ||(from <t:${Math.floor(message.createdAt.valueOf()/1000)}>)||`
);
});*/
client.on("guildMemberRemove", member => {
if (member.guild.id != config.guild) return;
// leave message
client.channels.resolve(config.default_channel)?.send(random([
`${member.user.username} left`,
`${member.user.username} disappeared`,
`${member.user.username.toLowerCase()} is gone`
]));
});
client.on("messageCreate", message => {
// comment thread on announcements
message.channel.id == config.announcement_channel && message.startThread({name: "Comments"});
// stupid m bot
message.author.id == "732072478519722096" && message.content.endsWith("is bad letter m is much better") && message.delete();
});
// add reactions to video and audio
{
let a = async m => {
if (m.guild?.id != config.guild) return;
if ((m.embeds.some(e => e.type == "video") || m.attachments.some(a => a.contentType?.startsWith('video'))) && !m.g) {
m.g = true;
m.react(config.mi_emoji);
}
if (m.attachments.some(a => a.contentType?.startsWith('audio')) && !m.d) {
m.d = true;
m.react(config.ki_emoji);
}
}
client.on("messageCreate", a);
client.on("messageUpdate", (r, q) => a(q));
}
// thing to access archived channels
client.on("voiceStateUpdate", (oldState, newState) => {
if (newState.guild.id != config.guild) return;
if (oldState.channelId != config.archive_portal_voice_channel && newState.channelId == config.archive_portal_voice_channel) {
// join
newState.member?.roles.add(config.view_archived_channels_role);
} else if (oldState.channelId == config.archive_portal_voice_channel && newState.channelId != config.archive_portal_voice_channel) {
// leave
newState.member?.roles.remove(config.view_archived_channels_role);
}
});
// save deleted emojis
client.on("emojiDelete", emoji => {
client.channels.resolve(config.bot_channel)?.send({
content: "emoji deleted",
files: [{attachment: emoji.url, name: `${emoji.name}.${emoji.url.split('.').pop()}`}]
});
});
//g=setInterval(() => client.guilds.resolve(config.guild)?.setIcon(`mf/${Math.floor(Math.random()*14548)}.png`), 1800000);
-6
View File
@@ -1,6 +0,0 @@
#!/bin/bash
cd `dirname "$0"`
docker stop ldb
docker rm ldb
docker build -t ledlamp/lampdiscordbot .
docker run -d --name ldb --restart=unless-stopped --env-file=secrets.env -v /srv/www/ldb/:/srv/www/ldb/ ledlamp/lampdiscordbot
+42
View File
@@ -0,0 +1,42 @@
var client = require("./client");
var config = require("./config");
var Discord = require("discord.js");
client.on("messageCreate", async function (message) {
if (message.author.id == client.user.id) return;
if (!message.member?.roles.cache.has(config.admin_role)) return;
if (message.content.startsWith("!>")) {
with (message) {
try {
var x = await eval(message.content.substring(2).trim());
} catch(e) {
var x = e.message;
}
}
if (typeof x == "undefined") return void await message.react(config.eval_undefined_emoji);
let t = typeof x == 'string' ? 'txt' : 'js';
if (typeof x != 'string' && typeof x != "function") x = require('util').inspect(x, {depth: 1});
let cb = `\`\`\`${t}\n${x}\`\`\``;
if (cb.length <= 2000)
message.channel.send(cb);
else
message.channel.send({files:[{
attachment: Buffer.from(x),
name: `output.${t}`
}]});
}
else if (message.content.startsWith("!$")) {
let cp = require("child_process").spawn("bash", ["-c", message.content.substr(2).trim()]);
function ondat(a) {
try {
var split = Discord.Util.splitMessage(a.toString(), {split:{char:'\n',length:2000}});
} catch(x) {
var split = Discord.Util.splitMessage(a.toString(), {split:{char:'',length:2000}});
}
split.forEach(message.channel.send.bind(message.channel));
}
cp.stdout.on("data", ondat);
cp.stderr.on("data", ondat);
}
});
+21
View File
@@ -0,0 +1,21 @@
process.title = "lamp discord bot";
process.on("unhandledRejection", error => {
console.error("Unhandled Rejection:\n", error.stack || error);
});
require("./util"); // global variables set in here
require("./client");
require("./discord-misc");
require('./eval-exec');
require('./colors');
require('./www');
require('./pinboard');
require('./pixiv-embedder');
require('./translate2');
require('./world-clock');
require('./buttonthing');
require("./activitytracker");
require("./vocabularygame");
require("./pixiv-subscribe");
require("./count-cmd");
require("./masto");
+14
View File
@@ -0,0 +1,14 @@
[Unit]
Description=Bot for Lamp Discord Server
After=network.target
[Service]
User=ldb
Group=ldb
WorkingDirectory=/srv/ldb
EnvironmentFile=/srv/ldb/secrets.env
ExecStart=node index.js
Restart=on-success
[Install]
WantedBy=multi-user.target
-17
View File
@@ -1,17 +0,0 @@
global.config = require("./config");
global.Discord = require("discord.js");
global.client = new Discord.Client({
disableMentions: "everyone",
partials: ['MESSAGE','REACTION'],
fetchAllMembers: true
});
client.login(config.token).then(() => console.log("ready"));
client.on("guildMemberAdd", member => {
member.guild.id == config.guild && member.roles.add(member.user.bot ? config.bot_role : config.human_role)
});
require('./commands.js');
require('./colors.js');
require('./pinboard.js');
+39
View File
@@ -0,0 +1,39 @@
var {login} = require("masto");
var config = require("./config");
var client = require("./client");
var {WebhookClient} = require("discord.js");
var webhook = new WebhookClient({url: config.masto_webhook});
module.exports.webhook = webhook;
client.once("ready", async () => {
var donger = await login(config.masto);
console.log("donger logged in");
module.exports.donger = donger;
(async function openStream() {
try {
var stream = await donger.stream.streamUser();
module.exports.stream = stream;
stream.on("update", toot => {
if (toot.account.id != config.masto_account_id) return;
if (toot.visibility != "public") return;
if (toot.inReplyToAccountId && toot.inReplyToAccountId != toot.account.id) return;
webhook.send(toot.url || toot.reblog.url); //todo maybe custom embed
//todo maybe handle deletes
});
stream.ws.on("close", () => {
console.log("donger stream closed");
setTimeout(openStream, 10000);
});
} catch (error) {
console.error("donger stream", error.message);
setTimeout(openStream, 60000);
}
})();
});
+1
View File
File diff suppressed because one or more lines are too long
+1884 -121
View File
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -1,6 +1,14 @@
{ {
"dependencies": { "dependencies": {
"discord.js": "^12.5.3", "@discordjs/voice": "^0.7.5",
"fast-average-color-node": "^1.0.3" "deepl": "^1.0.12",
"discord.js": "^13.6.0",
"express": "^4.17.1",
"fast-average-color-node": "^1.0.3",
"kuroshiro": "^1.2.0",
"kuroshiro-analyzer-kuromoji": "^1.1.0",
"libsodium-wrappers": "^0.7.9",
"masto": "^4.4.0",
"node-fetch": "^2.6.1"
} }
} }
+53 -31
View File
@@ -1,13 +1,35 @@
var fs = require("fs"); var fs = require("fs");
var fetch = require("node-fetch"); var fetch = require("node-fetch");
var Discord = require("discord.js");
var client = require("./client");
var config = require("./config");
var app = require("./www");
var commands = require("./commands");
/*commands.push({
type: "MESSAGE",
name: "Archive",
exec: async i => {
let message = await i.channel.messages.fetch(i.targetId);
let asdf = await doThing(message, i.user);
i.reply({
content: `https://discord.com/channels/${asdf.guild.id}/${asdf.channel.id}/${asdf.id}`,
ephemeral: true
});
}
});*/
client.on("messageReactionAdd", async (reaction, user) => { client.on("messageReactionAdd", async (reaction, user) => {
if (reaction.emoji.name == '📍' || reaction.emoji.name == '📌') { if (reaction.emoji.name == '📍' || reaction.emoji.name == '📌') {
if (!reaction.message.guild) return; if (!reaction.message.guild) return;
if (reaction.message.channel.id == config.archive_channel) return; if (reaction.message.channel.id == config.archive_channel) return;
if (reaction.message['has been "pinned"'] || reaction.count > 1) return; if (reaction.message['has been pinned'] || reaction.count > 1) return;
reaction.message['has been "pinned"'] = true; reaction.message['has been pinned'] = true;
if (reaction.message.channel.id == config.porn_channel) { /*if (reaction.message.channel.id == config.porn_channel)*/ {
try { try {
await reaction.message.pin(); await reaction.message.pin();
} catch (e) { } catch (e) {
@@ -25,33 +47,33 @@ client.on("messageReactionAdd", async (reaction, user) => {
} }
} }
// cache avatar because discord doesn't keep it if they change it doThing(reaction.message, user);
var avatarURL = reaction.message.author.avatarURL({dynamic: true});
if (avatarURL) {
let afn = avatarURL.split('/').pop();
let lapath = config.avatar_cache_dir + afn;
if (!fs.existsSync(lapath)) {
try {
(await fetch(avatarURL)).body.pipe(fs.createWriteStream(lapath));
} catch (error) {
console.error("avatar download", error.message);
}
}
avatarURL = config.avatar_cache_url + afn;
} else avatarURL = reaction.message.author.defaultAvatarURL;
let imageCandidate = reaction.message.attachments.find(a => [".png",".jpg",".jpeg",".webp",".gif"].some(e => a.url.toLowerCase().endsWith(e)));
if (imageCandidate) imageCandidate["will be used for the image of the embed"] = true;
else imageCandidate = reaction.message.embeds.find(e => e.type == 'image');
let embed = new Discord.MessageEmbed()
.setAuthor(reaction.message.member?.displayName || reaction.message.author.username, avatarURL)
.setDescription(reaction.message.content)
.setImage(imageCandidate?.url)
.setFooter(`Pinned by ${reaction.message.guild.members.resolve(user)?.displayName || user.username}`)
.setTimestamp(reaction.message.createdAt)
.setColor(reaction.message.member?.roles.color?.color);
let attachments = reaction.message.attachments.filter(a => !a["will be used for the image of the embed"]).map(a => `[${a.name}](${a.url})`).join('\n');
if (attachments) embed.addField("Attachments", attachments);
(await client.channels.fetch(config.archive_channel))?.send(`https://discord.com/channels/${reaction.message.guild.id}/${reaction.message.channel.id}/${reaction.message.id}`, embed);
} }
}); });
async function doThing(message, user) {
var avatarURL = message.author.avatarURL({dynamic: true}) || message.author.defaultAvatarURL;
var avatarName = avatarURL.split('/').pop();
let imageCandidate = message.attachments.find(a => [".png",".jpg",".jpeg",".webp",".gif"].some(e => a.url.toLowerCase().endsWith(e)));
if (imageCandidate) imageCandidate["will be used for the image of the embed"] = true;
else imageCandidate = message.embeds.find(e => e.type == 'image');
let embed = new Discord.MessageEmbed()
.setAuthor(message.member?.displayName || message.author.username, `attachment://${avatarName}`)
.setDescription(message.content)
.setImage(imageCandidate?.url)
.setFooter(`Pinned by ${message.guild.members.resolve(user)?.displayName || user.username}`)
.setTimestamp(message.createdAt)
.setColor(message.member?.roles.color?.color);
let attachments = message.attachments.filter(a => !a["will be used for the image of the embed"]).map(a => `[${a.name}](${a.url})`).join('\n');
if (attachments) embed.addField("Attachments", attachments);
return (await client.channels.fetch(config.archive_channel))?.send({
content: `https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.id}`,
files: [{attachment: avatarURL, name: avatarName}],
embeds:[embed]
});
}
app.use("/avatars/", require("express").static(config.data_dir + "avatars/"));
+90
View File
@@ -0,0 +1,90 @@
var fetch = require("node-fetch");
var client = require("./client");
var config = require("./config");
var commands = require("./commands");
client.on("messageCreate", async message => {
if (message.guild?.id != config.guild) return;
if (message.author.bot) return;
if (message.author.id == client.user.id) return;
let pixiv_urls = new Set(message.content.match(/(?<!\/)https?:\/\/(?:www\.)?pixiv\.net(?:\/en)?\/artworks\/\d+\b/g));
if (!pixiv_urls.size) return;
message.suppressEmbeds();
// suppressing embeds doesn't work on embeds that load after
client.on("messageUpdate", function arf(g,updatedMessage) {
if (updatedMessage.id == message.id) {
updatedMessage.suppressEmbeds();
// sometimes it still doesn't work
setTimeout(() => {
updatedMessage.suppressEmbeds();
}, 1000);
client.removeListener("messageUpdate", arf);
}
});
message.channel.sendTyping();
try {
await embedPixiv(message.channel, pixiv_urls, message.channel.send.bind(message.channel), pixiv_urls.size > 1);
} catch (error) {
if (pixiv_urls.size == 1) message.react('⚠');
}
});
commands.push({
name: "miku",
description: "Random Miku pic",
exec: async i => {
var mikutachi = require('./mikutachi');
await i.deferReply();
await embedPixiv(i.channel, [`https://www.pixiv.net/en/artworks/${random(mikutachi)}`], i.editReply.bind(i), true);
}
});
// using this code for embedding links and for slash commands
async function embedPixiv(/*message*/ channel, /*array of*/ links, send = channel.send.bind(channel) /* or interaction.reply function */, showLinks /* include pixiv links in response content */) {
for (let link of links) {
try {
let illust = Object.values(JSON.parse((await (await fetch(link)).text()).match(/<meta name="preload-data" id="meta-preload-data" content='(.*)'>/)[1]).illust)[0];
let content = `**${illust.title}**\n`;
if (showLinks || illust.illustType == 2) {
content += `<${link}>${illust.illustType == 2 ? " is an animation (must open link to play)" : ''}`;
}
let images = [];
for (let i = 0; i < illust.pageCount; i++) images.push({url: illust.urls.original.replace('p0', 'p'+i)});
if (images.length <= 10) {
try {
for (let image of images) {
image.data = await (await fetch(image.url, {headers: {"Referer": "https://www.pixiv.net/"}})).buffer();
}
await send({
content,
files: images.map(image => ({attachment: image.data || "error", name: ((illust.xRestrict && !channel.nsfw) ? 'SPOILER_' : '') + image.url.split('/').pop()}))
});
} catch (error) {
if (error.message == "Request entity too large") await fallback();
else throw error;
}
} else await fallback();
function fallback() {
let urls = images.map(image => image.url.replace("i.pximg.net", "px.owo39.me"));
if (illust.xRestrict && !channel.nsfw) urls = urls.map(url => `||${url} ||`);
urls = urls.join('\n');
if (urls.length > 2000) {
return send({content, files:[{attachment: Buffer.from(urls), name:"message.txt"}]});
} else {
return send((content ? content + '\n' : '') + urls);
}
}
} catch (error) {
console.error("pixiv embed error,", error.stack);
if (showLinks) {
send(`<${link}> failed to be embedded`);
} else {
throw error;
}
}
}
}
module.exports.embedPixiv = embedPixiv;
+32
View File
@@ -0,0 +1,32 @@
var client = require("./client");
var DataStore = require("./datastore");
var fetch = require("node-fetch");
var {embedPixiv} = require("./pixiv-embedder");
var config = require("./config");
async function check(tag, channel) {
var ds = new DataStore(`s${tag}`);
var t = encodeURIComponent(tag);
var data = await (await fetch(`https://www.pixiv.net/ajax/search/artworks/${t}?word=${t}&order=date_d&mode=all&p=1&s_mode=s_tag_full&type=all&lang=en`)).json();
var illusts = data.body.illustManga.data;
var newPosts = [];
for (let owo of illusts) {
if (!ds.get(owo.id)) {
newPosts.push(owo);
ds.put(owo.id);
} else break;
}
for (let i = newPosts.length - 1; i >= 0; i--) {
let url = `https://www.pixiv.net/en/artworks/${newPosts[i].id}`;
await embedPixiv(
client.channels.resolve(channel),
[url],
undefined,
true
);
}
}
module.exports.check = check;
module.exports.interval = setInterval(function() {
config.pixiv_subscriptions.forEach(x => check(x.tag, x.channel));
}, 1000*60*60);
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

+168
View File
@@ -0,0 +1,168 @@
var commands = require("./commands");
var config = require("./config");
var deepl = require("deepl");
var Kuroshiro = require("kuroshiro").default;
var KuromojiAnalyzer = require("kuroshiro-analyzer-kuromoji");
var kuroshiro = new Kuroshiro();
kuroshiro.init(new KuromojiAnalyzer());
var lang2flag = {
BG: '🇧🇬',
CS: '🇨🇿',
DA: '🇩🇰',
DE: '🇩🇪',
EL: '🇬🇷',
EN: '🇬🇧',
'EN-GB': '🇬🇧',
'EN-US': '🇺🇸',
ES: '🇪🇸',
ET: '🇪🇪',
FI: '🇫🇮',
FR: '🇫🇷',
HU: '🇭🇺',
IT: '🇮🇹',
JA: '🇯🇵',
LT: '🇱🇹',
LV: '🇱🇻',
NL: '🇳🇱',
PL: '🇵🇱',
PT: '🇵🇹',
'PT-PT': '🇵🇹',
'PT-BR': '🇧🇷',
RO: '🇷🇴',
RU: '🇷🇺',
SK: '🇸🇰',
SL: '🇸🇮',
SV: '🇸🇻',
ZH: '🇨🇳'
};
commands.push({
name: "toen",
description: "Translate text to English",
global: true,
options: [
{
type: "STRING",
name: "text",
description: "Text to translate",
required: true
}
],
exec: i => t(i, "EN")
});
commands.push({
name: "toja",
description: "Translate text to Japanese",
global: true,
options: [
{
type: "STRING",
name: "text",
description: "Text to translate",
required: true
}
],
exec: i => t(i, "JA")
});
commands.push({
name: "tolang",
description: "Translate text to any language",
global: true,
options: [
{
type: "STRING",
name: "lang",
description: "Language to translate to",
required: true,
choices: [
{ name: 'Bulgarian', value: 'BG' },
{ name: 'Czech', value: 'CS' },
{ name: 'Danish', value: 'DA' },
{ name: 'German', value: 'DE' },
{ name: 'Greek', value: 'EL' },
{ name: 'English (British)', value: 'EN-GB' },
{ name: 'English (American)', value: 'EN-US' },
{ name: 'Spanish', value: 'ES' },
{ name: 'Estonian', value: 'ET' },
{ name: 'Finnish', value: 'FI' },
{ name: 'French', value: 'FR' },
{ name: 'Hungarian', value: 'HU' },
{ name: 'Italian', value: 'IT' },
{ name: 'Japanese', value: 'JA' },
{ name: 'Lithuanian', value: 'LT' },
{ name: 'Latvian', value: 'LV' },
{ name: 'Dutch', value: 'NL' },
{ name: 'Polish', value: 'PL' },
// { name: 'Portuguese (all Portuguese varieties excluding Brazilian Portuguese)', value: 'PT-PT' },
{ name: 'Portuguese (Brazilian)', value: 'PT-BR' },
{ name: 'Romanian', value: 'RO' },
{ name: 'Russian', value: 'RU' },
{ name: 'Slovak', value: 'SK' },
{ name: 'Slovenian', value: 'SL' },
{ name: 'Swedish', value: 'SV' },
{ name: 'Chinese', value: 'ZH' }
]
},
{
type: "STRING",
name: "text",
description: "Text to translate",
required: true
}
],
exec: i => t(i, i.options.getString("lang"))
});
async function t(i, target_lang) {
var text = i.options.getString("text");
await i.deferReply();
try {
var translation = (await deepl({
text,
target_lang,
free_api: true,
auth_key: config.deepl_auth_key
})).data.translations[0];
} catch (error) {
return void await i.editReply(error.message);
}
if (translation.detected_source_language == "JA") try {
var input_romaji = await kuroshiro.convert(text, {to: "romaji", mode: "spaced"});
} catch (error) {}
if (target_lang == "JA") try {
var output_romaji = await kuroshiro.convert(translation.text, {to: "romaji", mode: "spaced"});
} catch (error) {}
let input_flag = lang2flag[translation.detected_source_language] || `[${translation.detected_source_language}]`;
let output_flag = lang2flag[target_lang] || `[${target_lang}]`;
let msg = input_flag + ' ' + text;
if (input_romaji) msg += '\n' + input_flag + ' ' + input_romaji;
msg += '\n' + output_flag + ' ' + translation.text;
if (output_romaji) msg += '\n' + output_flag + ' ' + output_romaji;
await i.editReply(msg);
try {
var reverse_translation = (await deepl({
text: translation.text,
target_lang: translation.detected_source_language,
free_api: true,
auth_key: config.deepl_auth_key
})).data.translations[0];
if (normalize(text) != normalize(reverse_translation.text)){
if (translation.detected_source_language == "JA") try {
var reverse_romaji = await kuroshiro.convert(reverse_translation.text, {to: "romaji", mode: "spaced"});
} catch (error) {}
await i.editReply(`${msg}\n🔁 ${reverse_translation.text}${reverse_romaji ? `\n🔁 ${reverse_romaji}` : ''}`);
}
} catch(error) {}
}
function normalize(text) {
return text.toLowerCase()//.split('').filter(x => x.match(/[a-z0-9 ]/)).join('');
}
+1
View File
@@ -0,0 +1 @@
global.random = x => x[Math.floor(Math.random() * x.length)];
+40
View File
File diff suppressed because one or more lines are too long
+21
View File
@@ -0,0 +1,21 @@
var client = require("./client");
var config = require("./config");
client.once("ready", () => {
(function clock() {
var d = new Date();
for (let x of config.world_clock) {
let t = x.flag + ' ' + Intl.DateTimeFormat("en", {
timeZone: x.timezone,
hour: 'numeric',
//minute: 'numeric',
timeZoneName: 'long',
hour12: true
}).format(d);
t = t.replace(/[a-z]+(?: |$)/g, ''); // most of the abbrv are GMT+n >:(
client.channels.resolve(x.channel)?.setName(t);
}
d.setMinutes(60);
setTimeout(clock, d - Date.now());
})();
});
+32
View File
@@ -0,0 +1,32 @@
var express = require("express");
var crypto = require("crypto");
var child_process = require("child_process");
var config = require("./config");
var client = require("./client");
var app = module.exports = express();
app.get("/update", (req, res) => {
if (!req.query.payload) return res.status(400).send("missing payload");
if (!req.headers["x-gitea-signature"]) return res.status(400).send("missing signature");
if (crypto.createHmac("sha256", config.secret).update(req.query.payload).digest("hex") != req.headers["x-gitea-signature"])
return res.status(400).send("Signature verification failed");
let data = JSON.parse(req.query.payload);
res.sendStatus(200);
if (data.commits.some(commit => commit.message.includes("%%"))) return;
child_process.exec("git fetch && git reset --hard origin/master", function(error) {
if (error) return void client.channels.resolve(config.bot_channel)?.send(`git pull: ${error.message}`);
child_process.exec("npm install", async function(error) {
if (error) return void client.channels.resolve(config.bot_channel)?.send(`npm install: ${error.message}`);
await client.channels.resolve(config.bot_channel)?.send('t');
process.exit();
});
});
});
app.get("/", (req, res) => {
res.type("text/plain").send(require("util").inspect(client));
});
app.server = app.listen(9251);