imported trol bot

This commit is contained in:
Morphious86 2021-09-03 02:04:05 +03:00
parent f52ef43cd1
commit 408d1c07da
64 changed files with 2787 additions and 0 deletions

107
.gitignore vendored Normal file
View File

@ -0,0 +1,107 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# trol bot token
/token.js

BIN
images/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/alpha.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
images/bovid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
images/cereal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/chad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
images/cheems.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
images/circle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/cry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
images/dabloon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
images/dog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
images/egg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
images/emoji.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
images/epci.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
images/flamingo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
images/fridge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
images/gnome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
images/google.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
images/hamoud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
images/herbert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/horny.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/kanve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/lol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
images/moai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
images/muta.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/peter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
images/pewdiepie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
images/pollo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/pussy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/roblox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
images/roll.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/screm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/sike.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
images/society.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
images/sosad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
images/sound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/spy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
images/steve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/trol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
images/trol2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
images/walter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/whatsapp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
images/whiter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

92
index.js Normal file
View File

@ -0,0 +1,92 @@
const { Client, Intents, MessageEmbed } = require("discord.js");
const { generateVideo } = require("./shitpost.js");
const request = require("request");
const fs = require("fs");
const path = require('path');
const tempDir = "./temp";
const client = new Client({ intents: [Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILDS] });
// invite link for orig trolbot
// https://discord.com/api/oauth2/authorize?client_id=882394859179216896&scope=bot&permissions=3263552
client.login(require("./token.js"));
if (!fs.existsSync(tempDir))
fs.mkdir(tempDir);
else
fs.readdir(tempDir, (err, files) =>
{
for (const file of files)
{
const filepath = path.join(tempDir, file);
fs.rm(filepath, { recursive: true }, err => { if (err) { throw err; } })
}
});
client.once("ready", () =>
{
console.log("loaded trol bot");
});
client.on("messageCreate", (msg) =>
{
if (msg.author.bot) return;
const args = msg.content.split(/ +/);
const command = args.shift().toLowerCase();
if (command == "trol")
{
if (args[0] == "help")
{
const embed = new MessageEmbed()
.setColor("#ffffff")
.setTitle("trol helpy :^)")
.addFields(
{ name: "trol", value: "uses attachment (if any)" },
{ name: "trol <link>", value: "uses image link" },
{ name: "trol me", value: "uses sender's pfp" },
{ name: "trol <@mention>", value: "uses mentioned user's pfp" }
);
msg.channel.send({ embeds: [embed] });
}
else
{
var link = args[0];
var file = null;
if (msg.attachments.size == 1) file = msg.attachments.first().attachment;
if (link != null && file == null)
{
if (link == "me") file = msg.author.avatarURL({ format: "png" });
if (msg.mentions.users.size > 0) file = msg.mentions.users.values().next().value.avatarURL({ format: "png" });
if (file == null) file = link;
}
if (file != null)
{
const downloadDir = path.join(tempDir, "download");
if (!fs.existsSync(downloadDir))
fs.mkdirSync(downloadDir);
var tempFilePath = Path.join(downloadDir, `dl_${Math.floor(Math.random() * 10000).toString().padStart(4, "0")}`);
request.head(file, (err, res, body) =>
{
if (err)
{
console.log(err);
return;
}
request(file).pipe(fs.createWriteStream(tempFilePath)).on('close', () =>
{
generateVideo(tempFilePath, 5).then(result =>
msg.channel.send({ files: [result] }).then(value =>
fs.promises.rm(result)
)
);
});
});
}
}
}
});

2227
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "memeify",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"canvas": "^2.8.0",
"discord.js": "^13.1.0",
"merge-audio-buffers": "^1.0.0",
"node-wav": "^0.0.2",
"path": "^0.12.7",
"request": "^2.88.2"
}
}

124
shitpost-audio.js Normal file
View File

@ -0,0 +1,124 @@
const fs = require("fs");
const wav = require("node-wav");
const path = require("path");
const tempDir = "./temp";
const soundDir = "./sounds";
const soundPaths = fs.readdirSync("sounds");
let loadedSounds = [];
let offset = 0;
for (let p in soundPaths)
{
const soundPath = path.join(soundDir, soundPaths[p]);
if (fs.statSync(soundPath).isDirectory())
{
offset++;
continue;
}
let buffer = fs.readFileSync(soundPath);
let decoded = wav.decode(buffer);
loadedSounds[p - offset] = decoded;
}
// somehow this works
// idk how to merge audio of different sample rates
// i tried looking it up and didn't find anything
// so i just made sure the sound files were exported with 48000 bytes per second
async function mergeBuffers (buffers, playtime = -1)
{
// for the final length, either use the specified playtime, or the length of the first sound
let length = playtime > 0 ? playtime * 48000 : buffers[0].length;
let finalBuffer = [];
for (let f_nr = 0; f_nr < length; f_nr++)
{
// literally add all the sound bytes together
// yeah, this works??
let value = 0;
for (let buffer of buffers)
if (buffer[f_nr]) value += buffer[f_nr];
finalBuffer.push(value);
}
return Float32Array.from(finalBuffer);
}
class MemeAudio
{
constructor()
{
this.tracks = [];
}
playSound (soundId, position = 0, track = -1)
{
// track not specified, go up one from previous
if (track < 0)
track = this.tracks.length;
// track doesn't exist, initialize a new one
let stereoTrackBuffer = this.tracks[track];
if (!this.tracks[track])
stereoTrackBuffer = [[], []];
// get the data of the sound to play
let sound = loadedSounds[soundId];
for (let ch in stereoTrackBuffer) // should just be left/right audio channels
{
let loadedChannel = sound.channelData[ch];
let byteArray = [];
// add empty space until the sound should play
for (let i = 0; i < position * 48000; i++)
byteArray[i] = 0;
// copy audio data from sound's channel
for (let byte of loadedChannel)
byteArray.push(byte);
// convert to Float32array
stereoTrackBuffer[ch] = Float32Array.from(byteArray);
}
// add to timeline
this.tracks[track] = stereoTrackBuffer;
return this;
}
async encode (duration)
{
let ac = { sampleRate: 48000, float: true, bitDepth: 32 }; // encoding config
// make an array of all left channel audio and all right channel audio
let combinedTrack = [[], []];
for (let track in this.tracks)
{
combinedTrack[0].push(this.tracks[track][0]);
combinedTrack[1].push(this.tracks[track][1]);
}
// make a single stereo track
let mergedTrack = await Promise.all([mergeBuffers(combinedTrack[0], duration), mergeBuffers(combinedTrack[1], duration)]);
let encoded = wav.encode(mergedTrack, ac);
return encoded;
}
}
async function generateAudio (seconds)
{
let audio = new MemeAudio();
let pos = 0;
while (pos < seconds)
{
audio.playSound(Math.floor(Math.random() * loadedSounds.length), pos);
pos += (Math.random() * 1) - 0.25;
}
let encoded = await audio.encode(seconds);
resultPath = path.join(tempDir, `snd_${Math.floor(Math.random() * 10000).toString().padStart(4, "0")}.wav`);
await fs.promises.writeFile(resultPath, encoded);
return resultPath;
}
module.exports = { generateAudio };

189
shitpost-video.js Normal file
View File

@ -0,0 +1,189 @@
const { createCanvas, loadImage } = require("canvas");
const fs = require("fs");
const tempDir = "./temp";
const imagesDir = "./images";
// load images
let initialized = false;
let images = [];
let imgPromises = [];
fs.promises.readdir(imagesDir).then(filenames =>
{
for (var filename of filenames)
imgPromises.push(loadImage(path.join(imagesDir, filename)).then(data => images.push(data)));
Promise.all(imgPromises).then(() => initialized = true);
});
async function generateFrames (sourceImagePath, duration)
{
if (!initialized)
return null;
let outputPath = path.join(tempDir, "frames_" + Math.floor(Math.random() * 10000).toString().padStart(4, "0"));
let sourceImage;
await Promise.all([
fs.promises.mkdir(outputPath),
loadImage(sourceImagePath).then(data => sourceImage = data)
]);
// settings
const fps = 20;
const res = 256;
const totalFrames = fps * duration;
// init timeline
let objects = [];
// define classes
class Object
{
constructor(arg = {})
{
this.imageId = arg.imageId || -1;
this.spawnFrame = arg.spawnFrame || 0;
this.lifetime = fps * duration;
this.pos = arg.pos || [0.5, 0.5];
this.scale = arg.scale || [1, 1];
this.pivot = arg.pivot || [0.5, 0.5];
this.rot = arg.rot || 0;
this.blink = false;
this.sineDur = 0;
this.actions = arg.actions || [];
objects.push(this);
}
}
class Action
{
constructor(arg = {})
{
this.type = arg.type;
this.delta = arg.delta;
this.start = arg.start || 0;
}
}
// generate timeline
const base = new Object();
if (randomChance(80)) base.actions.push(new Action({ type: "scale", delta: [randomRange(0, 0.1), randomRange(0, 0.05)] }));
for (i = 0; i < randomRange(2, 12); i++)
{
const obj = new Object();
obj.pos = [Math.random(), Math.random()];
const uniformScale = randomRange(0.1, 0.7);
obj.scale = [uniformScale + Math.random() * 0.01, uniformScale + Math.random() * 0.01];
obj.imageId = Math.floor(Math.random() * images.length);
obj.spawnFrame = Math.floor(Math.random() * totalFrames);
obj.lifetime = randomRange(fps * 0.25, fps * 3);
obj.pivot = [Math.random(), Math.random()];
if (randomChance(25))
obj.actions.push(new Action({ type: "rotate", delta: randomRange(-8, 8) }))
if (randomChance(25))
obj.actions.push(new Action({ type: "scale", delta: [randomRange(0, 0.05), 0] }))
if (randomChance(25))
obj.blink = true;
else if (randomChance(25))
obj.actions.push(new Action({ type: "move", delta: [randomRange(-0.05, 0.05), randomRange(-0.05, 0.05)] }))
if (randomChance(75))
obj.sineDur = randomRange(1, 5);
}
// sort by spawnframe
objects.sort((a, b) => (a.spawnFrame > b.spawnFrame) ? 1 : -1);
// render frames
let framePromises = [];
for (var _f = 0; _f < totalFrames; _f++)
{
const f = _f;
framePromises.push(async () =>
{
const canvas = createCanvas(res, res);
const ctx = canvas.getContext("2d");
// draw objects
for (var object of objects)
{
var life = f - object.spawnFrame; // frames passed since init
if (life < 0) continue;
if (life > object.lifetime) continue;
if (object.blink && life % 2 == 1) continue;
var pos = object.pos;
var rot = object.rot;
var scale = object.scale;
var image = object.imageId == -1 ? sourceImage : images[object.imageId];
// process actions
for (var action of object.actions)
{
if (f < object.spawnFrame + action.start + 1 || ((action.dur > 0) && (f > object.spawnFrame + action.start + action.dur))) continue; // ignore
const progress = object.sineDur > 0 ? 10 * Math.sin(life * object.sineDur) : life;
switch (action.type)
{
case "move":
pos = [object.pos[0] + action.delta[0] * progress, object.pos[1] + action.delta[1] * progress];
break;
case "scale":
scale = [object.scale[0] + action.delta[0] * progress, object.scale[1] + action.delta[1] * progress];
break;
case "rotate":
rot = object.rot + action.delta * life;
break;
}
}
var size = [scale[0] * res, scale[1] * res]; // size in pixels
var cpos = [pos[0] * res, pos[1] * res]; // center pos
var blpos = [cpos[0] - size[0] * object.pivot[0], cpos[1] - size[1] * object.pivot[1]] // bottom left pos
// save base canvas transform
ctx.save();
// rotate canvas to match object rotation
ctx.translate(cpos[0], cpos[1]);
ctx.rotate(rot * Math.PI / 180);
ctx.translate(-cpos[0], -cpos[1]);
// draw
ctx.drawImage(image, blpos[0], blpos[1], size[0], size[1])
// restore transform
ctx.restore();
// save the frame
const buffer = canvas.toBuffer("image/png");
await fs.promises.writeFile(path.join(outputPath, `${f}.png"`), buffer);
}
});
}
await Promise.all(framePromises.map(fn => fn()));
return outputPath;
}
function randomRange (x, y)
{
return Math.random() * (y - x) + x;
}
function randomChance (percent)
{
return (Math.random() * 100) <= percent;
}
module.exports = { generateFrames };

29
shitpost.js Normal file
View File

@ -0,0 +1,29 @@
const { generateAudio } = require("./shitpost-audio.js");
const { generateFrames } = require("./shitpost-video.js");
const { spawn } = require("child_process");
const fs = require("fs");
async function generateVideo (sourceImg, duration)
{
let [framesPath, audioPath] = await Promise.all([
generateFrames(sourceImg, duration),
generateAudio(duration)
]);
const outputPath = `./temp/output_${Math.floor(Math.random() * 10000).toString().padStart(4, "0")}.mp4`;
const child = spawn(`ffmpeg -i ${audioPath} -r 20 -i ${framesPath}/%d.png -c:v libx264 -vf fps=20 -pix_fmt yuv420p ${outputPath}`, { shell: true })
child.on("exit", (code) => { finished = true; });
let finished = false;
while (!finished) await new Promise(resolve => setTimeout(resolve, 10));
// delete temp files
fs.promises.rm(framesPath, { recursive: true });
fs.promises.rm(audioPath);
fs.promises.rm(sourceImg);
return outputPath;
}
module.exports = { generateVideo };

BIN
sounds/21.wav Normal file

Binary file not shown.

BIN
sounds/bababoey.wav Normal file

Binary file not shown.

BIN
sounds/bell.wav Normal file

Binary file not shown.

BIN
sounds/bonk.wav Normal file

Binary file not shown.

BIN
sounds/bruh.wav Normal file

Binary file not shown.

BIN
sounds/bwomp.wav Normal file

Binary file not shown.

BIN
sounds/fart.wav Normal file

Binary file not shown.

BIN
sounds/fart2.wav Normal file

Binary file not shown.

BIN
sounds/gnome.wav Normal file

Binary file not shown.

BIN
sounds/kill.wav Normal file

Binary file not shown.

BIN
sounds/nokia.wav Normal file

Binary file not shown.

BIN
sounds/puebes.wav Normal file

Binary file not shown.

BIN
sounds/revfart.wav Normal file

Binary file not shown.

BIN
sounds/sus.wav Normal file

Binary file not shown.

BIN
sounds/thump.wav Normal file

Binary file not shown.