2023-09-10 09:35:51 +00:00
|
|
|
// @ts-check
|
|
|
|
|
|
|
|
const DiscordTypes = require("discord-api-types/v10")
|
|
|
|
const Ty = require("../../types")
|
|
|
|
const assert = require("assert").strict
|
|
|
|
const {PNG} = require("pngjs")
|
|
|
|
|
|
|
|
const passthrough = require("../../passthrough")
|
2023-09-18 10:51:59 +00:00
|
|
|
const {sync, db, discord, select} = passthrough
|
2023-09-10 09:35:51 +00:00
|
|
|
/** @type {import("../../matrix/file")} */
|
|
|
|
const file = sync.require("../../matrix/file")
|
|
|
|
//** @type {import("../../matrix/mreq")} */
|
|
|
|
const mreq = sync.require("../../matrix/mreq")
|
|
|
|
|
|
|
|
const SIZE = 160 // Discord's display size on 1x displays is 160
|
|
|
|
|
|
|
|
const INFO = {
|
|
|
|
mimetype: "image/png",
|
|
|
|
w: SIZE,
|
|
|
|
h: SIZE
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef RlottieWasm
|
|
|
|
* @prop {(string) => boolean} load load lottie data from string of json
|
|
|
|
* @prop {() => number} frames get number of frames
|
|
|
|
* @prop {(frameCount: number, width: number, height: number) => Uint8Array} render render lottie data to bitmap
|
|
|
|
*/
|
|
|
|
|
|
|
|
const Rlottie = (async () => {
|
|
|
|
const Rlottie = require("./rlottie-wasm.js")
|
|
|
|
await new Promise(resolve => Rlottie.onRuntimeInitialized = resolve)
|
|
|
|
return Rlottie
|
|
|
|
})()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {DiscordTypes.APIStickerItem} stickerItem
|
2023-10-04 23:32:05 +00:00
|
|
|
* @returns {Promise<{mxc_url: string, info: typeof INFO}>}
|
2023-09-10 09:35:51 +00:00
|
|
|
*/
|
|
|
|
async function convert(stickerItem) {
|
2023-10-05 23:31:10 +00:00
|
|
|
const existingMxc = select("lottie", "mxc_url", {sticker_id: stickerItem.id}).pluck().get()
|
2023-10-04 23:32:05 +00:00
|
|
|
if (existingMxc) return {mxc_url: existingMxc, info: INFO}
|
2023-09-10 09:35:51 +00:00
|
|
|
const r = await Rlottie
|
|
|
|
const res = await fetch(file.DISCORD_IMAGES_BASE + file.sticker(stickerItem))
|
|
|
|
if (res.status !== 200) throw new Error("Sticker data file not found.")
|
|
|
|
const text = await res.text()
|
|
|
|
/** @type RlottieWasm */
|
|
|
|
const rh = new r.RlottieWasm()
|
|
|
|
const status = rh.load(text)
|
|
|
|
if (!status) throw new Error(`Rlottie unable to load ${text.length} byte data file.`)
|
|
|
|
const rendered = rh.render(0, SIZE, SIZE)
|
|
|
|
let png = new PNG({
|
|
|
|
width: SIZE,
|
|
|
|
height: SIZE,
|
|
|
|
bitDepth: 8, // 8 red + 8 green + 8 blue + 8 alpha
|
|
|
|
colorType: 6, // RGBA
|
|
|
|
inputColorType: 6, // RGBA
|
|
|
|
inputHasAlpha: true,
|
|
|
|
})
|
|
|
|
png.data = Buffer.from(rendered)
|
|
|
|
// @ts-ignore wrong type from pngjs
|
|
|
|
const readablePng = png.pack()
|
|
|
|
/** @type {Ty.R.FileUploaded} */
|
|
|
|
const root = await mreq.mreq("POST", "/media/v3/upload", readablePng, {
|
|
|
|
headers: {
|
|
|
|
"Content-Type": INFO.mimetype
|
|
|
|
}
|
|
|
|
})
|
|
|
|
assert(root.content_uri)
|
2023-10-04 23:32:05 +00:00
|
|
|
db.prepare("INSERT INTO lottie (sticker_id, mxc_url) VALUES (?, ?)").run(stickerItem.id, root.content_uri)
|
|
|
|
return {mxc_url: root.content_uri, info: INFO}
|
2023-09-10 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports.convert = convert
|