diff --git a/README.md b/README.md index 6329c4a..104a6ab 100755 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Register that one with synapse and start the bridge with `npm run start`. - [x] Replies - [x] Typing notifs - [see note](#Note-on-presence-from-matrix-side) - [ ] Presence - ~~not possible yet~~ - - [ ] Read notifications - ~~not possible yet~~ + - [x] Read notifications - [x] Message edits - [x] Message redacts - works as edit, real redact unavailable without being admin in chat - [ ] Initiate rooms from the matrix side @@ -108,12 +108,12 @@ where the access token is `df89482ba9a19e5a2dee85031612b021a08cd521115e1c7d2cd70 - Matrix -> VK (AS A USER) - [x] Text content - [x] Image content - - [x] Audio/Video content + - [x] Audio messages - [x] Other files - [x] Replies - [x] Typing notifs - [ ] Presence - - [ ] Read notifications + - [x] Read notifications - [x] Message edits - [x] Message redacts - in 24 hours - [ ] Initiate rooms from the matrix side @@ -163,7 +163,7 @@ npm run build - [x] Ответы - [x] Индикатор печати - [смотрите примечание](#примечание-о-эфемерных-событиях) - [ ] Индикатор "в сети" - - [ ] Индикаторы прочтения + - [x] Индикаторы прочтения - [x] Редактирование сообщений - [x] Удаление сообщений - работает как редактирование - [ ] Инициация чатов со стороны Matrix @@ -239,12 +239,12 @@ https://oauth.vk.com/blank.html#access_token=df89482ba9a19e5a2dee85031612b021a08 - Matrix -> Вконтакте (как пользователь) - [x] Текстовые сообщения - [x] Изображения - - [x] Аудио и видео + - [x] Аудио сообщения - [x] Прочие файлы - [x] Ответы - [x] Индикатор печати - [ ] Индикатор "в сети" - - [ ] Индикаторы прочтения + - [x] Индикаторы прочтения - [x] Редактирование сообщений - [x] Удаление сообщений - в течении 24 часов - [ ] Инициация чатов со стороны Matrix diff --git a/package.json b/package.json index 3ac8007..fc1a0fd 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mx-puppet-vk", - "version": "0.6.0", + "version": "0.7.0", "description": "Matrix <-> VK bridge based on mx-puppet-bridge and VK-IO.", "main": "index.js", "repository": { diff --git a/src/attachments-handler.ts b/src/attachments-handler.ts index c1017fb..bf2d98b 100644 --- a/src/attachments-handler.ts +++ b/src/attachments-handler.ts @@ -239,6 +239,12 @@ export class AttachmentsHandler { case AttachmentType.LINK: formatted += `> 🔗 [ ${attachment["title"] ? attachment["title"] : attachment["url"]} ](${attachment["url"]})\n`; break; + case AttachmentType.WALL: + const wallpost = await vkPuppet.renderWallPost(puppetId, attachment); + formatted += wallpost.split("\n").forEach((element) => { + formatted += `> ${element}\n`; + }); + break; default: formatted += `> ❓️ Unhandled attachment of type ${attachment.type}\n`; break; diff --git a/src/index.ts b/src/index.ts index 6dd843f..2209539 100755 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,7 @@ if (options.help) { const protocol: IProtocolInformation = { features: { image: true, + audio: true, file: true, presence: true, reply: true, @@ -93,9 +94,11 @@ async function run() { puppet.on("redact", vk.handleMatrixRedact.bind(vk)); puppet.on("reply", vk.handleMatrixReply.bind(vk)); puppet.on("image", vk.handleMatrixImage.bind(vk)); + puppet.on("audio", vk.handleMatrixAudio.bind(vk)); puppet.on("file", vk.handleMatrixFile.bind(vk)); puppet.on("typing", vk.handleMatrixTyping.bind(vk)); + puppet.on("read", vk.handleMatrixRead.bind(vk)); puppet.setCreateRoomHook(vk.createRoom.bind(vk)); puppet.setGetUserIdsInRoomHook(vk.getUserIdsInRoom.bind(vk)); diff --git a/src/vk.ts b/src/vk.ts index da86920..6de05ed 100755 --- a/src/vk.ts +++ b/src/vk.ts @@ -418,6 +418,65 @@ export class VkPuppet { } } + public async handleMatrixAudio( + room: IRemoteRoom, + data: IFileEvent, + asUser: ISendingUser | null, + // tslint:disable-next-line: no-any + event: any, + ) { + const p = this.puppets[room.puppetId]; + if (!p) { + return; + } + const MAXFILESIZE = 50000000; + const size = data.info ? data.info.size || 0 : 0; + + if (size < MAXFILESIZE) { + try { + const attachment = await p.client.upload.audioMessage({ + peer_id: Number(room.roomId), + source: { + value: data.url, + filename: data.filename, + }, + }); + const response = await p.client.api.messages.send({ + peer_id: Number(room.roomId), + random_id: new Date().getTime(), + message: asUser ? `${asUser.displayname} sent an audio message:` : undefined, + attachment: [`doc${attachment.ownerId}_${attachment.id}`], + }); + await this.puppet.eventSync.insert(room, data.eventId!, response.toString()); + } catch (err) { + try { + const response = await p.client.api.messages.send({ + peer_ids: Number(room.roomId), + message: `Audio message ${data.filename} was sent, but VK refused to recieve it. You may download it there:\n${data.url}`, + random_id: new Date().getTime(), + }); + await this.puppet.eventSync.insert(room, data.eventId!, + p.data.isUserToken ? response[0]["message_id"].toString() : response[0]["conversation_message_id"].toString()); + } catch (err) { + log.error("Error sending to vk", err.error || err.body || err); + } + } + } else { + try { + const response = await p.client.api.messages.send({ + peer_ids: Number(room.roomId), + message: `File ${data.filename} was sent, but it is too big for VK. You may download it there:\n${data.url}`, + random_id: new Date().getTime(), + }); + await this.puppet.eventSync.insert(room, data.eventId!, + p.data.isUserToken ? response[0]["message_id"].toString() : response[0]["conversation_message_id"].toString()); + } catch (err) { + log.error("Error sending to vk", err.error || err.body || err); + } + } + } + + public async handleMatrixFile( room: IRemoteRoom, data: IFileEvent, @@ -476,8 +535,6 @@ export class VkPuppet { } } - // Never called on my server for some reason, but - // if being called, should work public async handleMatrixTyping( room: IRemoteRoom, typing: boolean, @@ -500,6 +557,24 @@ export class VkPuppet { } } + public async handleMatrixRead( + room: IRemoteRoom, + eventId: string + ) { + const p = this.puppets[room.puppetId]; + if (!p) { + return null; + } + try { + const response = await p.client.api.messages.markAsRead({ + peer_id: Number(room.roomId), + start_message_id: Number(eventId), + }); + } catch (err) { + log.error("Error sending read event to vk", err.error || err.body || err); + } + } + public async createRoom(room: IRemoteRoom): Promise { const p = this.puppets[room.puppetId]; if (!p) { @@ -599,6 +674,7 @@ export class VkPuppet { : context.attachments; for (const f of attachments) { + let rendered: string; switch (f.type) { case AttachmentType.PHOTO: await attachmentHandler.handlePhotoAttachment(params, f); @@ -627,14 +703,18 @@ export class VkPuppet { break; case AttachmentType.WALL: + rendered = await this.renderWallPost(puppetId, f) await this.puppet.sendMessage(params, { - body: await this.renderWallPost(puppetId, f), + body: rendered, + formattedBody: this.converter.makeHtml(rendered), }); break; case AttachmentType.WALL_REPLY: + rendered = await this.renderWallPost(puppetId, f) await this.puppet.sendMessage(params, { - body: await this.renderWallPost(puppetId, f), + body: rendered, + formattedBody: this.converter.makeHtml(rendered), }); break; @@ -741,7 +821,7 @@ export class VkPuppet { }; const renderWallPostAsUser = async () => { - const user = await this.getRemoteUser(puppetId, Number(post.fromId)); + const user = await this.getRemoteUser(puppetId, Number(post.wall.ownerId)); let formatted = `Forwarded post from [${user.name}](${user.externalUrl})\n`; post = post.wall; post.text?.split("\n").forEach((element) => { @@ -770,6 +850,13 @@ export class VkPuppet { } }); } + if (post.copy_history !== undefined && post.copy_history !== 0) { + const subpost = await this.renderWallPost(puppetId, { wall: post.copy_history[0] }) + subpost.split("\n").forEach((element) => { + formatted += `> ${element}\n`; + }); + }; + return formatted; };