This commit is contained in:
Lio Young 2021-04-04 17:17:46 +02:00
parent 77e22c837f
commit 749f37c337
No known key found for this signature in database
GPG Key ID: 789795A11879E169
22 changed files with 909 additions and 1117 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
config.ts
node_modules/
node_modules/
build/

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Lio Young
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,11 +1,11 @@
# Thaldrin
Repo for Thaldrin V4, completely rewritten in [auguwu/wumpcord](https://github.com/auguwu/wumpcord)
# Licence
None yet, but Credit me if you use parts of my code.
Repo for Thaldrin v4, rewritten entirely based on his previous code.
# Authors
- Lio Melio - *Owner/Developer* - [@HimboLion](https://twitter.com/HimboLion)
- Lio Melio - _Owner/Developer_ - [@HimboLion](https://twitter.com/HimboLion)
# License
**Thaldrin** is released under the [MIT](/LICENSE) License

8
index.ts Normal file
View File

@ -0,0 +1,8 @@
//@ts-ignore
import config from "./config";
import client from "./src/handler/client/Client"
import { Util } from "discord.js";
Util.fetchRecommendedShards(config.token).then((count) => {
console.log(`Starting ${config.variables.name}`)
new client(config, count)
})

1447
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,32 @@
{
"name": "thaldrin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc",
"start": "node build/index.js",
"dev": "rm -r build && npm run build && npm run start"
},
"repository": {
"type": "git",
"url": "git+https://github.com/thaldrin/thaldrin.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/thaldrin/thaldrin/issues"
},
"homepage": "https://github.com/thaldrin/thaldrin#readme",
"dependencies": {
"@sniff/armpits": "^0.0.6",
"axios": "^0.21.1",
"leeks.js": "^0.0.9",
"util": "^0.12.3",
"wumpcord": "^1.0.4"
"@supabase/supabase-js": "^1.7.7",
"@thaldrin/sourcefinder": "^1.0.0",
"discord.js": "^12.5.1",
"yiff": "^3.0.2"
},
"devDependencies": {
"@types/node": "^14.14.20"
"@types/node": "^14.14.37",
"@types/ws": "^7.4.1"
}
}

27
src/events/message.ts Normal file
View File

@ -0,0 +1,27 @@
import { Client, Collection, Message } from "discord.js";
import supabase from "../utils/database";
import { Server } from "../utils/types";
export = {
name: "message",
run: async (client: Client, message: Message) => {
if (message.author.bot) return
if (message.channel.type === "dm") return
// @ts-ignore
// console.log(client.guilds.cache.size)
client.guilds.cache.forEach(guild => {
console.log(`${guild.name} | ${guild.id}`)
})
// let { data, error } = await supabase.from<Server>("servers").select().eq(`server_id`, message.guild.id)
// if (data?.length === 0) await supabase.from<Server>("servers").insert({
// server_id: message.guild?.id
// })
// console.log(message.guild?.name, data)
}
}

9
src/events/ready.ts Normal file
View File

@ -0,0 +1,9 @@
import config from "../../config"
export = {
name: "ready",
run: async (client: any) => {
console.log(`${config.variables.name} has started.`)
}
}

61
src/handler/client/Client.ts Executable file
View File

@ -0,0 +1,61 @@
import { Client, Collection } from "discord.js";
import { readdirSync as read } from "fs";
import path from "path";
// const server = require('../../website/server');
export default class Thaldrin extends Client {
commands: Collection<unknown, unknown>;
cooldowns: Collection<unknown, unknown>;
config: any;
lastEval: any;
constructor(config: { token: any; }, shards: number) {
super({
// disableEveryone: true,
// disabledEvents: ['TYnpm i --save-dev @types/wsPING_START'],
shardCount: shards,
// totalShardCount: shards
});
this.commands = new Collection();
this.cooldowns = new Collection();
// this.queues = new Collection();
this.config = config;
this.lastEval = null;
this.login(config.token);
this.load();
}
async load() {
const events = await read(path.join(__dirname, '../../events'));
const modules = await read(path.join(__dirname, '../../modules'));
// server(this);
events.filter((f) => f.endsWith('.js')).forEach((file) => {
try {
const event = require(path.join(__dirname, '../../events', file));
this.on(event.name, event.run.bind(null, this));
} catch (err) {
console.error(err);
}
});
modules.filter((f) => !f.endsWith('.js')).forEach(async (module) => {
const commands = await read(path.join(__dirname, '../../modules', module));
commands.filter((f) => f.endsWith('.js')).forEach((command) => {
try {
const file = require(path.join(__dirname, '../../modules', module, command));
const Command = new file();
Command.module = module
this.commands.set(Command.name, Command);
} catch (err) {
console.error(err);
}
});
});
}
};

View File

@ -0,0 +1,14 @@
module.exports = class Command {
constructor(command) {
this.name = command.name || "";
this.description = command.description || "";
this.aliases = command.aliases || [];
this.module = command.module || "";
this.cooldown = command.cooldown || 0;
this.guild = command.guild || false;
this.dev = command.dev || false;
this.nsfw = command.nsfw || false;
this.AuthorPermissions = command.AuthorPermissions || "NONE";
this.hidden = command.hidden || false;
}
};

View File

@ -1,41 +0,0 @@
import { Client, MessageCreateEvent } from "wumpcord";
import config from "./config"
import { Shortlink } from "./utils/Message/shortlinks";
import { SourceFinder } from "./utils/Message/sourcefinder";
import Armpit from "@sniff/armpits";
const Armpits = new Armpit()
Armpits.info("Starting up...")
const client = new Client({
token: config.TOKEN,
interactions: true,
ws: { intents: ['guilds', 'guildMessages'] }
});
// Ignore the @ts-ignore lines, those are because of
// inconsistent Typings within Wumpcord at the time of writing these files
client.on('message', async (event: MessageCreateEvent) => {
if (event.message.author.bot) return;
// Grab Server Settings from Redis Cache before doing anything?
Shortlink(event, false)
SourceFinder(event, true)
// @ts-ignore
if (event.message.content === '!ping') return await event.message.channel.reply("pong")
});
client.on('ready', async () => {
console.log(`Connected as ${client.user.tag}!`);
client.setStatus('online', { // Sets it to "Competing in uwu"
type: 5,
name: 'uwu'
});
});
client.connect();

View File

@ -0,0 +1,30 @@
import Command from "../../handler/structures/Command";
export = class Eval extends Command {
constructor() {
super({
name: "Eval",
description: "Evaluate JS code directly from the process.",
aliases: [
'ev',
'e'
],
cooldown: 0,
dev: true,
guild: false
})
}
async command(ctx: any) {
let code = ctx.args.join(" ")
try {
let evaled = await eval(code)
if (typeof evaled != 'string') {
evaled = (await import("util")).inspect(evaled, false, 1)
}
return evaled
} catch (error) {
}
}
}

View File

@ -0,0 +1,19 @@
import Command from '../../handler/structures/Command';
export = class Info extends Command {
constructor() {
super({
name: "Info",
description: "Show Information about the Bot",
aliases: ["about"],
// module: "General",
cooldown: 0,
guildOnly: false,
dev: false
})
}
async command(ctx: any) {
return console.log("Information Command")
}
}

View File

@ -0,0 +1,19 @@
import Command from '../../handler/structures/Command';
export = class Wolf extends Command {
constructor() {
super({
name: "Wolf",
description: "Show a Wolf",
aliases: ["awoo"],
// module: "General",
cooldown: 0,
guildOnly: false,
dev: false
})
}
async command(ctx: any) {
return console.log("Wolf Command")
}
}

View File

@ -1,38 +0,0 @@
import axios from "axios";
import { MessageCreateEvent } from "wumpcord";
const md5 = new RegExp(
"((?:!)?https?://static[0-9]*.(?:e621|e926).net/data/(?:sample/|preview/|)[0-9a-f]{2}/[0-9a-f]{2}/([0-9a-f]{32}).([0-9a-z]+))",
"igm"
);
const search_md5 = "https://e621.net/posts.json?md5=";
const e6 = "https://e621.net/posts/";
const e9 = "https://e926.net/posts/";
const version = "0.3.0";
export async function SourceFinder(event: MessageCreateEvent, settings = true) {
if (!settings || settings === null || settings === undefined) return;
let Links = event.message.content.match(md5);
if (!Links) return;
let Sources: string[] = []
for (const index in Links) {
let ImageURL = Links[index]
let ImageHash = ImageURL.split(md5)[2]
let { data } = await axios.get(`${search_md5}${ImageHash}`, {
headers: {
"User-Agent": `SourceFinder/${version} by hokkqi (https://kji.tf/twitter)`
}
})
let source;
switch (data.rating) {
case 's':
source = `${e9}${data.post.id}`
break;
default:
source = `${e6}${data.post.id}`
break;
}
Sources.push(`<${source}>`)
}
return event.message.reply(`:link: :mag:\n${Sources.join('\n')}`)
}

7
src/utils/database.ts Normal file
View File

@ -0,0 +1,7 @@
import { createClient } from '@supabase/supabase-js'
import config from '../../config'
import { Server } from "./types";
const supabase = createClient(config.supabase.url, config.supabase.key)
export default supabase

View File

@ -1,123 +0,0 @@
/**
* Copyright (c) 2020-2021 August
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { inspect } from 'util';
import leeks from 'leeks.js';
// List of colors for the log levels
const Colors = {
debug: leeks.hex('#4F7CA3', '[Debug]'),
error: leeks.hex('#FF2255', '[Error]'),
warn: leeks.hex('#FFFFC5', '[Warn]'),
info: leeks.hex('#BCD9FF', '[Info]')
} as const;
type LogMessage = string | object | Error | any[] | Date | null | undefined | number | boolean;
enum LogLevel {
Info = 'info',
Warn = 'warn',
Error = 'error',
Debug = 'debug'
}
export default class Logger {
/** The logger's name */
private name: string;
/**
* Creates a new [Logger] instance
* @param name The name of the [Logger]
*/
constructor(name: string) {
this.name = name;
}
private _getDate() {
const current = new Date();
const hours = current.getHours();
const minutes = current.getMinutes();
const seconds = current.getSeconds();
const month = current.getMonth() + 1;
const day = current.getDate();
const year = current.getFullYear();
return leeks.colors.gray(`[${day}/${month}/${year} @ ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}]`);
}
private _formatMessage(...messages: LogMessage[]): string {
return messages.map<string>((message: unknown) => {
if ([null, undefined].includes(<any>message)) return leeks.colors.cyan(message === null ? 'null' : 'undefined');
if (message instanceof Array) return message.join('\n');
if (message instanceof Date) return leeks.colors.cyan(message.toUTCString());
if (message instanceof Error) {
const e = [`${message.name}: ${message.message}`];
const stack = message.stack ? message.stack.split('\n').map(s => s.trim()) : [];
stack.shift();
const all = stack.map(s => {
if (/(.+(?=)|.+) ((.+):\d+|[:\d+])[)]/g.test(s)) return s.match(/(.+(?=)|.+) ((.+):\d+|[:\d+])[)]/g)![0];
if (/(.+):\d+|[:\d+][)]/g.test(s)) return s.match(/(.+):\d+|[:\d+][)]/g)![0];
return s;
});
e.push(...all.map(item => ` • "${item.replace('at', '').trim()}"`));
return e.join('\n');
}
if (!['object', 'function', 'undefined', 'string'].includes(typeof message)) return leeks.colors.cyan(<any>message);
if (typeof message === 'object') return inspect(message, { depth: null });
return message as any;
}).join('\n');
}
private write(level: LogLevel, ...messages: LogMessage[]) {
const lvlText = Colors[level];
if (lvlText === undefined) throw new TypeError(`Invalid log level '${level}'`);
const message = this._formatMessage(...messages);
const name = leeks.hex('#F4A4D2', `[${this.name}]`);
const date = this._getDate();
const stream = level === LogLevel.Error ? process.stderr : process.stdout;
stream.write(`${date} ${name} ${lvlText} ${message}\n`);
}
info(...messages: LogMessage[]) {
return this.write(LogLevel.Info, ...messages);
}
warn(...messages: LogMessage[]) {
return this.write(LogLevel.Warn, ...messages);
}
error(...messages: LogMessage[]) {
return this.write(LogLevel.Error, ...messages);
}
debug(...messages: LogMessage[]) {
return this.write(LogLevel.Debug, ...messages);
}
}

View File

@ -1,22 +1,24 @@
// Initial code taken from @Cynosphere, rewritten by me
const Regex = /(?:\s|^)(gh|gl|yt|tw|npm|tv|bc|bcu|wc|sc|bot|fav|fau)\/([a-zA-Z0-9-_.#@/!]*)/g;
const Links = {
gh: "https://github.com/$link$",
gl: "https://gitlab.com/$link$",
yt: "https://youtu.be/$link$",
tw: "https://twitter.com/$link$",
npm: "https://npm.im/$link$",
tv: "https://twitch.tv/$link$",
bc: "https://$link$.bandcamp.com/",
bcu: "https://bandcamp.com/$link$",
wc: "https://werewolf.codes/$link$",
sc: "https://soundcloud.com/$link$",
const Links: {
[value: string]: string
} = {
"gh": "https://github.com/$link$",
"gl": "https://gitlab.com/$link$",
"yt": "https://youtu.be/$link$",
"tw": "https://twitter.com/$link$",
"npm": "https://npm.im/$link$",
"tv": "https://twitch.tv/$link$",
"bc": "https://$link$.bandcamp.com/",
"bcu": "https://bandcamp.com/$link$",
"wc": "https://werewolf.codes/$link$",
"sc": "https://soundcloud.com/$link$",
// fa: "https://furaffinity.net/$link$",
fav: "https://furaffinity.net/view/$link$",
fau: "https://furaffinity.net/user/$link$",
bot: "https://discordapp.com/oauth2/authorize?client_id=$link$&scope=bot"
"fav": "https://furaffinity.net/view/$link$",
"fau": "https://furaffinity.net/user/$link$",
"bot": "https://discordapp.com/oauth2/authorize?client_id=$link$&scope=bot"
};
export const SiteNames = {
const SiteNames = {
gh: "Github",
gl: "Gitlab",
gd: "Gitdab",
@ -33,11 +35,11 @@ export const SiteNames = {
bot: "Bot Invites",
wc: "werewolf.codes"
};
import { MessageCreateEvent } from "wumpcord";
export async function Shortlink(event: MessageCreateEvent, settings: boolean) {
export async function Shortlink(content: string, settings: boolean) {
let Possible: string[] = []
if (!settings || settings === null || settings === undefined) return;
let res = event.message.content.match(Regex)
if (!settings) return;
let res = content.match(Regex)
console.log(res)
if (!res) return;
res = res.map(x => (x.startsWith(' ') ? x.substring(1) : x))
@ -51,6 +53,6 @@ export async function Shortlink(event: MessageCreateEvent, settings: boolean) {
}
}
// @ts-ignore
return event.message.channel.send(Possible.join('\n'))
return Possible.join('\n')
}

View File

@ -0,0 +1,6 @@
import Sourcefinder from "@thaldrin/sourcefinder";
import config from "../../config";
const sourcefinder = new Sourcefinder(`Thaldrin/v${config.pkg.version} (t8.pm/bot)`)
export default sourcefinder

17
src/utils/types.ts Normal file
View File

@ -0,0 +1,17 @@
export type CommandContext = {
}
export type Server = {
id: string
server_id: string
prefix: string[]
locale: string
shortlinks: boolean
embeds: boolean
source: boolean
interactiontext: boolean
}

View File

@ -1,20 +1,26 @@
{
"compilerOptions": {
"target": "ES2019",
"module": "CommonJS",
"lib": ["ES2015", "ES2016", "ES2017", "ES2018", "ES2019", "ES2020", "ESNext"],
"declaration": false,
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"noImplicitAny": false,
"moduleResolution": "node",
"types": ["node"],
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "./build",
"allowJs": true,
"target": "ESNext",
"baseUrl": "src",
"resolveJsonModule": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"module": "commonjs",
"paths": {},
"typeRoots": ["./node_modules/@types"],
"inlineSourceMap": true,
"charset": "UTF-8",
"downlevelIteration": true,
"newLine": "lf",
"strict": true,
"strictBindCallApply": true,
"strictPropertyInitialization": false,
"declaration": true
},
"include": ["**/*"],
"exclude": ["node_modules", "build", "out", "tmp", "logs", "test"]
}

4
variables.ts Normal file
View File

@ -0,0 +1,4 @@
export default {
name: "Panthera",
prefix: ['thal', "<@434662676547764244>", "<@!434662676547764244>"],
}