chipmunkbot3/plugins/video.js

98 lines
3.5 KiB
JavaScript

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 = inject