100件以上のメッセージを取得する方法
jsconst { Collection } = require("@discordjs/collection");
function array2Collection(messages) {
return new Collection(messages.slice().sort((a, b) => {
const a_id = BigInt(a.id);
const b_id = BigInt(b.id);
return (a_id > b_id ? 1 : (a_id === b_id ? 0 : -1));
}).map(e => [e.id, e]));
}
module.exports = async function fetchMany(channel, options = { limit: 50 }) {
if ((options.limit ?? 50) <= 100) {
return channel.messages.fetch(options);
}
if (typeof options.around === "string") {
const messages = await channel.messages.fetch({ ...options, limit: 100 });
const limit = Math.floor((options.limit - 100) / 2);
if (messages.size < 100) {
return messages;
}
const backward = fetchMany(channel, { limit, before: messages.last().id });
const forward = fetchMany(channel, { limit, after: messages.first().id });
return array2Collection([messages, ...await Promise.all([backward, forward])].flatMap(
e => [...e.values()]
));
}
let temp;
function buildParameter() {
const req_cnt = Math.min(options.limit - messages.length, 100);
if (typeof options.after === "string") {
const after = temp
? temp.first().id : options.after
return { ...options, limit: req_cnt, after };
}
const before = temp
? temp.last().id : options.before;
return { ...options, limit: req_cnt, before };
}
const messages = [];
while (messages.length < options.limit) {
const param = buildParameter();
temp = await channel.messages.fetch(param);
messages.push(...temp.values());
if (param.limit > temp.size) {
break;
}
}
return array2Collection(messages);
}
使い方
fetchMany(<TextChannel | DMChannel | NewsChannel | Thread>, <?ChannelLogsQueryOptions>)
例
メッセージID 818529905184604180
より前 ( 818529905184604180
は含まれない) の 400 件のメッセージを取得して出力する
jslet messages = []
const fetchedMessages = await fetchMany(channel, {
limit: 400,
before: "818529905184604180"
})
fetchedMessages.forEach(msg =>
messages.push(`${msg.author.username} | ${msg.content}`)
)
console.log(messages.join('\n'))
解説
まずAPIの設計として before
、 after
、 around
がある。
around
というのは与えた引数の前後 limit/2
件のメッセージを取得するもの。
limit
に偶数を与えると limit+1
件結果が返ってくる。
これらは択一で複数を与えることはできない。
before
と after
は指定したIDのメッセージを含まない。
before
と after
の場合は単純でAPIをその方向に繰り返し呼べば良い。
around
は多少複雑で初回のリクエストを around
で行ったあとその両端から続くメッセージを (limit-100)/2
件取得する。
件数は切り捨てで良い
実験すればわかるし考えてもわかる(
古いメッセージがコレクションの後ろに来るようになっている
これは単に実装がそうなってるだけな気がしなくもないが気にしないことにする
つまりIDが小さいメッセージが先頭にくる
そうなるように sort
している
関連
井戸端
解説は私かく?yutoさん書く?
語彙力があまりないので伝わりにくい解説になってしまいそう(

それは私が書いてもそう。

というか本質的に難しいんだよこれ()

解説書くとしたらどこから説明したらいいんだろ

aroundの再帰部分?でも見たらわかるやん()

あとは関数の中に関数を入れるという邪悪なテクニックについて?

いい感じに書き直してくれてもいいのよ?

D.js さんはどんな風にしてるんだろ
彼の仕事はdiscord apiを呼び出すことなので()

なるほど

会話になってて草

解説にあると邪魔なので解説を上にあげよう(

同時に作業するとこうなってしまうのか(

ところでsort順序逆だったかもしれねぇ

逆だわ

fixed(

sort
をもう少し分かりやすくしたものがあってもよさそう

fetchMany
って discord.js にもあるんだ(関数名)

内部実装としてあるはず

(当然ここから持ってきた
なるほどね

forwardとbackwardを明示してみた

:+1:

終わった?

しらん(

私はだいたい満足した

とてもよさそう

( 'ω')

適当にアイコン作ってきたけどみずら

こっそりforをpush(可変長引数)に変えた(

草

砂場とかあると良いんですかね?

それくらい自分でproject作れば良い気がする

それはそう

ESのexportsとcommonjsのrequireを併用するなどの過ちを犯していた

というかこのプロジェクト全体の
井戸端があっても良いか?

そうだね あってもよさそう
