mirror of
https://github.com/plantroon/mx-puppet-xmpp.git
synced 2024-11-16 00:11:40 +00:00
implement quotes
This commit is contained in:
parent
9054d7a18f
commit
3f161b27cb
6
package-lock.json
generated
6
package-lock.json
generated
@ -98,9 +98,9 @@
|
||||
}
|
||||
},
|
||||
"@sorunome/skype-http": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@sorunome/skype-http/-/skype-http-1.5.1.tgz",
|
||||
"integrity": "sha512-dJ0fMeTmtzTUWbXN3+SCth8C9XElhrEkzbp454xyo0vXYyoPMbIUYuWeEas1hyeYjaqI9PdgTOe5xI9y+qr9/g==",
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@sorunome/skype-http/-/skype-http-1.5.2.tgz",
|
||||
"integrity": "sha512-NAxvVVHIi7G/9v5RbB3vkNqbgy2CB+puE6ZvwX1ha4+PCP5MTy5KZRfrhOpIVyTLmTEXS50USl/ixAek5RwLlA==",
|
||||
"requires": {
|
||||
"async-file": "^2.0.2",
|
||||
"big-integer": "^1.6.26",
|
||||
|
@ -11,7 +11,7 @@
|
||||
},
|
||||
"author": "Sorunome",
|
||||
"dependencies": {
|
||||
"@sorunome/skype-http": "^1.5.1",
|
||||
"@sorunome/skype-http": "^1.5.2",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"command-line-args": "^5.1.1",
|
||||
"command-line-usage": "^5.0.5",
|
||||
|
@ -62,6 +62,7 @@ const protocol: IProtocolInformation = {
|
||||
audio: true,
|
||||
file: true,
|
||||
edit: true,
|
||||
reply: true,
|
||||
globalNamespace: true,
|
||||
},
|
||||
id: "skype",
|
||||
@ -94,6 +95,7 @@ async function run() {
|
||||
puppet.on("puppetDelete", skype.deletePuppet.bind(skype));
|
||||
puppet.on("message", skype.handleMatrixMessage.bind(skype));
|
||||
puppet.on("edit", skype.handleMatrixEdit.bind(skype));
|
||||
puppet.on("reply", skype.handleMatrixReply.bind(skype));
|
||||
puppet.on("redact", skype.handleMatrixRedact.bind(skype));
|
||||
puppet.on("image", skype.handleMatrixImage.bind(skype));
|
||||
puppet.on("audio", skype.handleMatrixAudio.bind(skype));
|
||||
|
@ -52,8 +52,12 @@ export class MatrixMessageParser {
|
||||
const inner = this.walkChildNodes(nodeHtml);
|
||||
return `<a href="${escapeHtml(href)}">${inner}</a>`;
|
||||
}
|
||||
case "blockquote":
|
||||
return `<quote>${this.walkChildNodes(nodeHtml)}</quote>`;
|
||||
case "wrap":
|
||||
return this.walkChildNodes(nodeHtml);
|
||||
case "mx-reply": // disgard replies
|
||||
return "";
|
||||
default:
|
||||
if (!nodeHtml.tagName) {
|
||||
return this.walkChildNodes(nodeHtml);
|
||||
|
70
src/skype.ts
70
src/skype.ts
@ -409,6 +409,63 @@ export class Skype {
|
||||
}
|
||||
}
|
||||
|
||||
public async handleMatrixReply(room: IRemoteRoom, eventId: string, data: IMessageEvent) {
|
||||
const p = this.puppets[room.puppetId];
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
log.info("Received reply from matrix");
|
||||
const conversation = await p.client.getConversation(room);
|
||||
if (!conversation) {
|
||||
log.warn(`Room ${room.roomId} not found!`);
|
||||
return;
|
||||
}
|
||||
let msg: string;
|
||||
if (data.formattedBody) {
|
||||
msg = this.matrixMessageParser.parse(data.formattedBody);
|
||||
} else {
|
||||
msg = escapeHtml(data.body);
|
||||
}
|
||||
// now prepend the reply
|
||||
const author = escapeHtml(p.client.username.substr(p.client.username.indexOf(":") + 1));
|
||||
const ownContact = await p.client.getContact(p.client.username);
|
||||
const authorname = escapeHtml(ownContact ? ownContact.displayName : p.client.username);
|
||||
const conversationId = escapeHtml(conversation.id);
|
||||
const timestamp = Math.round(Number(eventId) / 1000).toString();
|
||||
const origEventId = (await this.puppet.eventSync.getMatrix(room.puppetId, eventId))[0];
|
||||
let contents = "blah";
|
||||
if (origEventId) {
|
||||
const [realOrigEventId, roomId] = origEventId.split(";");
|
||||
try {
|
||||
const client = (await this.puppet.roomSync.getRoomOp(roomId)) || this.puppet.botIntent.underlyingClient;
|
||||
const evt = await client.getEvent(roomId, realOrigEventId);
|
||||
if (evt && evt.content && typeof evt.content.body === "string") {
|
||||
if (evt.content.formatted_body) {
|
||||
contents = this.matrixMessageParser.parse(evt.content.formatted_body);
|
||||
} else {
|
||||
contents = escapeHtml(evt.content.body);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
log.verbose("Event not found", err.body || err);
|
||||
}
|
||||
}
|
||||
const quote = `<quote author="${author}" authorname="${authorname}" timestamp="${timestamp}" ` +
|
||||
`conversation="${conversationId}" messageid="${escapeHtml(eventId)}">` +
|
||||
`<legacyquote>[${timestamp}] ${authorname}: </legacyquote>${contents}<legacyquote>
|
||||
|
||||
<<< </legacyquote></quote>`;
|
||||
msg = quote + msg;
|
||||
const dedupeKey = `${room.puppetId};${room.roomId}`;
|
||||
this.messageDeduplicator.lock(dedupeKey, p.client.username, msg);
|
||||
const ret = await p.client.sendMessage(conversation.id, msg);
|
||||
const newEventId = ret && ret.MessageId;
|
||||
this.messageDeduplicator.unlock(dedupeKey, p.client.username, newEventId);
|
||||
if (newEventId) {
|
||||
await this.puppet.eventSync.insert(room.puppetId, data.eventId!, newEventId);
|
||||
}
|
||||
}
|
||||
|
||||
public async handleMatrixRedact(room: IRemoteRoom, eventId: string) {
|
||||
const p = this.puppets[room.puppetId];
|
||||
if (!p) {
|
||||
@ -514,6 +571,17 @@ export class Skype {
|
||||
log.silly("normal message dedupe");
|
||||
return;
|
||||
}
|
||||
if (rich && msg.trim().startsWith("<quote")) {
|
||||
// okay, we might have a reply...
|
||||
const $ = cheerio.load(msg);
|
||||
const quote = $("quote");
|
||||
const messageid = quote.attr("messageid");
|
||||
if (messageid) {
|
||||
const sendQuoteMsg = this.skypeMessageParser.parse(msg, { noQuotes: true });
|
||||
await this.puppet.sendReply(params, messageid, sendQuoteMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let sendMsg: IMessageEvent;
|
||||
if (rich) {
|
||||
sendMsg = this.skypeMessageParser.parse(msg);
|
||||
@ -557,7 +625,7 @@ export class Skype {
|
||||
}
|
||||
let sendMsg: IMessageEvent;
|
||||
if (rich) {
|
||||
sendMsg = this.skypeMessageParser.parse(msg);
|
||||
sendMsg = this.skypeMessageParser.parse(msg, { noQuotes: msg.trim().startsWith("<quote") });
|
||||
} else {
|
||||
sendMsg = {
|
||||
body: msg,
|
||||
|
@ -17,23 +17,30 @@ import * as escapeHtml from "escape-html";
|
||||
import { IMessageEvent } from "mx-puppet-bridge";
|
||||
import * as emoji from "node-emoji";
|
||||
|
||||
interface ISkypeMessageParserOpts {
|
||||
noQuotes?: boolean;
|
||||
}
|
||||
|
||||
export class SkypeMessageParser {
|
||||
public parse(msg: string): IMessageEvent {
|
||||
public parse(msg: string, opts: ISkypeMessageParserOpts = {}): IMessageEvent {
|
||||
opts = Object.assign({
|
||||
noQuotes: false,
|
||||
}, opts);
|
||||
const nodes = Parser.parse(`<wrap>${msg}</wrap>`, {
|
||||
lowerCaseTagName: true,
|
||||
pre: true,
|
||||
});
|
||||
return this.walkNode(nodes);
|
||||
return this.walkNode(nodes, opts);
|
||||
}
|
||||
|
||||
private walkChildNodes(node: Parser.Node): IMessageEvent {
|
||||
private walkChildNodes(node: Parser.Node, opts: ISkypeMessageParserOpts): IMessageEvent {
|
||||
if (!node.childNodes.length) {
|
||||
return {
|
||||
body: "",
|
||||
formattedBody: "",
|
||||
};
|
||||
}
|
||||
return node.childNodes.map((n) => this.walkNode(n)).reduce((acc, curr) => {
|
||||
return node.childNodes.map((n) => this.walkNode(n, opts)).reduce((acc, curr) => {
|
||||
return {
|
||||
body: acc.body + curr.body,
|
||||
formattedBody: acc.formattedBody! + curr.formattedBody!,
|
||||
@ -48,35 +55,35 @@ export class SkypeMessageParser {
|
||||
};
|
||||
}
|
||||
|
||||
private walkNode(node: Parser.Node): IMessageEvent {
|
||||
private walkNode(node: Parser.Node, opts: ISkypeMessageParserOpts): IMessageEvent {
|
||||
if (node.nodeType === Parser.NodeType.TEXT_NODE) {
|
||||
return this.escape((node as Parser.TextNode).text);
|
||||
} else if (node.nodeType === Parser.NodeType.ELEMENT_NODE) {
|
||||
const nodeHtml = node as Parser.HTMLElement;
|
||||
switch (nodeHtml.tagName) {
|
||||
case "i": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
const child = this.walkChildNodes(nodeHtml, opts);
|
||||
return {
|
||||
body: `_${child.body}_`,
|
||||
formattedBody: `<em>${child.formattedBody}</em>`,
|
||||
};
|
||||
}
|
||||
case "b": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
const child = this.walkChildNodes(nodeHtml, opts);
|
||||
return {
|
||||
body: `*${child.body}*`,
|
||||
formattedBody: `<strong>${child.formattedBody}</strong>`,
|
||||
};
|
||||
}
|
||||
case "s": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
const child = this.walkChildNodes(nodeHtml, opts);
|
||||
return {
|
||||
body: `~${child.body}~`,
|
||||
formattedBody: `<del>${child.formattedBody}</del>`,
|
||||
};
|
||||
}
|
||||
case "pre": {
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
const child = this.walkChildNodes(nodeHtml, opts);
|
||||
return {
|
||||
body: `{code}${child.body}{code}`,
|
||||
formattedBody: `<code>${child.formattedBody}</code>`,
|
||||
@ -84,12 +91,25 @@ export class SkypeMessageParser {
|
||||
}
|
||||
case "a": {
|
||||
const href = nodeHtml.attributes.href;
|
||||
const child = this.walkChildNodes(nodeHtml);
|
||||
const child = this.walkChildNodes(nodeHtml, opts);
|
||||
return {
|
||||
body: child.body === href ? href : `[${child.body}](${href})`,
|
||||
formattedBody: `<a href="${escapeHtml(href)}">${child.formattedBody}</a>`,
|
||||
};
|
||||
}
|
||||
case "quote": {
|
||||
if (opts.noQuotes) {
|
||||
return {
|
||||
body: "",
|
||||
formattedBody: "",
|
||||
};
|
||||
}
|
||||
const child = this.walkChildNodes(nodeHtml, opts);
|
||||
return {
|
||||
body: `> ${child.body}\n`,
|
||||
formattedBody: `<blockquote>${child.formattedBody}<br> - ${nodeHtml.attributes.authorname}</blockquote>`,
|
||||
};
|
||||
}
|
||||
case "ss": {
|
||||
// skype emoji
|
||||
const type = nodeHtml.attributes.type;
|
||||
@ -164,14 +184,14 @@ export class SkypeMessageParser {
|
||||
formattedBody: `(${escapeHtml(type)})`,
|
||||
};
|
||||
}
|
||||
case "e_m":
|
||||
// empty edit tag
|
||||
case "e_m": // empty edit tag
|
||||
case "legacyquote": // empty legacy quote tag
|
||||
return {
|
||||
body: "",
|
||||
formattedBody: "",
|
||||
};
|
||||
default:
|
||||
return this.walkChildNodes(nodeHtml);
|
||||
return this.walkChildNodes(nodeHtml, opts);
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
Loading…
Reference in New Issue
Block a user