!7 concept Msg { long msgID, channelID, userID; long date, edited; // epochSeconds S text; } standardBot1 EAMBot { init { dbIndexing(Msg, 'msgID); } allServers { enhanceFrame { piFrameMenuItem(f, "Show word list", rThread { showText("Word list", makeWordsList()) }); } } sync S processSimplifiedLine(S s, O... _) { try answer super.processSimplifiedLine(s, _); if ((s = dropMyPrefixOrNull(s)) == null) null; optPar MessageChannel channel; if "retrieve history" { MessageHistory history = channel.getHistory(); setAll(new Scan, +channel, +history, incremental := true).run(); ret "Retrieving..."; } if "retrieve full channel" { MessageHistory history = channel.getHistory(); setAll(new Scan, +channel, +history, incremental := false).run(); ret "Retrieving..."; } if "db size" ret nMessages(countConcepts(Msg)); if "random message" { Msg msg = random(list(Msg)); ret msg == null ? "No messages" : "[" + msg.msgID + "] " + msg.text; } null; } class Scan { MessageChannel channel; MessageHistory history; int scanned; bool incremental; run { history.retrievePast(100).queue(msgs -> { temp enter(); print("Got msgs: " + l(msgs)); if (empty(msgs)) ret with postInChannel(channel, "Done (" + nMessages(scanned) + ")"); scanned += l(msgs); if (storeMsgs(msgs) && incremental) ret with postInChannel(channel, "Stopping incremental scan after " + nMessages(scanned)); run(); }, onQueueError); } } bool storeMsgs(L l) { bool anySeen; for (Message msg : l) { Msg m, bool isNew = unpair uniq2(Msg, msgID := msg.getIdLong()); if (isNew) set anySeen; cset(m, channelID := msg.getTextChannel().getIdLong(), userID := msg.getAuthor().getIdLong(), date := msg.getCreationTime().toEpochSecond(), edited := msg.isEdited() ? msg.getEditedTime().toEpochSecond() : 0, text := msg.getContentRaw()); } ret anySeen; } S makeWordsList() { new Map map; // word -> date for (Msg msg : sortedByField date(list(Msg))) { for (S word : words2_notNextToNumbers_plusApostrophe(msg)) map.put(word, msg.date); } ret lines(keysSortedByValuesDesc(map)); } }