Forwards formatting

This commit is contained in:
Inex Code 2020-11-20 08:45:31 +00:00
parent 50e27b2e7d
commit 6daf69a6ab
5 changed files with 592 additions and 459 deletions

View file

@ -21,14 +21,14 @@ Register that one with synapse and start the bridge with `npm run start`.
- [x] Audio/Video content - [x] Audio/Video content
- [x] Other files - [x] Other files
- [x] Replies - [x] Replies
- [ ] Typing notifs - not possible yet - [ ] Typing notifs - Synapse 1.22.0 or later required
- [ ] Presence - not possible yet - [ ] Presence - ~~not possible yet~~
- [ ] Read notifications - not possible yet - [ ] Read notifications - ~~not possible yet~~
- [x] Message edits - [x] Message edits
- [x] Message redacts - works as edit, real redact unavailable without being admin in chat - [x] Message redacts - works as edit, real redact unavailable without being admin in chat
- VK -> Matrix - VK -> Matrix
- [x] Text content - [x] Text content
- [ ] Forwards - [x] Forwards
- [x] Image content - [x] Image content
- [x] Audio content - [x] Audio content
- [ ] Video content - [ ] Video content

939
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -14,12 +14,14 @@
"command-line-args": "^5.1.1", "command-line-args": "^5.1.1",
"command-line-usage": "^5.0.5", "command-line-usage": "^5.0.5",
"js-yaml": "^3.14.0", "js-yaml": "^3.14.0",
"mx-puppet-bridge": "^0.0.45", "mx-puppet-bridge": "^0.1.0-1",
"showdown": "^1.9.1",
"tslint": "^5.17.0", "tslint": "^5.17.0",
"typescript": "^4.0.3", "typescript": "^4.0.3",
"vk-io": "^4.0.3" "vk-io": "^4.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.19.3" "@types/node": "^12.19.3",
"@types/showdown": "^1.9.3"
} }
} }

View file

@ -49,7 +49,7 @@ const protocol: IProtocolInformation = {
features: { features: {
image: true, image: true,
file: true, file: true,
presence: false, presence: true,
reply: true, reply: true,
edit: true, edit: true,
advancedRelay: true, advancedRelay: true,
@ -95,6 +95,8 @@ async function run() {
puppet.on("image", vk.handleMatrixImage.bind(vk)); puppet.on("image", vk.handleMatrixImage.bind(vk));
puppet.on("file", vk.handleMatrixFile.bind(vk)); puppet.on("file", vk.handleMatrixFile.bind(vk));
puppet.on("typing", vk.handleMatrixTyping.bind(vk));
puppet.setCreateRoomHook(vk.createRoom.bind(vk)); puppet.setCreateRoomHook(vk.createRoom.bind(vk));
// required: get description hook // required: get description hook
// tslint:disable-next-line: no-any // tslint:disable-next-line: no-any

View file

@ -11,10 +11,11 @@ import {
ISendingUser, ISendingUser,
} from "mx-puppet-bridge"; } from "mx-puppet-bridge";
import { VK, MessageContext, Context, AttachmentType } from "vk-io"; import { VK, MessageContext, Context, AttachmentType, MessageForwardsCollection } from "vk-io";
import { userInfo } from "os"; import { userInfo } from "os";
import { runInThisContext } from "vm"; import { runInThisContext } from "vm";
import { lookup } from "dns"; import { lookup } from "dns";
import { Converter } from "showdown";
// here we create our log instance // here we create our log instance
const log = new Log("VKPuppet:vk"); const log = new Log("VKPuppet:vk");
@ -35,6 +36,13 @@ interface IEchoPuppets {
export class VkPuppet { export class VkPuppet {
private puppets: IEchoPuppets = {}; private puppets: IEchoPuppets = {};
private converter: Converter = new Converter({
simplifiedAutoLink: true,
excludeTrailingPunctuationFromURLs: true,
strikethrough: true,
simpleLineBreaks: true,
requireSpaceBeforeHeadingText: true,
});
constructor( constructor(
private puppet: PuppetBridge, private puppet: PuppetBridge,
) { } ) { }
@ -62,15 +70,18 @@ export class VkPuppet {
userId: userId.toString(), userId: userId.toString(),
name: info[0].name, name: info[0].name,
avatarUrl: info[0].photo_200, avatarUrl: info[0].photo_200,
externalUrl: `https://vk.com/${info[0].screen_name}`,
}; };
return response; return response;
} else { } else {
const info = await p.client.api.users.get({ user_ids: userId.toString(), fields: ["photo_max"] }); const info = await p.client.api.users.get({ user_ids: userId.toString(), fields: ["photo_max", "screen_name"] });
log.info(info[0]);
const response: IRemoteUser = { const response: IRemoteUser = {
puppetId, puppetId,
userId: userId.toString(), userId: userId.toString(),
name: `${info[0].first_name} ${info[0].last_name}`, name: `${info[0].first_name} ${info[0].last_name}`,
avatarUrl: info[0].photo_max, avatarUrl: info[0].photo_max,
externalUrl: `https://vk.com/${info[0].screen_name}`,
}; };
return response; return response;
} }
@ -400,6 +411,31 @@ export class VkPuppet {
} }
} }
} }
public async handleMatrixTyping(
room: IRemoteRoom,
typing: boolean,
asUser: ISendingUser | null,
event: any,
) {
log.info("Got typing", typing);
if (typing) {
log.info("Got typing");
const p = this.puppets[room.puppetId];
if (!p) {
return null;
}
try {
const response = await p.client.api.messages.setActivity({
peer_id: Number(room.roomId),
type: "typing",
})
} catch (err) {
log.error("Error sending typing presence to vk", err.error || err.body || err)
}
}
}
public async createRoom(room: IRemoteRoom): Promise<IRemoteRoom | null> { public async createRoom(room: IRemoteRoom): Promise<IRemoteRoom | null> {
const p = this.puppets[room.puppetId]; const p = this.puppets[room.puppetId];
@ -428,11 +464,16 @@ export class VkPuppet {
const params = await this.getSendParams(puppetId, context.peerId, context.senderId, const params = await this.getSendParams(puppetId, context.peerId, context.senderId,
context.conversationMessageId?.toString() || context.id.toString()); context.conversationMessageId?.toString() || context.id.toString());
if (context.hasText) { if (context.hasText || context.hasForwards) {
let msgText: string = context.text || "";
if (context.hasForwards) {
msgText = await this.appendForwards(puppetId, msgText, context.forwards);
}
if (context.hasReplyMessage) { if (context.hasReplyMessage) {
if (this.puppet.eventSync.getMatrix(params.room, context.replyMessage!.id.toString())) { if (this.puppet.eventSync.getMatrix(params.room, context.replyMessage!.id.toString())) {
const opts: IMessageEvent = { const opts: IMessageEvent = {
body: context.text || "Attachment", body: msgText || "Attachment",
formattedBody: this.converter.makeHtml(msgText),
}; };
// We got referenced message in room, using matrix reply // We got referenced message in room, using matrix reply
await this.puppet.sendReply(params, context.replyMessage!.id.toString(), opts); await this.puppet.sendReply(params, context.replyMessage!.id.toString(), opts);
@ -440,7 +481,7 @@ export class VkPuppet {
// Using a fallback // Using a fallback
const opts: IMessageEvent = { const opts: IMessageEvent = {
body: await this.prependReply( body: await this.prependReply(
puppetId, context.text || "", puppetId, msgText || "",
context.replyMessage?.text || "", context.replyMessage?.text || "",
context.senderId.toString(), context.senderId.toString(),
), ),
@ -449,7 +490,8 @@ export class VkPuppet {
} }
} else { } else {
const opts: IMessageEvent = { const opts: IMessageEvent = {
body: context.text || "Attachment", body: msgText || "Attachment",
formattedBody: this.converter.makeHtml(msgText),
}; };
await this.puppet.sendMessage(params, opts); await this.puppet.sendMessage(params, opts);
} }
@ -532,7 +574,7 @@ export class VkPuppet {
const replySplitted = reply.split("\n"); const replySplitted = reply.split("\n");
let formatted: string = `> <${user.name}>\n`; let formatted: string = `> <${user.name}>\n`;
replySplitted.forEach((element) => { replySplitted.forEach((element) => {
formatted += `> ${element}`; formatted += `> ${element}\n`;
}); });
formatted += `\n\n${body}`; formatted += `\n\n${body}`;
return formatted; return formatted;
@ -551,4 +593,42 @@ export class VkPuppet {
} }
return (splitted.join("\n").trim()); return (splitted.join("\n").trim());
} }
public async appendForwards(puppetId: number, body: string, forwards: MessageForwardsCollection) {
let formatted = `${body}\n`;
for (const f of forwards) {
const user = await this.getRemoteUser(puppetId, Number(f.senderId));
formatted += `> <[${user.name}](${user.externalUrl})>\n`
f.text?.split("\n").forEach((element) => {
formatted += `> ${element}\n`;
})
if (f.hasAttachments()) {
f.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.DOCUMENT:
formatted += `> 📁 [File ${attachment["title"]}](${attachment["url"]})\n`
break;
default:
break;
}
})
}
if (f.hasForwards) {
(await this.appendForwards(puppetId, "", f.forwards)).trim().split("\n").forEach((element) => {
formatted += `> ${element}\n`;
})
}
formatted += "\n";
}
return formatted;
}
} }