Compare commits
69 Commits
13fb466144
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ab43d009b0 | |||
| b18c90996e | |||
| 1f4dec517f | |||
| 1704537a13 | |||
| 69c5a106b5 | |||
| a2966b1475 | |||
| d04200742d | |||
| fbb082fee8 | |||
| bb80d22568 | |||
| 721435f039 | |||
| e85d88de69 | |||
| a4730289a0 | |||
| 02be479a15 | |||
| 1b2df7a1cb | |||
| 7eb01dda9d | |||
| c130ef1506 | |||
| 660234acfd | |||
| c0470e89b6 | |||
| 823c398a5a | |||
| 9b84e4ff7c | |||
| e19f11acae | |||
| 0fcd5f125c | |||
| 1316460838 | |||
| ed76ad6044 | |||
| c0036e7471 | |||
| 55812d6422 | |||
| 93b40700e0 | |||
| 345e368faa | |||
| 523f057ea3 | |||
| a0a9383d32 | |||
| 06685d0ad4 | |||
| 17d295043f | |||
| e069b80a1d | |||
| a016217a06 | |||
| 6dcd1b2665 | |||
| 6f369ee441 | |||
| 79611c34ae | |||
| bec6a886b1 | |||
| 0cd23ff738 | |||
| ba8d2f5cb9 | |||
| fdbf05b846 | |||
| 25ec6a1906 | |||
| f73217e282 | |||
| e0122e5365 | |||
| 7ccfe95b33 | |||
| eb48b90c96 | |||
| f62d629b1f | |||
| 2772a16525 | |||
| 502cffbf06 | |||
| 8fde14112b | |||
| dd159fa854 | |||
| dec7d3a50a | |||
| 978e08b713 | |||
| fd9cc47836 | |||
| 75fa8fce66 | |||
| 51691595ce | |||
| 3f64f2e8e5 | |||
| 8db44d917c | |||
| bb66625541 | |||
| 81a73d519f | |||
| b44a3c482e | |||
| b02ac22ab7 | |||
| bfd9f8be0d | |||
| 54840a409a | |||
| a4cbd51dd6 | |||
| a215a981aa | |||
| af43453a84 | |||
| 732a9c1ee7 | |||
| 32cc7389e3 |
@@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
secrets.env
|
||||
data
|
||||
tokens.txt
|
||||
+19
-6
@@ -6,10 +6,11 @@ var DataStore = require("./datastore");
|
||||
var ds = new DataStore("activity");
|
||||
|
||||
|
||||
app.get("/detect/:userid", (req, res) => {
|
||||
app.get("/detect/:code", (req, res) => {
|
||||
res.sendFile(process.cwd() + "/track-image.png");
|
||||
if (req.headers["user-agent"].includes("Discordbot")) return;
|
||||
onActivity(req.params.userid);
|
||||
onActivity(ds.get(req.params.code));
|
||||
ds.del(req.params.code);
|
||||
});
|
||||
|
||||
|
||||
@@ -54,9 +55,9 @@ module.exports.interval = setInterval(async () => {
|
||||
|
||||
|
||||
async function deactivateMember(member) {
|
||||
//if (ds.get(member.id + "deactivated")) return "member is already deactivated";
|
||||
await member.roles.add(config.inactive_role);
|
||||
ds.put(member.id + "deactivated");
|
||||
ds.put(member.id, Date.now());
|
||||
|
||||
var magic_channel = client.channels.resolve(ds.get(member.id + "magicchannelid"));
|
||||
if (!magic_channel) {
|
||||
@@ -82,17 +83,19 @@ async function deactivateMember(member) {
|
||||
}
|
||||
|
||||
var magic_channel_message_id = ds.get(member.id + "magicchannelmessage");
|
||||
var unique_code = Math.random().toString();
|
||||
ds.put(unique_code, member.id);
|
||||
var content = `${config.base_uri}/detect/${unique_code}`;
|
||||
if (!magic_channel_message_id) {
|
||||
var magic_channel_message = await magic_channel.send(`${config.base_uri}/detect/${member.id}?${Math.random()}`);
|
||||
var magic_channel_message = await magic_channel.send({content});
|
||||
ds.put(member.id + "magicchannelmessage", magic_channel_message.id)
|
||||
} else {
|
||||
await magic_channel.messages.edit(magic_channel_message_id, {content: `${config.base_uri}/detect/${member.id}?${Math.random()}`});
|
||||
await magic_channel.messages.edit(magic_channel_message_id, {content});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function reactivateMember(member) {
|
||||
//if (!ds.get(member.id + "deactivated")) return "member is not deactivated";
|
||||
await member.roles.remove(config.inactive_role);
|
||||
ds.del(member.id + "deactivated");
|
||||
var magic_channel = client.channels.resolve(ds.get(member.id + "magicchannelid"));
|
||||
@@ -101,3 +104,13 @@ async function reactivateMember(member) {
|
||||
|
||||
module.exports.deactivateMember = deactivateMember;
|
||||
module.exports.reactivateMember = reactivateMember;
|
||||
|
||||
|
||||
client.on("messageCreate", async message => {
|
||||
if (message.guildId != config.guild) return;
|
||||
let deactivatedMembersMentionedViaRoles = [...new Set(message.mentions.roles.flatMap(r => r.members).values())].filter(x => ds.get(x.id + "deactivated"));
|
||||
if (deactivatedMembersMentionedViaRoles.length) {
|
||||
for (let m of deactivatedMembersMentionedViaRoles) await reactivateMember(m);
|
||||
await message.reply({content: deactivatedMembersMentionedViaRoles.map(String).join(' '), allowedMentions:{repliedUser: false}});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
module.exports = class DiscordBackup {
|
||||
constructor(guild) {
|
||||
this.guild = guild;
|
||||
this.data = {};
|
||||
}
|
||||
|
||||
async backupGuild() {
|
||||
// includes emojis, stickers, roles
|
||||
this.data.guild = await this.guild.client.api.guilds(this.guild.id).get();
|
||||
}
|
||||
|
||||
async backupMembers() {
|
||||
this.data.members = await this.guild.client.api.guilds(this.guild.id).members.get({query: {limit: 1000}});
|
||||
}
|
||||
|
||||
async backupChannel(channelId) {
|
||||
var data = {
|
||||
channel: await this.guild.client.api.channels[channelId].get(),
|
||||
messages: []
|
||||
};
|
||||
this.data.channels ||= [];
|
||||
this.data.channels.push(data);
|
||||
do {
|
||||
var messages = await this.guild.client.api.channels[channelId].messages.get({query: {
|
||||
before: messages?.at(-1)?.id, limit: 100
|
||||
}});
|
||||
data.messages.push(...messages);
|
||||
} while (messages.length > 0);
|
||||
}
|
||||
|
||||
async backupEverything() {
|
||||
await this.backupGuild();
|
||||
await this.backupMembers();
|
||||
for (let channelId of this.guild.channels.cache.keys()) {
|
||||
try {
|
||||
await this.backupChannel(channelId);
|
||||
} catch (error) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return JSON.stringify(this.data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,67 +10,3 @@ client.login(config.token).then(async () => {
|
||||
console.log("ready");
|
||||
(await client.channels.fetch(config.bot_channel))?.send('a');
|
||||
});
|
||||
|
||||
|
||||
/* small misc stuff here */
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
client.on("guildMemberAdd", member => {
|
||||
if (member.guild.id != config.guild) return;
|
||||
// add role
|
||||
member.roles.add(member.user.bot ? config.bot_role : config.human_role);
|
||||
// join message
|
||||
client.channels.resolve(config.default_channel)?.send(random([
|
||||
`${member.user.username} join`,
|
||||
`${member.user.username} joined`,
|
||||
`${member.user.username} appear`,
|
||||
`${member.user.username.toLowerCase()} here`
|
||||
]));
|
||||
});
|
||||
client.on("guildMemberRemove", member => {
|
||||
if (member.guild.id != config.guild) return;
|
||||
// leave message
|
||||
client.channels.resolve(config.default_channel)?.send(random([
|
||||
`${member.user.username} left`,
|
||||
`${member.user.username} disappear`,
|
||||
`${member.user.username.toLowerCase()} gone`
|
||||
]));
|
||||
});
|
||||
|
||||
|
||||
client.on("messageCreate", message => {
|
||||
// comment thread on announcements
|
||||
message.channel.id == config.announcement_channel && message.startThread({name: "Comments"});
|
||||
// stupid m bot
|
||||
message.author.id == "732072478519722096" && message.content.endsWith("is bad letter m is much better") && message.delete();
|
||||
});
|
||||
|
||||
|
||||
// add reactions to video and audio
|
||||
{
|
||||
let a = async m => {
|
||||
if (m.guild?.id != config.guild) return;
|
||||
if ((m.embeds.some(e => e.type == "video") || m.attachments.some(a => a.contentType?.startsWith('video'))) && !m.g) {
|
||||
m.g = true;
|
||||
m.react(config.mi_emoji);
|
||||
}
|
||||
if (m.attachments.some(a => a.contentType?.startsWith('audio')) && !m.d) {
|
||||
m.d = true;
|
||||
m.react(config.ki_emoji);
|
||||
}
|
||||
}
|
||||
client.on("messageCreate", a);
|
||||
client.on("messageUpdate", (r, q) => a(q));
|
||||
}
|
||||
|
||||
// thing to access archived channels
|
||||
client.on("voiceStateUpdate", (oldState, newState) => {
|
||||
if (newState.guild.id != config.guild) return;
|
||||
if (oldState.channelId != config.archive_portal_voice_channel && newState.channelId == config.archive_portal_voice_channel) {
|
||||
// join
|
||||
newState.member?.roles.add(config.view_archived_channels_role);
|
||||
} else if (oldState.channelId == config.archive_portal_voice_channel && newState.channelId != config.archive_portal_voice_channel) {
|
||||
// leave
|
||||
newState.member?.roles.remove(config.view_archived_channels_role);
|
||||
}
|
||||
});
|
||||
@@ -9,11 +9,11 @@ var commands = require("./commands");
|
||||
|
||||
|
||||
function getColorRoleFor(user_id) {
|
||||
var color_id;
|
||||
try {
|
||||
color_id = fs.readFileSync(config.data_dir + "color/" + user_id, "utf8");
|
||||
return client.guilds.resolve(config.guild)?.roles.fetch(
|
||||
fs.readFileSync(config.data_dir + "color/" + user_id, "utf8")
|
||||
);
|
||||
} catch (e) {}
|
||||
return client.guilds.resolve(config.guild)?.roles.fetch(color_id);
|
||||
}
|
||||
module.exports.getColorRoleFor = getColorRoleFor;
|
||||
|
||||
@@ -115,8 +115,7 @@ commands.push({
|
||||
{
|
||||
name: "icon",
|
||||
description: "Image URL or an emoji",
|
||||
type: "STRING",
|
||||
required: true
|
||||
type: "STRING"
|
||||
}
|
||||
],
|
||||
exec: async i => {
|
||||
@@ -125,13 +124,13 @@ commands.push({
|
||||
if (!colorRole) return void i.editReply({content: "You don't have color role!"});
|
||||
try {
|
||||
let icon = i.options.getString("icon");
|
||||
if (icon.startsWith("http")) {
|
||||
if (/^https?:\/\//i.test(icon)) {
|
||||
await colorRole.setIcon(icon);
|
||||
await i.editReply({files: [{
|
||||
attachment: icon,
|
||||
name: icon.match(/\/(\w*(?:\.png|\.jpg|\.jpeg|\.gif|\.webp))$/i)?.[1] || "icon.png"
|
||||
}]});
|
||||
} else {
|
||||
} else if (icon) {
|
||||
var emoji = Discord.Util.parseEmoji(icon);
|
||||
if (emoji?.id) {
|
||||
await colorRole.setIcon(i.client.rest.cdn.Emoji(emoji.id, emoji.animated ? 'gif' : 'png'));
|
||||
@@ -139,6 +138,9 @@ commands.push({
|
||||
await colorRole.setUnicodeEmoji(icon);
|
||||
}
|
||||
await i.editReply({content: icon});
|
||||
} else {
|
||||
await colorRole.setIcon(null);
|
||||
await i.editReply({content: "icon removed"});
|
||||
}
|
||||
} catch (error) {
|
||||
await i.editReply({content: error.message});
|
||||
|
||||
+109
-35
@@ -38,32 +38,6 @@ var commands = module.exports = [
|
||||
i.reply(owo);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "archive",
|
||||
description: "Delete a channel without actually deleting it",
|
||||
options: [
|
||||
{
|
||||
name: "channel",
|
||||
description: "channel",
|
||||
type: "CHANNEL",
|
||||
required: true
|
||||
}
|
||||
],
|
||||
defaultPermission: false,
|
||||
permissions: [
|
||||
{
|
||||
id: config.admin_role,
|
||||
type: "ROLE",
|
||||
permission: true
|
||||
}
|
||||
],
|
||||
exec: async i => {
|
||||
let channel = i.options.getChannel("channel");
|
||||
await channel.setParent(config.archive_category);
|
||||
await channel.lockPermissions();
|
||||
await i.reply({content: channel.toString()});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "avatar",
|
||||
description: "View a user's original avatar (and save permanently as attachment)",
|
||||
@@ -121,6 +95,115 @@ var commands = module.exports = [
|
||||
name: "Steal Emoji",
|
||||
type: "MESSAGE",
|
||||
exec: i => commands.find(x => x.name == "steal").exec(i)
|
||||
},
|
||||
{
|
||||
name: "setserverbanner",
|
||||
description: "Set the server banner image",
|
||||
options: [
|
||||
{
|
||||
name: "url",
|
||||
description: "HTTP(S) URL to an image",
|
||||
type: "STRING"
|
||||
}
|
||||
],
|
||||
exec: async i => {
|
||||
var url = i.options.getString("url");
|
||||
try {
|
||||
if (!url) {
|
||||
await i.guild.setBanner(null);
|
||||
await i.reply("cleared the server banner");
|
||||
} else {
|
||||
if (/^https?:\/\//i.test(url)) {
|
||||
await i.guild.setBanner(url);
|
||||
await i.reply(url);
|
||||
} else {
|
||||
await i.reply("http image url only!");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
await i.reply(error.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "setservericon",
|
||||
description: "Change the server icon",
|
||||
options: [
|
||||
{
|
||||
name: "url",
|
||||
description: "HTTP(S) URL to an image",
|
||||
type: "STRING"
|
||||
}
|
||||
],
|
||||
exec: async i => {
|
||||
var url = i.options.getString("url");
|
||||
try {
|
||||
if (!url) {
|
||||
await i.guild.setIcon(null);
|
||||
await i.reply("cleared the server icon");
|
||||
} else {
|
||||
if (/^https?:\/\//i.test(url)) {
|
||||
await i.guild.setIcon(url);
|
||||
await i.reply(url);
|
||||
} else {
|
||||
await i.reply("http image url only!");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
await i.reply(error.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "getemoji",
|
||||
description: "Generate a URL for an emoji",
|
||||
options: [
|
||||
{
|
||||
name: "emoji",
|
||||
description: "The emoji (code) or the name of the emoji (case-sensitive)",
|
||||
type: "STRING",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "format",
|
||||
description: "choose image format",
|
||||
type: "STRING",
|
||||
choices: [
|
||||
{name: "PNG", value: "png"},
|
||||
{name: "JPG", value: "jpg"},
|
||||
{name: "WEBP", value: "webp"},
|
||||
{name: "GIF", value: "gif"}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "size",
|
||||
description: "choose image size",
|
||||
type: "INTEGER",
|
||||
choices: "16,20,22,24,28,32,40,44,48,56,60,64,80,96,100,128".split(',').map(s => ({name: s, value: Number(s)}))
|
||||
}
|
||||
],
|
||||
exec: i => {
|
||||
var emojiname = i.options.getString("emoji");
|
||||
if (emojiname.startsWith('<') && emojiname.endsWith('>')) emoji = Discord.Util.parseEmoji(emojiname);
|
||||
else {
|
||||
if (emojiname.startsWith(':')) emojiname = emojiname.slice(1);
|
||||
if (emojiname.endsWith(':')) emojiname = emojiname.slice(-1);
|
||||
var emoji = client.emojis.cache.find(e => e.name == emojiname);
|
||||
if (!emoji) emoji = client.emojis.cache.find(e => e.name.toLowerCase() == emojiname.toLowerCase());
|
||||
if (!emoji) return void i.reply(`could not find emoji named ${emojiname}`);
|
||||
}
|
||||
if (!emoji.id) return void i.reply(`invalid input`);
|
||||
var qs = [];
|
||||
var size = i.options.getInteger("size");
|
||||
if (size) qs.push(`size=${size}`);
|
||||
var format = i.options.getString("format");
|
||||
if (!format) format = emoji.animated ? "gif" : "png";
|
||||
if (format == "gif" && !emoji.animated) return void i.reply(`Non-animated emoji is not available as GIF.`);
|
||||
if (format == "webp") qs.push(`quality=lossless`);
|
||||
var url = `https://media.discordapp.net/emojis/${emoji.id}.${format}`;
|
||||
if (qs.length > 0) url += '?' + qs.join('&');
|
||||
i.reply(`${emoji.name}.${format}\n${url}`);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -133,14 +216,5 @@ client.once("ready", async () => {
|
||||
let guild_commands = commands.filter(x => !x.global);
|
||||
let guild = client.guilds.resolve(config.guild);
|
||||
await guild.commands.set(guild_commands);
|
||||
await guild.commands.permissions.set({
|
||||
fullPermissions: guild_commands.map(local_command => {
|
||||
let discord_command = guild.commands.cache.find(discord_command => local_command.name == discord_command.name);
|
||||
return {
|
||||
id: discord_command.id,
|
||||
permissions: local_command.permissions || []
|
||||
}
|
||||
})
|
||||
});
|
||||
await client.application.commands.set(global_commands);
|
||||
});
|
||||
@@ -8,15 +8,16 @@ module.exports = {
|
||||
human_role: "672956630962274306",
|
||||
bot_role: "673671040010027034",
|
||||
inactive_role: "892869309603389500",
|
||||
verified_role: "949064806030254130",
|
||||
view_archived_channels_role: "916056534402863125",
|
||||
eval_undefined_emoji: "707729833601531935",
|
||||
eval_undefined_emoji: "🅱️",
|
||||
mi_emoji: "887931046086185060",
|
||||
ki_emoji: "887935846710394910",
|
||||
default_channel: "672956424162115586",
|
||||
bot_channel: "782353314137505793",
|
||||
default_channel: "949831184957980722",
|
||||
bot_channel: "949831221981097984",
|
||||
archive_channel: "802280618636869663",
|
||||
moe_channel: "871864787213111366",
|
||||
porn_channel: "835734868427669574",
|
||||
porn_channel: "949831237927862333",
|
||||
announcement_channel: "876010629490683955",
|
||||
miku_channel: "900583427483516938",
|
||||
archive_category: "887838689533771776",
|
||||
@@ -25,26 +26,32 @@ module.exports = {
|
||||
base_uri: "https://ldb.owo69.me",
|
||||
world_clock: [
|
||||
{
|
||||
flag: "🇺🇸",
|
||||
timezone: "America/Los_Angeles",
|
||||
channel: "887897732428226660"
|
||||
},
|
||||
{
|
||||
flag: "🇺🇸",
|
||||
timezone: "America/New_York",
|
||||
channel: "888507872932143155"
|
||||
},
|
||||
{
|
||||
flag: "🇩🇪",
|
||||
timezone: "Europe/Berlin",
|
||||
channel: "887897886879281203"
|
||||
},
|
||||
{
|
||||
flag: "🇷🇺",
|
||||
timezone: "Europe/Moscow",
|
||||
channel: "887897904738599002"
|
||||
},
|
||||
{
|
||||
flag: "🇵🇭",
|
||||
timezone: "Asia/Manila",
|
||||
channel: "888505937315389451"
|
||||
},
|
||||
{
|
||||
flag: "🇯🇵",
|
||||
timezone: "Asia/Tokyo",
|
||||
channel: "887897753198419999"
|
||||
}
|
||||
@@ -61,6 +68,21 @@ module.exports = {
|
||||
{
|
||||
tag: "重音テト",
|
||||
channel: "904093991224627270"
|
||||
},
|
||||
{
|
||||
tag: "巡音ルカ",
|
||||
channel: "916444961958928394"
|
||||
}
|
||||
]
|
||||
],
|
||||
vrchat_status_category: "959236139913445376",
|
||||
vrchat_configuration: {
|
||||
username: process.env.VRCHAT_USERNAME,
|
||||
password: process.env.VRCHAT_PASSWORD
|
||||
},
|
||||
masto: {
|
||||
url: "https://mastodong.lol",
|
||||
accessToken: process.env.MASTO_TOKEN
|
||||
},
|
||||
masto_account_id: "108643271047165149",
|
||||
masto_webhook: process.env.DISCORD_WEBHOOK_FOR_MASTO
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
var commands = require("./commands");
|
||||
var app = require("./www");
|
||||
var config = require("./config");
|
||||
|
||||
var mediaProxyUAs = [
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11.6; rv:92.0) Gecko/20100101 Firefox/92.0",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0"
|
||||
];
|
||||
var img = Buffer.from("iVBORw0KGgoAAAANSUhEUgAAACMAAAAhCAYAAABTERJSAAACpUlEQVRYCa2XvW7bQAzH6SRApyJAkSHwlqHoJHSNgSx+lQx9iD5AH6KDX0VLAHctNHboFmQoCnTs0Kb40yJL8cg7WY4A43Q8fvxM8k7Sik64rq/ePtfMn358W9XW/dqFF7TmFuBxuKPV9S40eX66p3VHCjsHbDa5QDx+viTadCFAKtwPtP7wi5drULNgALIIwtONUBlQE+bFQASsAlSFURAi2n78K+507D+dHV8yWCdAKYyCbDrabr8qQHSzCCoAOoucWxC7jqB9//7wQ1bGK8qarKXjpiP0IWKJTpgZhhnuRCcf94OWD5BLrnX3QNLQBUyWFdTZZmBRaSJaU6740AvOEQsCn5j3feSdwh5LM8exHtjR/8LHfo+WZs0OebYmQSYwWiJZPWHkMgb2EZA08gSGbYMSQe6d+7nEld3myxr5EBt5vJQ9sx/ig2zTpT2iTls3mQ/EJKISxjm0aU2b0NksnZZlMp4Awmk3B5xZrt76Mvp5ZBxnZjxT1AH3Uf2RUDjPSuIVxxJBHMLwGdJ6CLpDUGLwH0g2gehkY1Gm319+HnStQ0MvjqLdgjXIbZ+JfjiOfiXmJDN4Rtzs8CI1ZYwCh82cZKsGgrWb3Tk/nyYwOPTeXb2Otzb+deNVAo5DSE8TZBoqCqOnry3P6GRugCiDngMPXHsdSnTOIoapgVjD6n1rxzkI8SUlwvziZBDTJ0UGEwABsVlhGF4ISiMGdsx6Rs+jRnDrCyA2K1jTnrGK2b3+c38oZgaJPAKB6nQPJ8aFeGYmCzsiykCge1RmYJCVKgrsZTUQ6B4yc0StUSrtER8tmQMCn7e+R7w6v5Av2VF4q/9+/4de3b7xPnkuWZBF+QKQeTTq1wGAoND8pjZv82ITOYZsDoC1VRgRtgIsCSK+W+M/mSFEURCM3rAAAAAASUVORK5CYII=","base64");
|
||||
|
||||
commands.push({
|
||||
name: "count",
|
||||
description: "Estimate how many clients are looking at the channel",
|
||||
exec: async i => {
|
||||
var count = 0;
|
||||
var route = `/tmp/${Math.random()}`;
|
||||
app.get(route, (req, res) => {
|
||||
if (mediaProxyUAs.includes(req.headers["user-agent"])) count++;
|
||||
res.type("png").send(img);
|
||||
});
|
||||
await i.reply(config.base_uri + route);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
await i.editReply(`It appears there might be **${count}** clients viewing this channel right now.`);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
var client = require("./client.js");
|
||||
var config = require("./config");
|
||||
|
||||
|
||||
client.on("guildMemberAdd", member => {
|
||||
if (member.guild.id != config.guild) return;
|
||||
// add role
|
||||
member.roles.add(member.user.bot ? config.bot_role : config.human_role);
|
||||
// welcome message
|
||||
/*setTimeout(() => {
|
||||
client.channels.resolve(config.default_channel)?.send(
|
||||
`Welcome ${member}. Please tell from where you entered this server and some other info about yourself in order to gain access to message history.`
|
||||
);
|
||||
}, 3000);*/
|
||||
member.roles.add(config.verified_role);
|
||||
});
|
||||
// join message
|
||||
/*client.on("messageDelete", message => {
|
||||
if (message.channel.id != config.default_channel) return;
|
||||
if (message.type != "GUILD_MEMBER_JOIN") return;
|
||||
client.channels.resolve(config.default_channel)?.send(
|
||||
`sussy baka ${message.author} deleted their join message ||(from <t:${Math.floor(message.createdAt.valueOf()/1000)}>)||`
|
||||
);
|
||||
});*/
|
||||
client.on("guildMemberRemove", member => {
|
||||
if (member.guild.id != config.guild) return;
|
||||
// leave message
|
||||
client.channels.resolve(config.default_channel)?.send(random([
|
||||
`${member.user.username} left`,
|
||||
`${member.user.username} disappeared`,
|
||||
`${member.user.username.toLowerCase()} is gone`
|
||||
]));
|
||||
});
|
||||
|
||||
|
||||
client.on("messageCreate", message => {
|
||||
// comment thread on announcements
|
||||
message.channel.id == config.announcement_channel && message.startThread({name: "Comments"});
|
||||
// stupid m bot
|
||||
message.author.id == "732072478519722096" && message.content.endsWith("is bad letter m is much better") && message.delete();
|
||||
});
|
||||
|
||||
|
||||
// add reactions to video and audio
|
||||
{
|
||||
let a = async m => {
|
||||
if (m.guild?.id != config.guild) return;
|
||||
if ((m.embeds.some(e => e.type == "video") || m.attachments.some(a => a.contentType?.startsWith('video'))) && !m.g) {
|
||||
m.g = true;
|
||||
m.react(config.mi_emoji);
|
||||
}
|
||||
if (m.attachments.some(a => a.contentType?.startsWith('audio')) && !m.d) {
|
||||
m.d = true;
|
||||
m.react(config.ki_emoji);
|
||||
}
|
||||
}
|
||||
client.on("messageCreate", a);
|
||||
client.on("messageUpdate", (r, q) => a(q));
|
||||
}
|
||||
|
||||
// thing to access archived channels
|
||||
client.on("voiceStateUpdate", (oldState, newState) => {
|
||||
if (newState.guild.id != config.guild) return;
|
||||
if (oldState.channelId != config.archive_portal_voice_channel && newState.channelId == config.archive_portal_voice_channel) {
|
||||
// join
|
||||
newState.member?.roles.add(config.view_archived_channels_role);
|
||||
} else if (oldState.channelId == config.archive_portal_voice_channel && newState.channelId != config.archive_portal_voice_channel) {
|
||||
// leave
|
||||
newState.member?.roles.remove(config.view_archived_channels_role);
|
||||
}
|
||||
});
|
||||
|
||||
// save deleted emojis
|
||||
client.on("emojiDelete", emoji => {
|
||||
client.channels.resolve(config.bot_channel)?.send({
|
||||
content: "emoji deleted",
|
||||
files: [{attachment: emoji.url, name: `${emoji.name}.${emoji.url.split('.').pop()}`}]
|
||||
});
|
||||
});
|
||||
|
||||
//g=setInterval(() => client.guilds.resolve(config.guild)?.setIcon(`mf/${Math.floor(Math.random()*14548)}.png`), 1800000);
|
||||
+1
-1
@@ -9,7 +9,7 @@ client.on("messageCreate", async function (message) {
|
||||
if (message.content.startsWith("!>")) {
|
||||
with (message) {
|
||||
try {
|
||||
var x = await eval(message.content.substr(2).trim());
|
||||
var x = await eval(message.content.substring(2).trim());
|
||||
} catch(e) {
|
||||
var x = e.message;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
process.title = "lamp discord bot";
|
||||
process.on("unhandledRejection", error => {
|
||||
console.error("Unhandled Rejection:\n" + error.stack);
|
||||
console.error("Unhandled Rejection:\n", error.stack || error);
|
||||
});
|
||||
|
||||
require("./util"); // global variables set in here
|
||||
require("./client");
|
||||
require("./discord-misc");
|
||||
require('./eval-exec');
|
||||
require('./colors');
|
||||
require('./www');
|
||||
@@ -16,3 +17,5 @@ require('./buttonthing');
|
||||
require("./activitytracker");
|
||||
require("./vocabularygame");
|
||||
require("./pixiv-subscribe");
|
||||
require("./count-cmd");
|
||||
require("./masto");
|
||||
@@ -0,0 +1,39 @@
|
||||
var {login} = require("masto");
|
||||
var config = require("./config");
|
||||
var client = require("./client");
|
||||
var {WebhookClient} = require("discord.js");
|
||||
|
||||
var webhook = new WebhookClient({url: config.masto_webhook});
|
||||
module.exports.webhook = webhook;
|
||||
|
||||
client.once("ready", async () => {
|
||||
var donger = await login(config.masto);
|
||||
console.log("donger logged in");
|
||||
module.exports.donger = donger;
|
||||
(async function openStream() {
|
||||
try {
|
||||
var stream = await donger.stream.streamUser();
|
||||
module.exports.stream = stream;
|
||||
stream.on("update", toot => {
|
||||
|
||||
if (toot.account.id != config.masto_account_id) return;
|
||||
if (toot.visibility != "public") return;
|
||||
if (toot.inReplyToAccountId && toot.inReplyToAccountId != toot.account.id) return;
|
||||
|
||||
webhook.send(toot.url || toot.reblog.url); //todo maybe custom embed
|
||||
|
||||
//todo maybe handle deletes
|
||||
});
|
||||
stream.ws.on("close", () => {
|
||||
console.log("donger stream closed");
|
||||
setTimeout(openStream, 10000);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("donger stream", error.message);
|
||||
setTimeout(openStream, 60000);
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
|
||||
|
||||
Generated
+733
-222
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -1,11 +1,14 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@discordjs/voice": "^0.7.5",
|
||||
"deepl": "^1.0.12",
|
||||
"discord.js": "github:iShibi/discord.js#feat-role-icon",
|
||||
"discord.js": "^13.6.0",
|
||||
"express": "^4.17.1",
|
||||
"fast-average-color-node": "^1.0.3",
|
||||
"kuroshiro": "^1.2.0",
|
||||
"kuroshiro-analyzer-kuromoji": "^1.1.0",
|
||||
"libsodium-wrappers": "^0.7.9",
|
||||
"masto": "^4.4.0",
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -8,7 +8,7 @@ var app = require("./www");
|
||||
var commands = require("./commands");
|
||||
|
||||
|
||||
commands.push({
|
||||
/*commands.push({
|
||||
type: "MESSAGE",
|
||||
name: "Archive",
|
||||
exec: async i => {
|
||||
@@ -19,17 +19,17 @@ commands.push({
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
});
|
||||
});*/
|
||||
|
||||
|
||||
client.on("messageReactionAdd", async (reaction, user) => {
|
||||
if (reaction.emoji.name == '📍' || reaction.emoji.name == '📌') {
|
||||
if (!reaction.message.guild) return;
|
||||
if (reaction.message.channel.id == config.archive_channel) return;
|
||||
if (reaction.message['has been "pinned"'] || reaction.count > 1) return;
|
||||
reaction.message['has been "pinned"'] = true;
|
||||
if (reaction.message['has been pinned'] || reaction.count > 1) return;
|
||||
reaction.message['has been pinned'] = true;
|
||||
|
||||
if (reaction.message.channel.id == config.porn_channel) {
|
||||
/*if (reaction.message.channel.id == config.porn_channel)*/ {
|
||||
try {
|
||||
await reaction.message.pin();
|
||||
} catch (e) {
|
||||
|
||||
+1
-40
@@ -1,11 +1,7 @@
|
||||
var fetch = require("node-fetch");
|
||||
var https = require("https");
|
||||
var fs = require("fs");
|
||||
|
||||
var client = require("./client");
|
||||
var config = require("./config");
|
||||
var commands = require("./commands");
|
||||
var app = require("./www");
|
||||
|
||||
client.on("messageCreate", async message => {
|
||||
if (message.guild?.id != config.guild) return;
|
||||
@@ -71,9 +67,7 @@ async function embedPixiv(/*message*/ channel, /*array of*/ links, send = channe
|
||||
}
|
||||
} else await fallback();
|
||||
function fallback() {
|
||||
// save the data already downloaded
|
||||
for (let image of images) if (image.data) fs.writeFileSync(config.data_dir + "pixiv-cache/" + image.url.split('?')[0].replace(/\//g, '\\'), image.data);
|
||||
let urls = images.map(image => image.url.replace("https://i.pximg.net/", `${config.base_uri}/pixiv-proxy/`));
|
||||
let urls = images.map(image => image.url.replace("i.pximg.net", "px.owo39.me"));
|
||||
if (illust.xRestrict && !channel.nsfw) urls = urls.map(url => `||${url} ||`);
|
||||
urls = urls.join('\n');
|
||||
if (urls.length > 2000) {
|
||||
@@ -94,36 +88,3 @@ async function embedPixiv(/*message*/ channel, /*array of*/ links, send = channe
|
||||
}
|
||||
|
||||
module.exports.embedPixiv = embedPixiv;
|
||||
|
||||
|
||||
|
||||
|
||||
app.use("/pixiv-proxy/", (req, res, next) => {
|
||||
if (req.method != "GET") return next();
|
||||
let local_file_path = config.data_dir + "pixiv-cache/" + req.url.split('?')[0].replace(/\//g, '\\');
|
||||
if (fs.existsSync(local_file_path)) res.sendFile(local_file_path);
|
||||
else {
|
||||
https.get(`https://i.pximg.net${req.url}`, {
|
||||
headers: {
|
||||
"Referer": "https://www.pixiv.net/"
|
||||
}
|
||||
}, function (origin_res) {
|
||||
if (res.statusCode != 200) return res.status(502).send(`upstream said ${res.statusCode}`);
|
||||
res.writeHead(200, {
|
||||
"Content-Type": origin_res.headers["content-type"]
|
||||
});
|
||||
let local_file_stream = fs.createWriteStream(local_file_path);
|
||||
origin_res.on("data", data => {
|
||||
res.write(data);
|
||||
local_file_stream.write(data);
|
||||
});
|
||||
origin_res.on("end", () => {
|
||||
res.end();
|
||||
local_file_stream.end();
|
||||
});
|
||||
}).on("error", error => {
|
||||
res.status(502).send(error.message);
|
||||
console.error("pixiv proxy error,", error.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
+2
-1
@@ -17,9 +17,10 @@ async function check(tag, channel) {
|
||||
} else break;
|
||||
}
|
||||
for (let i = newPosts.length - 1; i >= 0; i--) {
|
||||
let url = `https://www.pixiv.net/en/artworks/${newPosts[i].id}`;
|
||||
await embedPixiv(
|
||||
client.channels.resolve(channel),
|
||||
[`https://www.pixiv.net/en/artworks/${newPosts[i].id}`],
|
||||
[url],
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
+107
-19
@@ -6,6 +6,37 @@ var KuromojiAnalyzer = require("kuroshiro-analyzer-kuromoji");
|
||||
var kuroshiro = new Kuroshiro();
|
||||
kuroshiro.init(new KuromojiAnalyzer());
|
||||
|
||||
var lang2flag = {
|
||||
BG: '🇧🇬',
|
||||
CS: '🇨🇿',
|
||||
DA: '🇩🇰',
|
||||
DE: '🇩🇪',
|
||||
EL: '🇬🇷',
|
||||
EN: '🇬🇧',
|
||||
'EN-GB': '🇬🇧',
|
||||
'EN-US': '🇺🇸',
|
||||
ES: '🇪🇸',
|
||||
ET: '🇪🇪',
|
||||
FI: '🇫🇮',
|
||||
FR: '🇫🇷',
|
||||
HU: '🇭🇺',
|
||||
IT: '🇮🇹',
|
||||
JA: '🇯🇵',
|
||||
LT: '🇱🇹',
|
||||
LV: '🇱🇻',
|
||||
NL: '🇳🇱',
|
||||
PL: '🇵🇱',
|
||||
PT: '🇵🇹',
|
||||
'PT-PT': '🇵🇹',
|
||||
'PT-BR': '🇧🇷',
|
||||
RO: '🇷🇴',
|
||||
RU: '🇷🇺',
|
||||
SK: '🇸🇰',
|
||||
SL: '🇸🇮',
|
||||
SV: '🇸🇻',
|
||||
ZH: '🇨🇳'
|
||||
};
|
||||
|
||||
|
||||
commands.push({
|
||||
name: "toen",
|
||||
@@ -15,7 +46,7 @@ commands.push({
|
||||
{
|
||||
type: "STRING",
|
||||
name: "text",
|
||||
description: "Text",
|
||||
description: "Text to translate",
|
||||
required: true
|
||||
}
|
||||
],
|
||||
@@ -29,16 +60,65 @@ commands.push({
|
||||
{
|
||||
type: "STRING",
|
||||
name: "text",
|
||||
description: "Text",
|
||||
description: "Text to translate",
|
||||
required: true
|
||||
}
|
||||
],
|
||||
exec: i => t(i, "JA")
|
||||
});
|
||||
commands.push({
|
||||
name: "tolang",
|
||||
description: "Translate text to any language",
|
||||
global: true,
|
||||
options: [
|
||||
{
|
||||
type: "STRING",
|
||||
name: "lang",
|
||||
description: "Language to translate to",
|
||||
required: true,
|
||||
choices: [
|
||||
{ name: 'Bulgarian', value: 'BG' },
|
||||
{ name: 'Czech', value: 'CS' },
|
||||
{ name: 'Danish', value: 'DA' },
|
||||
{ name: 'German', value: 'DE' },
|
||||
{ name: 'Greek', value: 'EL' },
|
||||
{ name: 'English (British)', value: 'EN-GB' },
|
||||
{ name: 'English (American)', value: 'EN-US' },
|
||||
{ name: 'Spanish', value: 'ES' },
|
||||
{ name: 'Estonian', value: 'ET' },
|
||||
{ name: 'Finnish', value: 'FI' },
|
||||
{ name: 'French', value: 'FR' },
|
||||
{ name: 'Hungarian', value: 'HU' },
|
||||
{ name: 'Italian', value: 'IT' },
|
||||
{ name: 'Japanese', value: 'JA' },
|
||||
{ name: 'Lithuanian', value: 'LT' },
|
||||
{ name: 'Latvian', value: 'LV' },
|
||||
{ name: 'Dutch', value: 'NL' },
|
||||
{ name: 'Polish', value: 'PL' },
|
||||
// { name: 'Portuguese (all Portuguese varieties excluding Brazilian Portuguese)', value: 'PT-PT' },
|
||||
{ name: 'Portuguese (Brazilian)', value: 'PT-BR' },
|
||||
{ name: 'Romanian', value: 'RO' },
|
||||
{ name: 'Russian', value: 'RU' },
|
||||
{ name: 'Slovak', value: 'SK' },
|
||||
{ name: 'Slovenian', value: 'SL' },
|
||||
{ name: 'Swedish', value: 'SV' },
|
||||
{ name: 'Chinese', value: 'ZH' }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "STRING",
|
||||
name: "text",
|
||||
description: "Text to translate",
|
||||
required: true
|
||||
}
|
||||
],
|
||||
exec: i => t(i, i.options.getString("lang"))
|
||||
});
|
||||
|
||||
async function t(i, target_lang) {
|
||||
var text = i.options.getString("text");
|
||||
await i.deferReply();
|
||||
|
||||
try {
|
||||
var translation = (await deepl({
|
||||
text,
|
||||
@@ -49,18 +129,24 @@ async function t(i, target_lang) {
|
||||
} catch (error) {
|
||||
return void await i.editReply(error.message);
|
||||
}
|
||||
if (translation.detected_source_language == "JA") {
|
||||
try {
|
||||
var input_romaji = await kuroshiro.convert(text, {to: "romaji", mode: "spaced"});
|
||||
} catch (error) {}
|
||||
}
|
||||
if (target_lang == "JA") {
|
||||
try {
|
||||
var output_romaji = await kuroshiro.convert(translation.text, {to: "romaji", mode: "spaced"});
|
||||
} catch (error) {}
|
||||
}
|
||||
let msg = `${text}${input_romaji ? `\n${input_romaji}` : ''}\n${translation.text}${output_romaji ? `\n${output_romaji}` : ''}`;
|
||||
|
||||
if (translation.detected_source_language == "JA") try {
|
||||
var input_romaji = await kuroshiro.convert(text, {to: "romaji", mode: "spaced"});
|
||||
} catch (error) {}
|
||||
if (target_lang == "JA") try {
|
||||
var output_romaji = await kuroshiro.convert(translation.text, {to: "romaji", mode: "spaced"});
|
||||
} catch (error) {}
|
||||
|
||||
let input_flag = lang2flag[translation.detected_source_language] || `[${translation.detected_source_language}]`;
|
||||
let output_flag = lang2flag[target_lang] || `[${target_lang}]`;
|
||||
|
||||
let msg = input_flag + ' ' + text;
|
||||
if (input_romaji) msg += '\n' + input_flag + ' ' + input_romaji;
|
||||
msg += '\n' + output_flag + ' ' + translation.text;
|
||||
if (output_romaji) msg += '\n' + output_flag + ' ' + output_romaji;
|
||||
|
||||
await i.editReply(msg);
|
||||
|
||||
try {
|
||||
var reverse_translation = (await deepl({
|
||||
text: translation.text,
|
||||
@@ -68,13 +154,15 @@ async function t(i, target_lang) {
|
||||
free_api: true,
|
||||
auth_key: config.deepl_auth_key
|
||||
})).data.translations[0];
|
||||
if (text.toLowerCase() != reverse_translation.text.toLowerCase()){
|
||||
if (translation.detected_source_language == "JA") {
|
||||
try {
|
||||
var reverse_romaji = await kuroshiro.convert(reverse_translation.text, {to: "romaji", mode: "spaced"});
|
||||
} catch (error) {}
|
||||
}
|
||||
if (normalize(text) != normalize(reverse_translation.text)){
|
||||
if (translation.detected_source_language == "JA") try {
|
||||
var reverse_romaji = await kuroshiro.convert(reverse_translation.text, {to: "romaji", mode: "spaced"});
|
||||
} catch (error) {}
|
||||
await i.editReply(`${msg}\n🔁 ${reverse_translation.text}${reverse_romaji ? `\n🔁 ${reverse_romaji}` : ''}`);
|
||||
}
|
||||
} catch(error) {}
|
||||
}
|
||||
|
||||
function normalize(text) {
|
||||
return text.toLowerCase()//.split('').filter(x => x.match(/[a-z0-9 ]/)).join('');
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ client.once("ready", () => {
|
||||
(function clock() {
|
||||
var d = new Date();
|
||||
for (let x of config.world_clock) {
|
||||
let t = Intl.DateTimeFormat("en", {
|
||||
let t = x.flag + ' ' + Intl.DateTimeFormat("en", {
|
||||
timeZone: x.timezone,
|
||||
hour: 'numeric',
|
||||
//minute: 'numeric',
|
||||
|
||||
Reference in New Issue
Block a user