!7 // cmodule fails because of loadPageWithUserAgent module GBot > DynDiscordHopper { new Map dataByServer; int guildCount; long searches; class ByServer { bool isGuild; S myName = "GBot"; int defaultResults = 1; Set syntaxes = synchroSet(); S answer(S s, Map map) { new Matches m; try answer answerToHello(s, myName); if (discordBotID != 0) s = replacePrefix("<@" + discordBotID + ">", myName + " ", s); s = simpleSpaces_noTok(s); s = regexpReplace_direct(s, "\\s+:", ":"); if (eqic(s, myName + " guild count")) ret renderGuildCount(); if (eqic(s, myName + " searches")) ret str(searches); if (eqic(s, myName + " stats")) ret n2(guildCount, "server") + ", " + nSearches(searches); if (eqicOneOf(replaceIC(words2_spaces(s), " show ", " "), myName + " Help", myName + " info", myName + " commands")) ret loadSnippet(#1024125); if (swic_trim(s, myName + ":", m)) ret doIt(m.rest(), map); if (swic_trim(s, myName + " with description:", m)) ret doIt(m.rest(), map, withDescription := true); if (swic_trim(s, myName + " default results:", m)) { setField(defaultResults := parseInt(m.rest()); ret "OK, returning " + nResults(defaultResults) + " from now on"; } if (eqic(s, myName + " default results")) ret "I'm returning " + nResults(defaultResults) + " by default"; if (eqic(s, myName + " syntaxes")) ret backtickQuote(lines_rtrim(elementPlusList(myName + ": ...", syntaxes))); if (swic_trim_any(s, m, myName + " new syntax:", myName + " add syntax:")) { S syntax = massageSyntax(m.rest()); if (!endsWithEllipsis(syntax)) ret "Shouldn't this end with \"...\"? >> " + syntax; if (!syntaxes.add(syntax)) ret "I already know that syntax!"; change(); ret "Syntax added! You can try: " + backtickQuote(replaceSuffix("...", randomThingToGoogle(), syntax)); } if (swic_trim(s, myName + " forget syntax:", m)) { S syntax = massageSyntax(m.rest()); if (!syntaxes.remove(syntax)) ret "Syntax not found"; change(); ret "Syntax removed!"; } if (swicOneOf_trim(s, m, myName + " source", myName + " code")) ret snippetURL(programID()); if (ellipsisToDotPlusRegexpIC_matchAny(syntaxes, s, m)) ret doIt(m.rest(), map); null; } bool setField(S name, O value) { if (set_trueIfChanged(this, name, value)) false; ret true with _change(); } S doIt(S query, Map map, O... _) { LS l = regexpICFullMatch_groups("(\\d+) results? for[ :](.+)", query); int results = defaultResults; if (l != null) { results = parseInt(first(l)); query = unquote(trim(last(l))); } bool safeSearch = !discord_isNSFWChannel_gen(map.get('channel)); module().setField(searches := searches+1); updateModuleName(); ret discord_google(query, paramsPlus(_, +results, +safeSearch)); } } @Override S answer(S input, Map map) { ret mapEachLine_tlft_nempties(input, s -> { // config by guild or user long guildID = toLong(map.get('guildID)); long id = guildID; print("Guild ID: " + guildID); if (id == 0) { id = toLong(map.get('userID)); print("User ID: " + id); } ByServer data, bool isNew = unpair syncGetOrCreate2(dataByServer, id, func -> ByServer { new ByServer }); data.isGuild = id == guildID; if (isNew) { if (data.isGuild) ++guildCount; change(); } ret data.answer(s, map); }); } S randomThingToGoogle() { ret "why are penguins black and white?"; } S massageSyntax(S syntax) { syntax = unquote(syntax); ret trim(dropSuffix("...", syntax)) + " ..."; } start { if (guildCount == 0) setField(guildCount := countValuesWhere(dataByServer, isGuild := true)); updateModuleName(); } void updateModuleName() pcall { dm_setModuleName("GBot - " + n2(guildCount, "guild") + ", " + n2(searches, "search", "searches")); } S renderGuildCount() { ret "Total guilds joined: " + guildCount + ". Live guilds: " + liveGuildCount(); } int liveGuildCount() { ret l(discord.getGuilds()); } }