261 lines
8.6 KiB
TypeScript
261 lines
8.6 KiB
TypeScript
|
// first we import a few needed things again
|
||
|
import {
|
||
|
PuppetBridge,
|
||
|
IReceiveParams,
|
||
|
IMessageEvent,
|
||
|
Log,
|
||
|
} from "mx-puppet-bridge";
|
||
|
|
||
|
import { VK, AttachmentType, MessageForwardsCollection } from "vk-io";
|
||
|
import { MessagesForeignMessage, MessagesMessageAttachment } from "vk-io/lib/api/schemas/objects";
|
||
|
import { VkPuppet } from "./vk";
|
||
|
|
||
|
// here we create our log instance
|
||
|
const log = new Log("VKPuppet:attachment-handler");
|
||
|
|
||
|
// this interface is to hold all data on a single puppet
|
||
|
interface IEchoPuppet {
|
||
|
// this is usually a client class that connects to the remote protocol
|
||
|
// as we just echo back, unneeded in our case
|
||
|
client: VK;
|
||
|
// tslint:disable-next-line: no-any
|
||
|
data: any; // and let's keep a copy of the data associated with a puppet
|
||
|
}
|
||
|
|
||
|
export class AttachmentsHandler {
|
||
|
private puppet: IEchoPuppet;
|
||
|
private puppetBridge: PuppetBridge;
|
||
|
constructor(puppet: IEchoPuppet, puppetBridge: PuppetBridge) {
|
||
|
this.puppet = puppet;
|
||
|
this.puppetBridge = puppetBridge;
|
||
|
}
|
||
|
|
||
|
public getBiggestImage(images: object[]): any {
|
||
|
let maxImageResolution = 0;
|
||
|
let biggestImage: any = null;
|
||
|
images.forEach((image: object) => {
|
||
|
if (maxImageResolution < (image["width"] + image["height"])) {
|
||
|
maxImageResolution = image["width"] + image["height"];
|
||
|
biggestImage = image;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return biggestImage;
|
||
|
}
|
||
|
|
||
|
public async handlePhotoAttachment(params: IReceiveParams, attachment: MessagesMessageAttachment) {
|
||
|
try {
|
||
|
if (this.puppet.data.isUserToken) {
|
||
|
// VK API is weird. Very weird.
|
||
|
const biggestImage = this.getBiggestImage(
|
||
|
attachment["photo"]["sizes"],
|
||
|
);
|
||
|
const url: string = biggestImage["url"] || "";
|
||
|
|
||
|
if (url === "") {
|
||
|
log.error(`Image not found in ${attachment["photo"]}`);
|
||
|
}
|
||
|
await this.puppetBridge.sendFileDetect(params, url);
|
||
|
} else {
|
||
|
await this.puppetBridge.sendFileDetect(params, attachment["largeSizeUrl"]);
|
||
|
}
|
||
|
} catch (err) {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Image: ${attachment["image"]["largeSizeUrl"]}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async handleStickerAttachment(params: IReceiveParams, attachment: MessagesMessageAttachment) {
|
||
|
try {
|
||
|
if (this.puppet.data.isUserToken) {
|
||
|
await this.puppetBridge.sendFileDetect(
|
||
|
params, attachment["sticker"]["images_with_background"][4]["url"],
|
||
|
);
|
||
|
} else {
|
||
|
await this.puppetBridge.sendFileDetect(params, attachment["imagesWithBackground"][4]["url"]);
|
||
|
}
|
||
|
|
||
|
} catch (err) {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Sticker: ${attachment["imagesWithBackground"][4]["url"]}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async handleAudioMessage(params: IReceiveParams, attachment: MessagesMessageAttachment) {
|
||
|
const audioUrl: string = attachment["oggUrl"] || attachment["url"] || attachment["link_ogg"];
|
||
|
if (audioUrl === undefined || audioUrl === "") {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: "Audio messages aren't supported yet",
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
} else {
|
||
|
try {
|
||
|
await this.puppetBridge.sendAudio(params, audioUrl);
|
||
|
} catch (err) {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Audio message: ${audioUrl}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
}
|
||
|
if (attachment["transcript"] !== undefined) {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: "[Transcript]" + attachment["transcript"],
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async handleAudio(params: IReceiveParams, attachment: MessagesMessageAttachment) {
|
||
|
const audioUrl: string = attachment["url"];
|
||
|
if (audioUrl === undefined || audioUrl === "") {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: "Audio in messages aren't supported yet",
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
} else {
|
||
|
try {
|
||
|
await this.puppetBridge.sendAudio(params, audioUrl);
|
||
|
} catch (err) {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Audio: ${attachment["title"]} by ${attachment["artist"]} ${audioUrl}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async handleDocument(params: IReceiveParams, attachment: MessagesMessageAttachment) {
|
||
|
try {
|
||
|
if (this.puppet.data.isUserToken) {
|
||
|
await this.puppetBridge.sendFileDetect(params, attachment["doc"]["url"], attachment["doc"]["title"]);
|
||
|
} else {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Document: ${attachment["url"]}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
} catch (err) {
|
||
|
if (this.puppet.data.isUserToken) {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Document: ${attachment["doc"]["url"]}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
} else {
|
||
|
const opts: IMessageEvent = {
|
||
|
body: `Document: ${attachment["url"]}`,
|
||
|
};
|
||
|
await this.puppetBridge.sendMessage(params, opts);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async handleForwards(
|
||
|
vkPuppet: VkPuppet, puppetId: number, messageBody: string,
|
||
|
params: IReceiveParams, forwards: MessageForwardsCollection | MessagesForeignMessage[],
|
||
|
) {
|
||
|
let formatted = `${messageBody}\n`;
|
||
|
|
||
|
for (const f of forwards) {
|
||
|
const user = await vkPuppet.getRemoteUser(puppetId, Number(f.senderId));
|
||
|
formatted += `> <[${user.name}](${user.externalUrl})>\n`;
|
||
|
f.text?.split("\n").forEach((element) => {
|
||
|
formatted += `> ${element}\n`;
|
||
|
});
|
||
|
if (f.attachments !== undefined && f.attachments.length !== 0) {
|
||
|
f.attachments?.forEach(async (attachment) => {
|
||
|
switch (attachment.type) {
|
||
|
case AttachmentType.PHOTO:
|
||
|
formatted += `> 🖼️ [Photo](${attachment["largeSizeUrl"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.STICKER:
|
||
|
formatted += `> 🖼️ [Sticker](${attachment["imagesWithBackground"][4]["url"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.AUDIO_MESSAGE:
|
||
|
formatted += `> 🗣️ [Audio message](${attachment["oggUrl"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.AUDIO:
|
||
|
formatted += `> 🗣️ [Audio message](${attachment["oggUrl"] ?? attachment["url"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.DOCUMENT:
|
||
|
formatted += `> 📁 [File ${attachment["title"]}](${attachment["url"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.LINK:
|
||
|
formatted += `> 🔗 [ ${attachment["title"] ? attachment["title"] : attachment["url"]} ](${attachment["url"]})\n`;
|
||
|
break;
|
||
|
default:
|
||
|
formatted += `> ❓️ Unhandled attachment of type ${attachment.type}\n`;
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
if (f.hasForwards) {
|
||
|
(
|
||
|
await this.handleForwards(vkPuppet, puppetId, "", params, f.forwards)
|
||
|
).trim().split("\n").forEach((element) => {
|
||
|
formatted += `> ${element}\n`;
|
||
|
},
|
||
|
);
|
||
|
}
|
||
|
formatted += "\n";
|
||
|
}
|
||
|
return formatted;
|
||
|
}
|
||
|
|
||
|
public async handleForwardsAsUser(
|
||
|
vkPuppet: VkPuppet, puppetId: number, messageBody: string,
|
||
|
params: IReceiveParams, forwards: MessageForwardsCollection | MessagesForeignMessage[],
|
||
|
) {
|
||
|
let formatted = `${messageBody}\n`;
|
||
|
|
||
|
for (const f of forwards) {
|
||
|
const user = await vkPuppet.getRemoteUser(puppetId, Number(f.from_id));
|
||
|
formatted += `> <[${user.name}](${user.externalUrl})>\n`;
|
||
|
f.text?.split("\n").forEach((element) => {
|
||
|
formatted += `> ${element}\n`;
|
||
|
});
|
||
|
if (f.attachments !== undefined && f.attachments.length !== 0) {
|
||
|
f.attachments?.forEach(async (attachment) => {
|
||
|
switch (attachment.type) {
|
||
|
case AttachmentType.PHOTO:
|
||
|
formatted += `> 🖼️ [Photo](${this.getBiggestImage(attachment[attachment.type]["sizes"])["url"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.STICKER:
|
||
|
formatted += `> 🖼️ [Sticker](${this.getBiggestImage(attachment[attachment.type]["images_with_background"])["url"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.AUDIO_MESSAGE:
|
||
|
formatted += `> 🗣️ [Audio message](${attachment[attachment.type]["link_ogg"]}) \n`;
|
||
|
if (attachment[attachment.type]["transcript"] !== undefined) {
|
||
|
formatted += `> > [Transcript] ${attachment[attachment.type]["transcript"]}`;
|
||
|
}
|
||
|
break;
|
||
|
case AttachmentType.DOCUMENT:
|
||
|
formatted += `> 📁 [File ${attachment[attachment.type]["title"]}](${attachment[attachment.type]["url"]})\n`;
|
||
|
break;
|
||
|
case AttachmentType.LINK:
|
||
|
formatted += `> 🔗 [ ${attachment["title"] ? attachment["title"] : attachment["url"]} ](${attachment["url"]})\n`;
|
||
|
break;
|
||
|
default:
|
||
|
formatted += `> ❓️ Unhandled attachment of type ${attachment.type}\n`;
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
if (f.fwd_messages !== undefined) {
|
||
|
(
|
||
|
await this.handleForwardsAsUser(vkPuppet, puppetId, "", params, f.fwd_messages)
|
||
|
).trim().split("\n").forEach((element) => {
|
||
|
formatted += `> ${element}\n`;
|
||
|
});
|
||
|
}
|
||
|
formatted += "\n";
|
||
|
}
|
||
|
return formatted;
|
||
|
}
|
||
|
|
||
|
}
|