img conversion

This commit is contained in:
Nathan Rashleigh committed 2024-04-09 15:57:09 +10:00
1 parent 38c5579fbb
commit b655adc305
5 files changed
+927 -24

No files matched your search

+108 -3
View File
@@ -1,6 +1,29 @@
import axios from 'axios';
import path from 'path'
export default function scraper(discordAuth) {
import axios from 'axios'
import mime from 'mime-types'
import type { PrismaClient, Attachment } from '@prisma/client';
import type { ImageAnnotatorClient } from '@google-cloud/vision';
import type Minio from 'minio'
import sharp from 'sharp';
const IMAGE_TYPES = [
'image/png',
'image/jpeg',
'image/webp',
'image/gif',
]
const VIDEO_TYPES = [
'video/mp4',
'video/quicktime'
]
const STORAGE_BUCKET = process.env.STORAGE_BUCKET
export default function scraper(discordAuth, vision: ImageAnnotatorClient, minio: Minio.Client) {
const headers = {
'Authorization': discordAuth,
}
@@ -25,12 +48,93 @@ export default function scraper(discordAuth) {
return res.data
}
async function detectText(attachment: Attachment) {
// bail out of anything not an image
if (!IMAGE_TYPES.includes(attachment.contentType)) return {}
const annotateRequest = {
image: {
source: {
imageUri: attachment.url
}
},
features: [{ type: 'TEXT_DETECTION' }],
}
const res = await vision.annotateImage(annotateRequest)
// comes back as an array
return res[0] || {}
}
async function downloadAttachment(a: Attachment) {
const download = await axios.get(a.url, { responseType: 'stream' })
const isImage = IMAGE_TYPES.includes(a.contentType)
const objectName = () => {
if (isImage)
return `${a.memeId}.webp`
return `${a.memeId}.${mime.extension(a.contentType)}`
}
const stream = async () => {
if (isImage) {
const converter = sharp().webp()
download.data.pipe(converter)
return converter
}
return download.data
}
return minio.putObject(STORAGE_BUCKET, objectName(), await stream())
}
function filterAttachments(messages, guild, channel) {
const acceptedContentTypes = [
...IMAGE_TYPES,
...VIDEO_TYPES,
]
return Promise.all(messages
.filter(m => m.attachments)
// bundle message and attachment together
.map(m => m.attachments.map(a => [a, m]))
.flat()
.filter(([a, m]) => acceptedContentTypes.includes(a.content_type))
.map(async ([a, m]) => {
const attachment: Attachment = {
id: BigInt(a.id),
msgId: BigInt(m.id),
channelId: BigInt(m.channel_id),
url: a.url,
contentType: a.content_type,
message: m,
// create this ahead of time to associate with our copy of the media
memeId: crypto.randomUUID(),
// @ts-ignore it's fine
vision: {},
guild,
channel,
createdAt: undefined,
updatedAt: undefined
}
const visionData = await detectText(attachment)
return { ...attachment, vision: visionData }
}))
}
async function getChannelAttachments(channelId) {
try {
const channel = await fetchChannel(channelId)
const guild = await fetchGuildDetails(channel.guild_id)
const messages = await fetchChannelMessages(channelId)
return { messages, channel, guild }
return filterAttachments(messages, guild, channel);
// return { messages, channel, guild }
} catch (e) {
console.error('scrape error', {
err: e.toJSON(),
@@ -41,6 +145,7 @@ export default function scraper(discordAuth) {
return {
getChannelAttachments,
downloadAttachment,
}
}