Version 0.6.0
* Fix forwards in user mode (closes #21) * Treat replies as forwards in user mode (closes #20) * Fix posts in user mode (closes #22) * Basic geo support * Initial autopopulate support
This commit is contained in:
parent
d12455bfd7
commit
443179b286
|
@ -120,6 +120,7 @@ where the access token is `df89482ba9a19e5a2dee85031612b021a08cd521115e1c7d2cd70
|
|||
- VK (AS A USER) -> Matrix
|
||||
- [x] Auth as a user instead of group
|
||||
- [x] Text content
|
||||
- [x] Replies (as forwards)
|
||||
- [x] Forwards
|
||||
- [x] Image content
|
||||
- [ ] Audio content - unavailable via user tokens
|
||||
|
|
33
package-lock.json
generated
33
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mx-puppet-vk",
|
||||
"version": "0.5.1",
|
||||
"version": "0.6.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1080,21 +1080,6 @@
|
|||
"domexception": "2.0.1",
|
||||
"fetch-blob": "2.1.2",
|
||||
"mime-types": "2.1.31"
|
||||
},
|
||||
"dependencies": {
|
||||
"mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"requires": {
|
||||
"mime-db": "1.48.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
|
@ -2543,13 +2528,13 @@
|
|||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
},
|
||||
"vk-io": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/vk-io/-/vk-io-4.3.1.tgz",
|
||||
"integrity": "sha512-ceFgfOHF3uNyy+jBDD4ZZzymcaDbBd3k1UgKWt0L02fzDqJPhQVXjy8x6OKSZXBxqEtQP/M2K3GroEqs/4PqGg==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vk-io/-/vk-io-4.3.2.tgz",
|
||||
"integrity": "sha512-9L532/3hxkqNhrK3NcHOQ1aiIPxIDExY+D/bwbJX6gE1zT+rVYAyteapXkYR8xuD9qCcgbDBBu8b+h5a1NFVOA==",
|
||||
"requires": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"debug": "^4.3.1",
|
||||
"form-data-encoder": "^1.0.0",
|
||||
"debug": "^4.3.2",
|
||||
"form-data-encoder": "^1.0.1",
|
||||
"formdata-node": "^3.5.4",
|
||||
"inspectable": "^1.2.0",
|
||||
"middleware-io": "^2.8.0",
|
||||
|
@ -2557,9 +2542,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mx-puppet-vk",
|
||||
"version": "0.5.3",
|
||||
"version": "0.6.0",
|
||||
"description": "Matrix <-> VK bridge based on mx-puppet-bridge and VK-IO.",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
|
260
src/attachments-handler.ts
Normal file
260
src/attachments-handler.ts
Normal file
|
@ -0,0 +1,260 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -98,6 +98,8 @@ async function run() {
|
|||
puppet.on("typing", vk.handleMatrixTyping.bind(vk));
|
||||
|
||||
puppet.setCreateRoomHook(vk.createRoom.bind(vk));
|
||||
puppet.setGetUserIdsInRoomHook(vk.getUserIdsInRoom.bind(vk));
|
||||
puppet.setCreateUserHook(vk.createUser.bind(vk));
|
||||
// required: get description hook
|
||||
// tslint:disable-next-line: no-any
|
||||
puppet.setGetDescHook(async (puppetId: number, data: any): Promise<string> => {
|
||||
|
|
388
src/vk.ts
388
src/vk.ts
|
@ -16,8 +16,10 @@ import { userInfo } from "os";
|
|||
import { runInThisContext } from "vm";
|
||||
import { lookup } from "dns";
|
||||
import { Converter } from "showdown";
|
||||
import { MessagesMessageAttachment } from "vk-io/lib/api/schemas/objects";
|
||||
import { MessagesMessage, MessagesMessageAttachment } from "vk-io/lib/api/schemas/objects";
|
||||
import { ElementFlags, OptionalTypeNode } from "typescript";
|
||||
import { AttachmentsHandler } from "./attachments-handler";
|
||||
import { debug } from "console";
|
||||
|
||||
// here we create our log instance
|
||||
const log = new Log("VKPuppet:vk");
|
||||
|
@ -36,183 +38,6 @@ interface IEchoPuppets {
|
|||
[puppetId: number]: IEchoPuppet;
|
||||
}
|
||||
|
||||
|
||||
export class AttachmentsHandler {
|
||||
private puppet: IEchoPuppet;
|
||||
private puppetBridge: PuppetBridge;
|
||||
constructor (puppet: IEchoPuppet, puppetBridge: PuppetBridge) {
|
||||
this.puppet = puppet;
|
||||
this.puppetBridge = puppetBridge;
|
||||
}
|
||||
|
||||
public getBiggestImage(images: Array<object>): any {
|
||||
let maxImageResolution = 0;
|
||||
let biggestImage: any = null;
|
||||
images.forEach(
|
||||
function(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.
|
||||
let biggestImage = this.getBiggestImage(
|
||||
attachment["photo"]["sizes"]
|
||||
);
|
||||
let 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) {
|
||||
let audio_url: string = attachment["oggUrl"] || attachment["url"];
|
||||
if (audio_url === undefined || audio_url === "") {
|
||||
const opts: IMessageEvent = {
|
||||
body: "Audio messages aren't supported yet",
|
||||
};
|
||||
await this.puppetBridge.sendMessage(params, opts);
|
||||
} else {
|
||||
try {
|
||||
await this.puppetBridge.sendAudio(params, audio_url);
|
||||
} catch (err) {
|
||||
const opts: IMessageEvent = {
|
||||
body: `Audio message: ${audio_url}`,
|
||||
};
|
||||
await this.puppetBridge.sendMessage(params, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async handleAudio(params: IReceiveParams, attachment: MessagesMessageAttachment) {
|
||||
let audio_url: string = attachment["url"];
|
||||
if (audio_url === undefined || audio_url === "") {
|
||||
const opts: IMessageEvent = {
|
||||
body: "Audio in messages aren't supported yet",
|
||||
};
|
||||
await this.puppetBridge.sendMessage(params, opts);
|
||||
} else {
|
||||
try {
|
||||
await this.puppetBridge.sendAudio(params, audio_url);
|
||||
} catch (err) {
|
||||
const opts: IMessageEvent = {
|
||||
body: `Audio: ${attachment["title"]} by ${attachment["artist"]} ${audio_url}`,
|
||||
};
|
||||
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) {
|
||||
const opts: IMessageEvent = {
|
||||
body: `Document: ${attachment["url"]}`,
|
||||
};
|
||||
await this.puppetBridge.sendMessage(params, opts);
|
||||
}
|
||||
}
|
||||
|
||||
public async handleForwards(
|
||||
vkPuppet: VkPuppet, puppetId: number, message_body: string,
|
||||
params: IReceiveParams, forwards: MessageForwardsCollection
|
||||
) {
|
||||
let formatted = `${message_body}\n`;
|
||||
log.debug("Forawrded messages", forwards);
|
||||
|
||||
for (const f of forwards) {
|
||||
const user = await vkPuppet.getRemoteUser(puppetId, Number(f.senderId));
|
||||
log.debug("Forwarder", user);
|
||||
formatted += `> <[${user.name}](${user.externalUrl})>\n`;
|
||||
f.text?.split("\n").forEach((element) => {
|
||||
formatted += `> ${element}\n`;
|
||||
});
|
||||
if (f.hasAttachments()) {
|
||||
f.attachments.forEach(async (attachment) => {
|
||||
switch (attachment.type) {
|
||||
case AttachmentType.PHOTO:
|
||||
await this.handlePhotoAttachment(params, attachment);
|
||||
break;
|
||||
case AttachmentType.STICKER:
|
||||
await this.handleStickerAttachment(params, attachment);
|
||||
break;
|
||||
case AttachmentType.AUDIO_MESSAGE:
|
||||
await this.handleAudioMessage(params, attachment);
|
||||
break;
|
||||
case AttachmentType.DOCUMENT:
|
||||
await this.handleDocument(params, attachment);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export class VkPuppet {
|
||||
private puppets: IEchoPuppets = {};
|
||||
private converter: Converter = new Converter({
|
||||
|
@ -316,6 +141,31 @@ export class VkPuppet {
|
|||
return response;
|
||||
}
|
||||
|
||||
public async getUserIdsInRoom(room: IRemoteRoom): Promise<Set<string> | null> {
|
||||
const p = this.puppets[room.puppetId];
|
||||
|
||||
const users = new Set<string>();
|
||||
if (room.isDirect === false) {
|
||||
const response = await p.client.api.messages.getConversationMembers({ peer_id: Number(room.roomId) });
|
||||
response.items.forEach((element) => {
|
||||
users.add(element.member_id.toString());
|
||||
});
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
public async createUser(user: IRemoteUser): Promise<IRemoteUser | null> {
|
||||
const p = this.puppets[user.puppetId];
|
||||
if (!p) {
|
||||
return null;
|
||||
}
|
||||
const remoteUser = await this.getRemoteUser(user.puppetId, Number(user.userId));
|
||||
if (!remoteUser) {
|
||||
return null;
|
||||
}
|
||||
return remoteUser;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: no-any
|
||||
public async newPuppet(puppetId: number, data: any) {
|
||||
// this is called when we need to create a new puppet
|
||||
|
@ -328,7 +178,6 @@ export class VkPuppet {
|
|||
// and listen to incoming messages from it
|
||||
try {
|
||||
const client = new VK({ token: data.token, apiLimit: 20 });
|
||||
log.debug("Trying to init listener with", data.token);
|
||||
|
||||
client.updates.on("message_new", async (context) => {
|
||||
try {
|
||||
|
@ -681,42 +530,65 @@ export class VkPuppet {
|
|||
p.data.isUserToken ? context.id.toString() : context.conversationMessageId?.toString() || context.id.toString());
|
||||
const attachmentHandler = new AttachmentsHandler(p, this.puppet);
|
||||
|
||||
if (context.hasText || context.hasForwards) {
|
||||
let msgText: string = context.text || "";
|
||||
if (context.hasForwards) {
|
||||
let msgText: string = context.text || "";
|
||||
let fullContext: MessagesMessage | undefined;
|
||||
if (p.data.isUserToken) {
|
||||
fullContext = (await p.client.api.messages.getById({ message_ids: context.id, extended: 1 })).items[0];
|
||||
if (fullContext.geo !== undefined) {
|
||||
msgText += `geo:${fullContext.geo.coordinates.latitude},${fullContext.geo.coordinates.longitude}\n`;
|
||||
}
|
||||
} else {
|
||||
fullContext = undefined;
|
||||
if (context.geo !== undefined) {
|
||||
msgText += `geo:${context.geo.coordinates.latitude},${context.geo.coordinates.longitude}\n`;
|
||||
}
|
||||
}
|
||||
if (context.hasForwards) {
|
||||
if (fullContext !== undefined) {
|
||||
const forwards = (await p.client.api.messages.getById({ message_ids: context.id, extended: 1 })).items[0]["fwd_messages"];
|
||||
if (fullContext.fwd_messages !== undefined) {
|
||||
try {
|
||||
msgText = await attachmentHandler.handleForwardsAsUser(this, puppetId, msgText, params, fullContext.fwd_messages);
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
log.debug(context);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
msgText = await attachmentHandler.handleForwards(this, puppetId, msgText, params, context.forwards);
|
||||
msgText = await attachmentHandler.handleForwards(this, puppetId, msgText, params, (context.forwards));
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
log.debug(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fix handling of replies somehow because they aren't sending replies in matrix in user mode at all
|
||||
if (context.hasReplyMessage) {
|
||||
if (this.puppet.eventSync.getMatrix(params.room, context.replyMessage!.id.toString())) {
|
||||
const opts: IMessageEvent = {
|
||||
body: msgText || "Attachment",
|
||||
formattedBody: this.converter.makeHtml(msgText),
|
||||
};
|
||||
// We got referenced message in room, using matrix reply
|
||||
await this.puppet.sendReply(params, context.replyMessage!.id.toString(), opts);
|
||||
} else {
|
||||
// Using a fallback
|
||||
const opts: IMessageEvent = {
|
||||
body: await this.prependReply(
|
||||
puppetId, msgText || "",
|
||||
context.replyMessage?.text || "",
|
||||
context.senderId.toString(),
|
||||
),
|
||||
};
|
||||
await this.puppet.sendMessage(params, opts);
|
||||
}
|
||||
} else {
|
||||
if (context.hasReplyMessage) {
|
||||
if (this.puppet.eventSync.getMatrix(params.room, context.replyMessage!.id.toString())) {
|
||||
const opts: IMessageEvent = {
|
||||
body: msgText || "Attachment",
|
||||
formattedBody: this.converter.makeHtml(msgText),
|
||||
};
|
||||
// We got referenced message in room, using matrix reply
|
||||
await this.puppet.sendReply(params, context.replyMessage!.id.toString(), opts);
|
||||
} else {
|
||||
// Using a fallback
|
||||
const opts: IMessageEvent = {
|
||||
body: await this.prependReply(
|
||||
puppetId, msgText || "",
|
||||
context.replyMessage?.text || "",
|
||||
context.senderId.toString(),
|
||||
),
|
||||
};
|
||||
await this.puppet.sendMessage(params, opts);
|
||||
}
|
||||
} else {
|
||||
if (msgText !== "") {
|
||||
const opts: IMessageEvent = {
|
||||
body: msgText,
|
||||
formattedBody: this.converter.makeHtml(msgText),
|
||||
};
|
||||
await this.puppet.sendMessage(params, opts);
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +609,7 @@ export class VkPuppet {
|
|||
break;
|
||||
|
||||
case AttachmentType.AUDIO_MESSAGE:
|
||||
await attachmentHandler.handleAudioMessage(params, f)
|
||||
await attachmentHandler.handleAudioMessage(params, f["audio_message"]);
|
||||
break;
|
||||
|
||||
case AttachmentType.AUDIO:
|
||||
|
@ -831,38 +703,82 @@ export class VkPuppet {
|
|||
}
|
||||
|
||||
public async renderWallPost(puppetId: number, post: MessagesMessageAttachment) {
|
||||
const user = await this.getRemoteUser(puppetId, Number(post.fromId));
|
||||
let formatted = `Forwarded post from [${user.name}](${user.externalUrl})\n`;
|
||||
post.text?.split("\n").forEach((element) => {
|
||||
formatted += `> ${element}\n`;
|
||||
});
|
||||
if (post.hasAttachments()) {
|
||||
post.attachments.forEach((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](${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;
|
||||
}
|
||||
|
||||
const renderWallPostAsGroup = async () => {
|
||||
const user = await this.getRemoteUser(puppetId, Number(post.fromId));
|
||||
let formatted = `Forwarded post from [${user.name}](${user.externalUrl})\n`;
|
||||
post.text?.split("\n").forEach((element) => {
|
||||
formatted += `> ${element}\n`;
|
||||
});
|
||||
if (post.hasAttachments()) {
|
||||
post.attachments.forEach((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](${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;
|
||||
}
|
||||
});
|
||||
}
|
||||
return formatted;
|
||||
};
|
||||
|
||||
const renderWallPostAsUser = async () => {
|
||||
const user = await this.getRemoteUser(puppetId, Number(post.fromId));
|
||||
let formatted = `Forwarded post from [${user.name}](${user.externalUrl})\n`;
|
||||
post = post.wall;
|
||||
post.text?.split("\n").forEach((element) => {
|
||||
formatted += `> ${element}\n`;
|
||||
});
|
||||
if (post.attachments !== undefined && post.attachments.length !== 0) {
|
||||
const attachmentHandler = new AttachmentsHandler(p, this.puppet);
|
||||
post.attachments.forEach((attachment) => {
|
||||
switch (attachment.type) {
|
||||
case AttachmentType.PHOTO:
|
||||
formatted +=
|
||||
`> 🖼️ [Photo](${attachmentHandler.getBiggestImage(attachment[attachment.type]["sizes"])["url"]})\n`;
|
||||
break;
|
||||
case AttachmentType.AUDIO:
|
||||
formatted += `> 🗣️ [Audio] ${attachment[attachment.type]["title"]} by ${attachment[attachment.type]["artist"]} ${attachment[attachment.type]["url"]}\n`;
|
||||
break;
|
||||
case AttachmentType.DOCUMENT:
|
||||
formatted += `> 📁 [File ${attachment[attachment.type]["title"]}](${attachment[attachment.type]["url"]})\n`;
|
||||
break;
|
||||
case AttachmentType.LINK:
|
||||
formatted += `> 🔗 [ ${attachment[attachment.type]["title"] ? attachment[attachment.type]["title"] : attachment[attachment.type]["url"]} ](${attachment[attachment.type]["url"]})\n`;
|
||||
break;
|
||||
default:
|
||||
formatted += `> ❓️ Unhandled attachment of type ${attachment.type}\n`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
return formatted;
|
||||
};
|
||||
|
||||
const p = this.puppets[puppetId];
|
||||
if (p.data.isUserToken) {
|
||||
return await renderWallPostAsUser();
|
||||
} else {
|
||||
return await renderWallPostAsGroup();
|
||||
}
|
||||
return formatted;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue