Compare commits
No commits in common. "011889216b1116637ce4069372e61edf6bcb8637" and "8987107685f8748288be0e247163c5722195d2c3" have entirely different histories.
011889216b
...
8987107685
10 changed files with 37 additions and 152 deletions
|
@ -1,53 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
const DiscordTypes = require("discord-api-types/v10")
|
||||
const Ty = require("../../types")
|
||||
const assert = require("assert").strict
|
||||
|
||||
const passthrough = require("../../passthrough")
|
||||
const {sync, db, select} = passthrough
|
||||
/** @type {import("../../matrix/file")} */
|
||||
const file = sync.require("../../matrix/file")
|
||||
/** @type {import("../../matrix/mreq")} */
|
||||
const mreq = sync.require("../../matrix/mreq")
|
||||
/** @type {import("../converters/lottie")} */
|
||||
const convertLottie = sync.require("../converters/lottie")
|
||||
|
||||
const INFO = {
|
||||
mimetype: "image/png",
|
||||
w: convertLottie.SIZE,
|
||||
h: convertLottie.SIZE
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {DiscordTypes.APIStickerItem} stickerItem
|
||||
* @returns {Promise<{mxc_url: string, info: typeof INFO}>}
|
||||
*/
|
||||
async function convert(stickerItem) {
|
||||
// Reuse sticker if already converted and uploaded
|
||||
const existingMxc = select("lottie", "mxc_url", {sticker_id: stickerItem.id}).pluck().get()
|
||||
if (existingMxc) return {mxc_url: existingMxc, info: INFO}
|
||||
|
||||
// Fetch sticker data from Discord
|
||||
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()
|
||||
|
||||
// Convert to PNG (readable stream)
|
||||
const readablePng = await convertLottie.convert(text)
|
||||
|
||||
// Upload to MXC
|
||||
/** @type {Ty.R.FileUploaded} */
|
||||
const root = await mreq.mreq("POST", "/media/v3/upload", readablePng, {
|
||||
headers: {
|
||||
"Content-Type": INFO.mimetype
|
||||
}
|
||||
})
|
||||
assert(root.content_uri)
|
||||
|
||||
// Save the link for next time
|
||||
db.prepare("INSERT INTO lottie (sticker_id, mxc_url) VALUES (?, ?)").run(stickerItem.id, root.content_uri)
|
||||
return {mxc_url: root.content_uri, info: INFO}
|
||||
}
|
||||
|
||||
module.exports.convert = convert
|
|
@ -1,10 +1,25 @@
|
|||
// @ts-check
|
||||
|
||||
const stream = require("stream")
|
||||
const DiscordTypes = require("discord-api-types/v10")
|
||||
const Ty = require("../../types")
|
||||
const assert = require("assert").strict
|
||||
const {PNG} = require("pngjs")
|
||||
|
||||
const passthrough = require("../../passthrough")
|
||||
const {sync, db, discord, select} = passthrough
|
||||
/** @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
|
||||
|
@ -19,11 +34,16 @@ const Rlottie = (async () => {
|
|||
})()
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @returns {Promise<import("stream").Readable>}
|
||||
* @param {DiscordTypes.APIStickerItem} stickerItem
|
||||
* @returns {Promise<{mxc_url: string, info: typeof INFO}>}
|
||||
*/
|
||||
async function convert(text) {
|
||||
async function convert(stickerItem) {
|
||||
const existingMxc = select("lottie", "mxc_url", {sticker_id: stickerItem.id}).pluck().get()
|
||||
if (existingMxc) return {mxc_url: existingMxc, info: INFO}
|
||||
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)
|
||||
|
@ -38,12 +58,17 @@ async function convert(text) {
|
|||
inputHasAlpha: true,
|
||||
})
|
||||
png.data = Buffer.from(rendered)
|
||||
// The transform stream is necessary because PNG requires me to pipe it somewhere before this event loop ends
|
||||
const resultStream = png.pack()
|
||||
const p = new stream.PassThrough()
|
||||
resultStream.pipe(p)
|
||||
return p
|
||||
// @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)
|
||||
db.prepare("INSERT INTO lottie (sticker_id, mxc_url) VALUES (?, ?)").run(stickerItem.id, root.content_uri)
|
||||
return {mxc_url: root.content_uri, info: INFO}
|
||||
}
|
||||
|
||||
module.exports.convert = convert
|
||||
module.exports.SIZE = SIZE
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
const fs = require("fs")
|
||||
const stream = require("stream")
|
||||
const {test} = require("supertape")
|
||||
const {convert} = require("./lottie")
|
||||
|
||||
const WRITE_PNG = false
|
||||
|
||||
test("lottie: can convert and save PNG", async t => {
|
||||
const input = await fs.promises.readFile("test/res/lottie-bee.json", "utf8")
|
||||
const resultStream = await convert(input)
|
||||
/* c8 ignore next 3 */
|
||||
if (WRITE_PNG) {
|
||||
resultStream.pipe(fs.createWriteStream("test/res/lottie-bee.png"))
|
||||
t.fail("PNG written to /test/res/lottie-bee.png, please manually check it")
|
||||
} else {
|
||||
const expected = await fs.promises.readFile("test/res/lottie-bee.png")
|
||||
const actual = Buffer.alloc(expected.length)
|
||||
let i = 0
|
||||
await stream.promises.pipeline(
|
||||
resultStream,
|
||||
async function* (source) {
|
||||
for await (const chunk of source) {
|
||||
chunk.copy(actual, i)
|
||||
i += chunk.length
|
||||
}
|
||||
},
|
||||
new stream.PassThrough()
|
||||
)
|
||||
t.equal(i, actual.length, `allocated ${actual.length} bytes, but wrote ${i}`)
|
||||
t.deepEqual(actual, expected)
|
||||
}
|
||||
})
|
|
@ -12,8 +12,8 @@ const {sync, db, discord, select, from} = passthrough
|
|||
const file = sync.require("../../matrix/file")
|
||||
/** @type {import("./emoji-to-key")} */
|
||||
const emojiToKey = sync.require("./emoji-to-key")
|
||||
/** @type {import("../actions/lottie")} */
|
||||
const lottie = sync.require("../actions/lottie")
|
||||
/** @type {import("./lottie")} */
|
||||
const lottie = sync.require("./lottie")
|
||||
/** @type {import("../../m2d/converters/utils")} */
|
||||
const mxUtils = sync.require("../../m2d/converters/utils")
|
||||
/** @type {import("../../discord/utils")} */
|
||||
|
|
32
test/data.js
32
test/data.js
|
@ -1331,38 +1331,6 @@ module.exports = {
|
|||
name: "pomu puff"
|
||||
}]
|
||||
},
|
||||
lottie_sticker: {
|
||||
id: "1106366167788044450",
|
||||
type: 0,
|
||||
content: "",
|
||||
channel_id: "122155380120748034",
|
||||
author: {
|
||||
id: "113340068197859328",
|
||||
username: "Cookie 🍪",
|
||||
global_name: null,
|
||||
display_name: null,
|
||||
avatar: "b48302623a12bc7c59a71328f72ccb39",
|
||||
discriminator: "7766",
|
||||
public_flags: 128,
|
||||
avatar_decoration: null
|
||||
},
|
||||
attachments: [],
|
||||
embeds: [],
|
||||
mentions: [],
|
||||
mention_roles: [],
|
||||
pinned: false,
|
||||
mention_everyone: false,
|
||||
tts: false,
|
||||
timestamp: "2023-05-11T23:44:09.690000+00:00",
|
||||
edited_timestamp: null,
|
||||
flags: 0,
|
||||
components: [],
|
||||
sticker_items: [{
|
||||
id: "860171525772279849",
|
||||
format_type: 3,
|
||||
name: "8"
|
||||
}]
|
||||
},
|
||||
message_in_thread: {
|
||||
type: 0,
|
||||
tts: false,
|
||||
|
|
|
@ -103,9 +103,6 @@ INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES
|
|||
('!maggESguZBqGBZtSnr:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'),
|
||||
('!CzvdIdUQXgUjDVKxeU:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU');
|
||||
|
||||
INSERT INTO lottie (sticker_id, mxc_url) VALUES
|
||||
('860171525772279849', 'mxc://cadence.moe/ZtvvVbwMIdUZeovWVyGVFCeR');
|
||||
|
||||
INSERT INTO "auto_emoji" ("name","emoji_id","guild_id") VALUES
|
||||
('L1','1144820033948762203','529176156398682115'),
|
||||
('L2','1144820084079087647','529176156398682115'),
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,16 +0,0 @@
|
|||
# Source
|
||||
|
||||
Flying Bee by Afif Ridwan
|
||||
https://lottiefiles.com/animations/flying-bee-WkXvUiWkZ1
|
||||
|
||||
# License
|
||||
|
||||
Lottie Simple License (FL 9.13.21) https://lottiefiles.com/page/license
|
||||
|
||||
Copyright © 2021 Design Barn Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the public animation files available for download at the LottieFiles site (“Files”) to download, reproduce, modify, publish, distribute, publicly display, and publicly digitally perform such Files, including for commercial purposes, provided that any display, publication, performance, or distribution of Files must contain (and be subject to) the same terms and conditions of this license. Modifications to Files are deemed derivative works and must also be expressly distributed under the same terms and conditions of this license. You may not purport to impose any additional or different terms or conditions on, or apply any technical measures that restrict exercise of, the rights granted under this license. This license does not include the right to collect or compile Files from LottieFiles to replicate or develop a similar or competing service.
|
||||
|
||||
Use of Files without attributing the creator(s) of the Files is permitted under this license, though attribution is strongly encouraged. If attributions are included, such attributions should be visible to the end user.
|
||||
|
||||
FILES ARE PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL THE CREATOR(S) OF FILES OR DESIGN BARN, INC. BE LIABLE ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF SUCH FILES.
|
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB |
|
@ -60,7 +60,6 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
|
|||
require("../d2m/actions/register-user.test")
|
||||
require("../d2m/converters/edit-to-changes.test")
|
||||
require("../d2m/converters/emoji-to-key.test")
|
||||
require("../d2m/converters/lottie.test")
|
||||
require("../d2m/converters/message-to-event.test")
|
||||
require("../d2m/converters/message-to-event.embeds.test")
|
||||
require("../d2m/converters/pins-to-list.test")
|
||||
|
|
Loading…
Reference in a new issue