Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9055

Discordで通話中のみのチャットを作るBotをdiscord.jsで作った

$
0
0

discord.js-12.3.1request-2.88.2Node.js-12.18.3
Discordで通話中のみのチャットが作りたい!
こちらの記事を見て、社内Discordで使いたいという要望があったので、discord.jsで作ってみました。
処理の流れやソースの構成はほぼそのままです。

ソースコード

全体はこちらにあります。

index.js
constDiscord=require("discord.js");constclient=newDiscord.Client();constprivateChat=require('./main.js')client.login(process.env.DISCORD_BOT_TOKEN);// ボイスチャンネルの状態変更イベント時に実行client.on('voiceStateUpdate',(oldState,newState)=>privateChat.onVoiceStateUpdate(oldState,newState));client.on("ready",()=>{console.log(`Logged in as ${client.user.tag}!`);});
main.js
constDiscord=require("discord.js");constclient=newDiscord.Client();constrequest=require("request");module.exports={onVoiceStateUpdate:onVoiceStateUpdate};constCHANNEL_PREFIX="🔑";constBOT_ROLE_NAME="BOT";asyncfunctiononVoiceStateUpdate(oldState,newState){if(oldState.channelID===newState.channelID){return;}if(oldState.channelID!=null){constoldChannel=oldState.guild.channels.cache.get(oldState.channelID);if(oldChannel.members.size==0){awaittxChDelete(oldChannel);}else{awaitchExit(oldChannel,newState.member);}}if(newState.channelID!=null){lettxtChannel;constnewChannel=newState.guild.channels.cache.get(newState.channelID);if(newChannel.members.size==1){txtChannel=awaittxChCreate(newChannel,newState.member);}else{txtChannel=awaitchJoin(newChannel,newState.member);}awaitchSendNotification(txtChannel,newState.member);}}// テキストチャンネルを作成asyncfunctiontxChCreate(voiceChannel,voiceJoinedMember){try{constguild=voiceChannel.guild;// チャンネル名の後ろにボイスチャンネルのIDを付与して一意にletchName=CHANNEL_PREFIX+voiceChannel.name+"_"+voiceChannel.id;letbotRole=guild.roles.cache.find(val=>val.name===BOT_ROLE_NAME);letresult=awaitguild.channels.create(chName,{parent:voiceChannel.parent,type:"text",// denyでeveryoneユーザは見れないように// allowでボイスチャンネルに参加したメンバーは見れるようにpermissionOverwrites:[{id:guild.roles.everyone.id,deny:["VIEW_CHANNEL"]},{id:voiceJoinedMember.id,allow:["VIEW_CHANNEL"]},{id:botRole.id,allow:["VIEW_CHANNEL"]}],});returnresult;}catch(err){console.log(err);}}// ボイスチャンネルのIDがついたテキストチャンネルを検索functionchFind(voiceChannel){constguild=voiceChannel.guild;letsearchCondition=voiceChannel.id;letresult=guild.channels.cache.find(val=>val.name.endsWith(searchCondition));returnresult;}// テキストチャンネルを削除asyncfunctiontxChDelete(ch){lettarget=awaitchFind(ch);if(target!=null){target.delete().catch(console.error);}else{console.log("削除するチャンネルがないンゴ");}}// テキストチャンネルの権限を付与asyncfunctionchJoin(ch,user){lettarget=awaitchFind(ch);if(target!=null){target.updateOverwrite(user,{VIEW_CHANNEL:true});returntarget;}else{console.log("チャンネルがないンゴ");}}// テキストチャンネルの権限を削除asyncfunctionchExit(ch,user){lettarget=awaitchFind(ch);if(target!=null){target.updateOverwrite(user,{VIEW_CHANNEL:false});}else{console.log("チャンネルがないンゴ");}}// 入室時にメンションを飛ばして案内asyncfunctionchSendNotification(ch,user){constguild=ch.guild;constsendChannel=awaitguild.channels.cache.find(val=>val.name===ch.name);awaitsendChannel.send(`<@!${user.id}>`).catch(console.error);constembed=newDiscord.MessageEmbed().setTitle("プライベートチャットに参加しました。").setAuthor("To "+user.displayName).setDescription("ボイスチャンネルに参加している人だけに見えるチャンネルです。\n全員が退出すると削除されます。");sendChannel.send(embed);}

ハマったところ

同じカテゴリにいくつもチャンネルがあるのでテキストチャンネル名の中にボイスチャンネル名を含めて識別しやすくしたいと考えました。
最初はボイスチャンネルと同じ名前でテキストチャンネルを作成しようとしていましたが、Discordのテキストチャンネルとボイスチャンネルに使える文字種が異なってること(大文字不可、[]不可など)を知らなかったため、チャンネル名の不一致によりchFindがうまく動きませんでした。
ボイスチャンネル:Apex Legends - A
テキストチャンネル:apex-legends-a

結果として参考にした記事と同じようにボイスチャンネルIDを末尾につけて識別できるようにしています。

letchName=CHANNEL_PREFIX+voiceChannel.name+"_"+voiceChannel.id;

最後に

導入以来、社内MTGをDiscordのボイスチャンネルで行う際などに重宝してくれてるようです。
また、discord.pyをdiscord.jsで書き直すのも双方の言語やライブラリ仕様の違いについての理解を深めるいい機会になりました。


Viewing all articles
Browse latest Browse all 9055

Latest Images

Trending Articles