const ffmpeg = require('fluent-ffmpeg') const tmp = require('tmp') const fs = require('fs') const path = require('path') const canvas = require('canvas') const colorsys = require('colorsys') const { randomUUID } = require('crypto') const nbt = require('prismarine-nbt') const SNBT = require('../util/snbt.js') const toNBTUUID = require('./../util/uuid-to-nbt-uuid.js') const cnv = canvas.createCanvas(256, 144) const ctx = cnv.getContext('2d') function inject (bot) { const video = { nowPlaying: null, _interval: null, _tmpobj: null, play, stop, summon } bot.video = video async function play (input, uuids) { uuids ??= await summon(cnv.height) video._tmpobj = tmp.dirSync() bot.core.run('minecraft:tellraw @a ' + JSON.stringify('Extracting frames from the video...')) ffmpeg(input) .output(path.join(video._tmpobj.name, '%01d.bmp')) .fps(30) .size(cnv.width + 'x' + cnv.height) .on('error', (err) => bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: require('util').inspect(err).replace(/\n.*/g, ''), color: 'red' }))) .on('end', playVideo) .run() function playVideo () { bot.core.run('minecraft:tellraw @a ' + JSON.stringify('Now playing the video')) const frames = [] fs.readdirSync(video._tmpobj.name).forEach((filename) => { const filepath = path.join(video._tmpobj.name, filename) let num = filename // while (num.length !== 0 && !/\d/.test(num[0])) { // num = num.slice(1) // } num = parseInt(num) frames[num] = filepath }) let i = 0 video._interval = setInterval(async () => { const img = await canvas.loadImage(frames[i++]).catch(({ message }) => bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: message, color: 'red' }))) if (!(img ?? false)) return fs.unlink(frames[i - 1], () => {}) ctx.drawImage(img, 0, 0, cnv.width, cnv.height) const rgba = ctx.getImageData(0, 0, cnv.width, cnv.height).data let line = [] let k = 0 for (let j = 0; j < rgba.length; j += 4) { const r = rgba[j] const g = rgba[j + 1] const b = rgba[j + 2] const hex = colorsys.rgbToHex(r, g, b) if (line.length >= 1 && line[line.length - 1].color === hex) line[line.length - 1].text += '╷' else line.push({ text: '╷', color: hex }) if (((j / 4) % cnv.width) === 0) { bot.core.run(`minecraft:data modify entity ${uuids[k++]} CustomName set value ${SNBT.stringify(nbt.string(JSON.stringify(line)))}`) line = [] } } if (i >= frames.length) stop() }, 33.33333) } } function stop () { clearInterval(video._interval) video._tmpobj?.removeCallback() } function summon (amount) { return new Promise((resolve) => { const uuids = [] bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: 'Summoning armor stands...' })) video._interval = setInterval(() => { const uuid = randomUUID() bot.exploits.execute(`at _ChipMC_ run summon armor_stand ~ ~${uuids.length * -0.1} ~ ${SNBT.stringify(nbt.comp({ UUID: toNBTUUID(uuid), CustomNameVisible: nbt.byte(1), Invisible: nbt.byte(1), Marker: nbt.byte(1) }))}`) uuids.push(uuid) if (uuids.length >= amount) { clearInterval(video._interval) resolve(uuids) } }, 100) }) } } module.exports.bot = inject