Compare commits

...

2 commits

12 changed files with 201 additions and 75 deletions

3
.gitignore vendored
View file

@ -1 +1,2 @@
.env
.env
cai.token

View file

@ -1,6 +1,6 @@
{
"tasks": {
"dev": "deno run --watch --allow-env --allow-read=. --allow-net --env-file main.ts",
"deployCommands": "deno run --env-file --allow-env --allow-net --allow-read=./commands scripts/deployCommands.ts"
"dev": "deno run --watch --allow-env --allow-read=. --allow-net --env-file ./src/main.ts",
"deployCommands": "deno run --env-file --allow-env --allow-net --allow-read=./src/ scripts/deployCommands.ts"
}
}

74
deno.lock generated
View file

@ -1,16 +1,28 @@
{
"version": "4",
"version": "5",
"specifiers": {
"jsr:@std/fs@*": "1.0.18",
"jsr:@std/path@*": "1.1.0",
"jsr:@std/path@^1.1.0": "1.1.0",
"npm:@types/node@*": "22.12.0",
"npm:cainode@latest": "1.2.2",
"npm:discord.js@*": "14.20.0"
},
"jsr": {
"@std/fs@1.0.18": {
"integrity": "24bcad99eab1af4fde75e05da6e9ed0e0dce5edb71b7e34baacf86ffe3969f3a",
"dependencies": [
"jsr:@std/path@^1.1.0"
]
},
"@std/path@1.1.0": {
"integrity": "ddc94f8e3c275627281cbc23341df6b8bcc874d70374f75fec2533521e3d6886"
}
},
"npm": {
"@bufbuild/protobuf@2.5.2": {
"integrity": "sha512-foZ7qr0IsUBjzWIq+SuBLfdQCpJ1j8cTuNNT4owngTHoN5KsJb8L9t65fzz7SCeSWzescoOil/0ldqiL041ABg=="
},
"@discordjs/builders@1.11.2": {
"integrity": "sha512-F1WTABdd8/R9D1icJzajC4IuLyyS8f3rTOz66JsSI3pKvpCAtsMBweu8cyNYsIyvcrKAVn9EPK+Psoymq+XC0A==",
"dependencies": [
@ -66,6 +78,52 @@
"ws"
]
},
"@livekit/mutex@1.1.1": {
"integrity": "sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw=="
},
"@livekit/rtc-node-darwin-arm64@0.11.1": {
"integrity": "sha512-M+Ui87H06ae19GGI7r937dS6hI84MBBTQAkkNlL7qd+pvdCAk25u0FYa8r4SOElKJ0VR3AbzeDoXTihLgpvjMg==",
"os": ["darwin"],
"cpu": ["arm64"]
},
"@livekit/rtc-node-darwin-x64@0.11.1": {
"integrity": "sha512-7G92fyuK2p+jdTH2cUJTNeAmtknTGsXuy0xbI727V7VzQvHFDXULCExRlgwn4t9TxvNlIjUpiltiQ6RCSai6zw==",
"os": ["darwin"],
"cpu": ["x64"]
},
"@livekit/rtc-node-linux-arm64-gnu@0.11.1": {
"integrity": "sha512-vqZN9+87Pvxit7auYVW69M+GvUPnf+EwipIJ92GgCJA3Ir1Tcceu5ud5/Ic+0FzSoV0cotVVlQNm74F0tQvyCg==",
"os": ["linux"],
"cpu": ["arm64"]
},
"@livekit/rtc-node-linux-x64-gnu@0.11.1": {
"integrity": "sha512-smHZUMfgILQh6/eoauYNe/VlKwQCp4/4jWxiIADHY+mtDtVSvQ9zB6y4GP8FrpohRwFWesKCUpvPBypU0Icrng==",
"os": ["linux"],
"cpu": ["x64"]
},
"@livekit/rtc-node-win32-x64-msvc@0.11.1": {
"integrity": "sha512-bTWVtb+UiRPFjiuhrqq40gt5vs5mMPTa1e+kd2jGQPTOlKZPLArQ0WgFcep2TAy1zmcpOgfeM1XRPVFhZl7G1A==",
"os": ["win32"],
"cpu": ["x64"]
},
"@livekit/rtc-node@0.11.1": {
"integrity": "sha512-EFw+giPll12fcXATZpN2zKkE3umYJAdHvfjW+Yu0aBjwfxbUBXu8rz6le2CzDNvGmRwR888DSZXFZfYikwZgiw==",
"dependencies": [
"@bufbuild/protobuf",
"@livekit/mutex",
"@livekit/typed-emitter"
],
"optionalDependencies": [
"@livekit/rtc-node-darwin-arm64",
"@livekit/rtc-node-darwin-x64",
"@livekit/rtc-node-linux-arm64-gnu",
"@livekit/rtc-node-linux-x64-gnu",
"@livekit/rtc-node-win32-x64-msvc"
]
},
"@livekit/typed-emitter@3.0.0": {
"integrity": "sha512-9bl0k4MgBPZu3Qu3R3xy12rmbW17e3bE9yf4YY85gJIQ3ezLEj/uzpKHWBsLaDoL5Mozz8QCgggwIBudYQWeQg=="
},
"@sapphire/async-queue@1.5.5": {
"integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="
},
@ -94,6 +152,14 @@
"@vladfrangu/async_event_emitter@2.4.6": {
"integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="
},
"cainode@1.2.2": {
"integrity": "sha512-x73+JgjAJOjuNJYpRXqbET86sDuEY8pcCmC55oCZWi3Vfh9wxoPWWldTxWhmuYD2A71jGNu20UB8A70nf3Q43A==",
"optionalDependencies": [
"@livekit/rtc-node",
"ws"
],
"scripts": true
},
"discord-api-types@0.38.12": {
"integrity": "sha512-vqkRM50N5Zc6OVckAqtSslbUEoXmpN4bd9xq2jkoK9fgO3KNRIOyMMQ7ipqjwjKuAgzWvU6G8bRIcYWaUe1sCA=="
},
@ -140,7 +206,11 @@
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="
},
"ws@8.18.2": {
"integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="
"integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
"optionalPeers": [
"bufferutil@^4.0.1",
"utf-8-validate@>=5.0.2"
]
}
}
}

64
main.ts
View file

@ -1,64 +0,0 @@
import {
Client as _client,
ClientOptions,
Collection,
Events,
GatewayIntentBits,
MessageFlags,
} from "npm:discord.js";
const token = Deno.env.get("token");
import { Command } from "./types.ts";
import { gatherCommandsPaths } from "./commands.ts";
class Client extends _client {
commands: Collection<string, Command>;
constructor(options: ClientOptions) {
super(options);
this.commands = new Collection();
}
}
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
async function register(commandPath: string) {
const { default: command }: { default: Command } = await import(commandPath);
if ("data" in command && "execute" in command) {
client.commands.set(command.data.name, command);
console.log(`Registered ${command.data.name}.`);
} else {
console.log(
`[WARNING] The command at ${commandPath} is missing a required "data" or "execute" property.`
);
}
}
(await gatherCommandsPaths()).forEach(register)
client.once(Events.ClientReady, (readyClient) => {
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
});
client.on(Events.InteractionCreate, async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
console.error(error);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
} else {
await interaction.reply({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
}
}
});
client.login(token);

View file

@ -1,7 +1,7 @@
import { REST, RESTPostAPIChatInputApplicationCommandsJSONBody, Routes } from "npm:discord.js";
const { clientId, guildId, token } = Deno.env.toObject();
import { Command } from "../types.ts";
import { gatherCommandsPaths } from "../commands.ts";
import { Command } from "../src/types.ts";
import { gatherCommandsPaths } from "../src/commands.ts";
const commands: RESTPostAPIChatInputApplicationCommandsJSONBody[] = [];
async function register(commandPath: string) {

3
src/cai.ts Normal file
View file

@ -0,0 +1,3 @@
import { CAINode } from "npm:cainode@latest";
export default new CAINode()

View file

@ -8,10 +8,8 @@ export async function gatherCommandsPaths(): Promise<string[]> {
for await (const entry of commandsRoot) {
if (entry.isDirectory) {
const commandsFolderPath = path.join(foldersPath, entry.name);
const commandsFiles = (
await Array.fromAsync(Deno.readDir(commandsFolderPath))
).filter((file) => file.name.endsWith(".js"));
for (const file of commandsFiles) {
const commandsFiles = Deno.readDir(commandsFolderPath)
for await (const file of commandsFiles) {
const commandPath = path.join(commandsFolderPath, file.name);
commandsPath.push(commandPath);

View file

@ -0,0 +1,42 @@
import {
CacheType,
ChatInputCommandInteraction,
MessageFlags,
SlashCommandBuilder,
} from "npm:discord.js";
import cai from "../../cai.ts";
async function getToken() {
try {
await Deno.stat("./cai.token");
return await Deno.readFile("./cai.token");
} catch {
const token: string = await cai.generate_token("charcord.bot@gmail.com", 0);
await Deno.writeTextFile("./cai.token", token);
return token;
}
}
export default {
data: new SlashCommandBuilder()
.setName("login")
.setDescription("Login to character.ai"),
async execute(interaction: ChatInputCommandInteraction<CacheType>) {
if(cai.logged) {
await cai.logout()
}
await interaction.reply({
content: "Logging in...",
flags: MessageFlags.Ephemeral,
});
const token = await getToken();
await cai.login(token);
console.log(
`Logged in character.ai as ${cai.user.info.user.user.username}`
);
await interaction.followUp({
content: `Logged in character.ai as ${cai.user.info.user.user.username}`,
flags: MessageFlags.Ephemeral,
});
},
};

76
src/main.ts Normal file
View file

@ -0,0 +1,76 @@
import {
Client as _client,
ClientOptions,
Collection,
Events,
GatewayIntentBits,
MessageFlags,
} from "npm:discord.js";
const token = Deno.env.get("token");
import { Command } from "./types.ts";
import { gatherCommandsPaths } from "./commands.ts";
import { exists } from "jsr:@std/fs/exists";
import cai from "./cai.ts";
class Client extends _client {
commands: Collection<string, Command>;
constructor(options: ClientOptions) {
super(options);
this.commands = new Collection();
}
}
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
async function register(commandPath: string) {
const { default: command }: { default: Command } = await import(commandPath);
if ("data" in command && "execute" in command) {
client.commands.set(command.data.name, command);
} else {
console.log(
`[WARNING] The command at ${commandPath} is missing a required "data" or "execute" property.`
);
}
}
(await gatherCommandsPaths()).forEach(register);
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
console.error(error);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({
content: "There was an error while executing this command!",
flags: MessageFlags.Ephemeral,
});
} else {
await interaction.reply({
content: "There was an error while executing this command!",
flags: MessageFlags.Ephemeral,
});
}
}
});
client.once(Events.ClientReady, (readyClient) => {
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
});
if (await exists("./cai.token", { isFile: true })) {
await cai.login(await Deno.readTextFile("./cai.token"));
cai.logged = true;
console.log(`Logged in character.ai as ${cai.user.info.user.user.username}`);
}
client.login(token);

0
src/utils.ts Normal file
View file