Skip to content
This repository has been archived by the owner on Aug 25, 2021. It is now read-only.

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
Android-KitKat committed May 27, 2021
1 parent afbea90 commit 8b9339a
Show file tree
Hide file tree
Showing 8 changed files with 677 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ dist

# TernJS port file
.tern-port

# Configuration
config.json
52 changes: 52 additions & 0 deletions commands/matrix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module.exports = {
name: 'matrix',
description: '矩阵命令',
options: [{
name: 'invite',
type: 'SUB_COMMAND',
description: '查看机器人的邀请链接。'
},{
name: 'info',
type: 'SUB_COMMAND',
description: '查看机器人信息。'
}],

async execute(interaction) {
// 根据子命令调用对应的处理程序
let sub = interaction.options[0].name;
await handles[sub](interaction);
}
}

// 处理程序
let handles = {
invite(interaction) {
// 引入对象
const { commonEmbed } = interaction.client.embeds;

// 发送嵌入消息
let embed = commonEmbed()
.setTitle('欢迎使用矩阵!')
.setDescription(`[点此邀请加入服务器](https://discord.com/oauth2/authorize?client_id=${interaction.applicationID}&scope=bot+applications.commands&permissions=8)`);
interaction.reply(embed);
},

async info(interaction) {
// 引入对象
const { user, application, embeds } = interaction.client;
const { commonEmbed } = embeds;
const { version } = require('../package.json');

await application.fetch(); // 获取应用信息
// 发送嵌入消息
let embed = commonEmbed()
.setTitle('机器人信息')
.setThumbnail(user.displayAvatarURL())
.addFields(
{ name: '所有者', value: application.owner.tag, inline: true },
{ name: '版本', value: version, inline: true },
{ name: '源代码', value: 'https://github.com/Android-KitKat/Matrix', inline: false }
);
interaction.reply(embed);
}
}
117 changes: 117 additions & 0 deletions commands/playsteam.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const Discord = require('discord.js');
const fetch = require('node-fetch');
const xml2js = require('xml2js');

module.exports = {
name: 'playsteam',
description: '寻找共同游玩的Steam游戏。',
cooldown: 60,
options: [{
name: 'player1',
type: 'STRING',
description: 'Steam个人资料地址',
required: true
},{
name: 'player2',
type: 'STRING',
description: 'Steam个人资料地址',
required: true
},{
name: 'player3',
type: 'STRING',
description: 'Steam个人资料地址',
required: false
},{
name: 'player4',
type: 'STRING',
description: 'Steam个人资料地址',
required: false
},{
name: 'player5',
type: 'STRING',
description: 'Steam个人资料地址',
required: false
},{
name: 'player6',
type: 'STRING',
description: 'Steam个人资料地址',
required: false
}],

async execute(interaction) {
// 解析参数
let profiles = [];
for (let option of interaction.options) {
profiles.push(option.value.trim());
}

// 推迟回复
await interaction.defer();

// 引入嵌入消息工具类
const { commonEmbed, errorEmbed } = interaction.client.embeds;

// 计算游戏的交集
let data;
try {
data = await getGamesData(profiles[0]);
for (let i = 1; i < profiles.length; i++) {
let intersect = data.intersect(await getGamesData(profiles[i]));
intersect.each(game => {
let oldGame = data.get(game.appID);
if (game.hoursOnRecord || oldGame.hoursOnRecord) {
game.hoursOnRecord = (game.hoursOnRecord || 0) + (oldGame.hoursOnRecord || 0);
}
});
data = intersect;
}
} catch (error) {
if (error.code !== 'ERR_GAME_INFO' && error.name !== 'TypeError') throw error;
return interaction.followUp({ embeds:[errorEmbed(error)], ephemeral: true });
}

// 按游玩时间排序
data = data.sort((gameA, gameB) => {
let a = gameA.hoursOnRecord || 0;
let b = gameB.hoursOnRecord || 0;
return -(a - b);
});

// 用便于浏览的形式输出
let result = [];
for (let game of data.first(15).values()) {
result.push(`[${game.name}](${game.storeLink}) (${game.hoursOnRecord} 小时)`);
}
let embed = commonEmbed()
.setTitle('共同游玩的Steam游戏')
.setDescription(`将游玩时间相加后进行排序的前15个游戏。\n\n${result.join('\n')}`);
await interaction.followUp(embed);
}
}

/**
* 获取游戏数据
* @param {string} profile Steam个人资料地址
* @returns {Promise<Discord.Collection<string, any>>}
*/
async function getGamesData(profile) {
let url = `${profile}${profile.endsWith('/') ? '' : '/'}games/?xml=1&l=schinese`; // 生成URL
let res = await fetch(url); // 发送请求
let data = await xml2js.parseStringPromise(await res.text(), { explicitArray: false }); // 解析XML
// 无法获取游戏数据时报错
if (!data.gamesList.games) {
let error = new Error(`无法获取 [${data.gamesList.steamID}](${profile}) 的游戏信息。`);
error.code = 'ERR_GAME_INFO';
throw error;
}
// 提取游戏数据
let coll = new Discord.Collection();
for (let game of data.gamesList.games.game) {
// 格式化游玩时间
if (game.hoursOnRecord) {
game.hoursOnRecord = Number(game.hoursOnRecord.replace(/,/g, ''));
};
coll.set(game.appID, game);
}
return coll;
}
9 changes: 9 additions & 0 deletions config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"token": "Bot token",
"proxy": {
"enable": false,
"http": "http://127.0.0.1:8080",
"https": ""
},
"activity": ""
}
132 changes: 132 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
const fs = require('fs');
const colors = require('colors/safe');
const Discord = require('discord.js');
const EmbedUtils = require('./utils/EmbedUtils');
const { token, proxy, activity } = require('./config.json');

// 创建客户端
const client = new Discord.Client({
intents: ['GUILD_INTEGRATIONS'],
presence: {
activities: [{
name: '启动中...'
}]
}
});

// 增加自定义属性
client.commands = new Discord.Collection();
client.cooldowns = new Discord.Collection();
client.embeds = new EmbedUtils(client);
client.logger = require('tracer').dailyfile({
format: '{{timestamp}} <{{title}}> {{message}}',
dateformat: 'yyyy-mm-dd HH:MM:ss Z',
transport: data => {
let color = {
//log : do nothing
trace : colors.magenta,
debug : colors.cyan,
info : colors.green,
warn : colors.yellow,
error : colors.red.bold,
fatal : colors.red.bold
}
let output = color[data.title](data.output);
if (data.title == 'warn') {
console.warn(output);
} else if (data.level > 4) {
console.error(output);
} else {
console.log(output);
}
},
root: './logs/',
maxLogFiles: 30,
allLogsFileName: 'Matrix'
});
const { commands, cooldowns, embeds, logger } = client;
const { errorEmbed } = embeds;

// 创建日志文件夹
if (!fs.existsSync('./logs/')) fs.mkdirSync('./logs/');

// 加载命令
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
let command = require(`./commands/${file}`);
commands.set(command.name, command);
}

// 准备就绪时
client.once('ready', () => {
logger.info(`登陆到 ${client.user.tag}`); // 输出登陆信息
client.user.setPresence(activity ? { activities: [{ name: activity }] } : {}); // 设置活动状态
// 注册斜杠命令
commands.each(command => {
client.application.commands.create(command);
});
});

// 收到交互时
client.on('interaction', async interaction => {
// 检查交互
if (!interaction.isCommand()) return;
if (!commands.has(interaction.commandName)) return interaction.reply({ embeds: [errorEmbed('命令不存在!')], ephemeral: true });

// 获取相关对象
const command = commands.get(interaction.commandName);
const { user, guild, guildID } = interaction;

// 检查冷却时间
if (!cooldowns.has(command.name)) {
cooldowns.set(command.name, new Discord.Collection());
}
const now = Date.now();
const timestamps = cooldowns.get(command.name);
const cooldownAmount = (command.cooldown || 3) * 1000;
if (timestamps.has(user.id)) {
const timeLeft = (cooldownAmount - (now - timestamps.get(user.id))) / 1000;
return interaction.reply({ embeds: [errorEmbed(`\`${command.name}\` 命令正在冷却,请 ${timeLeft.toFixed(1)} 秒后再试。`)], ephemeral: true });
}

// 记录冷却时间
timestamps.set(user.id, now);
setTimeout(() => timestamps.delete(user.id), cooldownAmount);

// 记录日志
let options = [];
interaction.options.forEach(option => {
options.push(`${option.name}${option.value ? `: ${option.value}` : ''}`);
});
let optionsText = options.length > 0 ? ` ${options.join(' ')}` : '';
let guildText = guild ? `,位于 ${(await guild.fetch()).name}(${guildID})` : '';
logger.info(`${user.tag}(${user.id}) 使用了 /${command.name}${optionsText}${guildText}。`);

// 执行命令
try {
await command.execute(interaction);
} catch (error) {
logger.error(error);
if (interaction.deferred) {
interaction.followUp({ embeds: [errorEmbed('在尝试执行命令时出错!')], ephemeral: true });
} else {
interaction.reply({ embeds: [errorEmbed('在尝试执行命令时出错!')], ephemeral: true });
}
}
});

// 设置代理
if (proxy.enable) {
require('global-agent').bootstrap();
if (proxy.http) global.GLOBAL_AGENT.HTTP_PROXY = proxy.http;
if (proxy.https) global.GLOBAL_AGENT_HTTPS_PROXY = proxy.https;
}

client.login(token); // 登陆客户端

// 程序中止时
process.on('SIGINT', async () => {
client.destroy(); // 销毁客户端
logger.info('拜拜!'); // 输出退出信息
process.exit(); // 程序退出
});
Loading

0 comments on commit 8b9339a

Please sign in to comment.