dograma
Version:
NodeJS/Browser MTProto API Telegram client library,
700 lines (698 loc) • 25.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CustomMessage = void 0;
const senderGetter_1 = require("./senderGetter");
const api_1 = require("../api");
const chatGetter_1 = require("./chatGetter");
const utils = __importStar(require("../../Utils"));
const forward_1 = require("./forward");
const file_1 = require("./file");
const Helpers_1 = require("../../Helpers");
const users_1 = require("../../client/users");
const Logger_1 = require("../../extensions/Logger");
const messageButton_1 = require("./messageButton");
const inspect_1 = require("../../inspect");
/**
* This custom class aggregates both {@link Api.Message} and {@link Api.MessageService} to ease accessing their members.<br/>
* <br/>
* Remember that this class implements {@link ChatGetter} and {@link SenderGetter}<br/>
* which means you have access to all their sender and chat properties and methods.
*/
class CustomMessage extends senderGetter_1.SenderGetter {
constructor(args) {
super();
this.init(args);
}
[inspect_1.inspect.custom]() {
return (0, Helpers_1.betterConsoleLog)(this);
}
init({ id, peerId = undefined, date = undefined, out = undefined, mentioned = undefined, mediaUnread = undefined, silent = undefined, post = undefined, fromId = undefined, replyTo = undefined, message = undefined, fwdFrom = undefined, viaBotId = undefined, media = undefined, replyMarkup = undefined, entities = undefined, views = undefined, editDate = undefined, postAuthor = undefined, groupedId = undefined, fromScheduled = undefined, legacy = undefined, editHide = undefined, pinned = undefined, restrictionReason = undefined, forwards = undefined, replies = undefined, action = undefined, reactions = undefined, noforwards = undefined, ttlPeriod = undefined, _entities = new Map(), }) {
if (!id)
throw new Error("id is a required attribute for Message");
let senderId = undefined;
if (fromId) {
senderId = utils.getPeerId(fromId);
}
else if (peerId) {
if (post || (!out && peerId instanceof api_1.Api.PeerUser)) {
senderId = utils.getPeerId(peerId);
}
}
// Common properties to all messages
this._entities = _entities;
this.out = out;
this.mentioned = mentioned;
this.mediaUnread = mediaUnread;
this.silent = silent;
this.post = post;
this.post = post;
this.fromScheduled = fromScheduled;
this.legacy = legacy;
this.editHide = editHide;
this.ttlPeriod = ttlPeriod;
this.id = id;
this.fromId = fromId;
this.peerId = peerId;
this.fwdFrom = fwdFrom;
this.viaBotId = viaBotId;
this.replyTo = replyTo;
this.date = date;
this.message = message;
this.media = media instanceof api_1.Api.MessageMediaEmpty ? media : undefined;
this.replyMarkup = replyMarkup;
this.entities = entities;
this.views = views;
this.forwards = forwards;
this.replies = replies;
this.editDate = editDate;
this.pinned = pinned;
this.postAuthor = postAuthor;
this.groupedId = groupedId;
this.restrictionReason = restrictionReason;
this.action = action;
this.noforwards = noforwards;
this.reactions = reactions;
this._client = undefined;
this._text = undefined;
this._file = undefined;
this._replyMessage = undefined;
this._buttons = undefined;
this._buttonsFlat = undefined;
this._buttonsCount = 0;
this._viaBot = undefined;
this._viaInputBot = undefined;
this._actionEntities = undefined;
// Note: these calls would reset the client
chatGetter_1.ChatGetter.initChatClass(this, { chatPeer: peerId, broadcast: post });
senderGetter_1.SenderGetter.initSenderClass(this, {
senderId: senderId ? (0, Helpers_1.returnBigInt)(senderId) : undefined,
});
this._forward = undefined;
}
_finishInit(client, entities, inputChat) {
this._client = client;
const cache = client._entityCache;
if (this.senderId) {
[this._sender, this._inputSender] = utils._getEntityPair(this.senderId.toString(), entities, cache);
}
if (this.chatId) {
[this._chat, this._inputChat] = utils._getEntityPair(this.chatId.toString(), entities, cache);
}
if (inputChat) {
// This has priority
this._inputChat = inputChat;
}
if (this.viaBotId) {
[this._viaBot, this._viaInputBot] = utils._getEntityPair(this.viaBotId.toString(), entities, cache);
}
if (this.fwdFrom) {
this._forward = new forward_1.Forward(this._client, this.fwdFrom, entities);
}
if (this.action) {
if (this.action instanceof api_1.Api.MessageActionChatAddUser ||
this.action instanceof api_1.Api.MessageActionChatCreate) {
this._actionEntities = this.action.users.map((i) => entities.get(i.toString()));
}
else if (this.action instanceof api_1.Api.MessageActionChatDeleteUser) {
this._actionEntities = [
entities.get(this.action.userId.toString()),
];
}
else if (this.action instanceof api_1.Api.MessageActionChatJoinedByLink) {
this._actionEntities = [
entities.get(utils.getPeerId(new api_1.Api.PeerChannel({
channelId: this.action.inviterId,
}))),
];
}
else if (this.action instanceof api_1.Api.MessageActionChannelMigrateFrom) {
this._actionEntities = [
entities.get(utils.getPeerId(new api_1.Api.PeerChat({ chatId: this.action.chatId }))),
];
}
}
}
get client() {
return this._client;
}
get text() {
if (this._text === undefined && this._client) {
if (!this._client.parseMode) {
this._text = this.message;
}
else {
this._text = this._client.parseMode.unparse(this.message || "", this.entities || []);
}
}
return this._text || "";
}
set text(value) {
this._text = value;
if (this._client && this._client.parseMode) {
[this.message, this.entities] = this._client.parseMode.parse(value);
}
else {
this.message = value;
this.entities = [];
}
}
get rawText() {
return this.message || "";
}
/**
* @param {string} value
*/
set rawText(value) {
this.message = value;
this.entities = [];
this._text = "";
}
get isReply() {
return !!this.replyTo;
}
get forward() {
return this._forward;
}
async _refetchSender() {
await this._reloadMessage();
}
/**
* Re-fetches this message to reload the sender and chat entities,
* along with their input versions.
* @private
*/
async _reloadMessage() {
if (!this._client)
return;
let msg = undefined;
try {
const chat = this.isChannel ? await this.getInputChat() : undefined;
let temp = await this._client.getMessages(chat, { ids: this.id });
if (temp) {
msg = temp[0];
}
}
catch (e) {
this._client._log.error("Got error while trying to finish init message with id " +
this.id);
if (this._client._log.canSend(Logger_1.LogLevel.ERROR)) {
console.error(e);
}
}
if (msg == undefined)
return;
this._sender = msg._sender;
this._inputSender = msg._inputSender;
this._chat = msg._chat;
this._inputChat = msg._inputChat;
this._viaBot = msg._viaBot;
this._viaInputBot = msg._viaInputBot;
this._forward = msg._forward;
this._actionEntities = msg._actionEntities;
}
/**
* Returns a list of lists of `MessageButton <MessageButton>`, if any.
* Otherwise, it returns `undefined`.
*/
get buttons() {
if (!this._buttons && this.replyMarkup) {
if (!this.inputChat) {
return;
}
try {
const bot = this._neededMarkupBot();
this._setButtons(this.inputChat, bot);
}
catch (e) {
return;
}
}
return this._buttons;
}
/**
* Returns `buttons` when that property fails (this is rarely needed).
*/
async getButtons() {
if (!this.buttons && this.replyMarkup) {
const chat = await this.getInputChat();
if (!chat)
return;
let bot;
try {
bot = this._neededMarkupBot();
}
catch (e) {
await this._reloadMessage();
bot = this._neededMarkupBot();
}
this._setButtons(chat, bot);
}
return this._buttons;
}
get buttonCount() {
if (!this._buttonsCount) {
if (this.replyMarkup instanceof api_1.Api.ReplyInlineMarkup ||
this.replyMarkup instanceof api_1.Api.ReplyKeyboardMarkup) {
this._buttonsCount = this.replyMarkup.rows
.map((r) => r.buttons.length)
.reduce(function (a, b) {
return a + b;
}, 0);
}
else {
this._buttonsCount = 0;
}
}
return this._buttonsCount;
}
get file() {
if (!this._file) {
const media = this.photo || this.document;
if (media) {
this._file = new file_1.File(media);
}
}
return this._file;
}
get photo() {
if (this.media instanceof api_1.Api.MessageMediaPhoto) {
if (this.media.photo instanceof api_1.Api.Photo)
return this.media.photo;
}
else if (this.action instanceof api_1.Api.MessageActionChatEditPhoto) {
return this.action.photo;
}
else {
return this.webPreview && this.webPreview.photo instanceof api_1.Api.Photo
? this.webPreview.photo
: undefined;
}
return undefined;
}
get document() {
if (this.media instanceof api_1.Api.MessageMediaDocument) {
if (this.media.document instanceof api_1.Api.Document)
return this.media.document;
}
else {
const web = this.webPreview;
return web && web.document instanceof api_1.Api.Document
? web.document
: undefined;
}
return undefined;
}
get webPreview() {
if (this.media instanceof api_1.Api.MessageMediaWebPage) {
if (this.media.webpage instanceof api_1.Api.WebPage)
return this.media.webpage;
}
}
get audio() {
return this._documentByAttribute(api_1.Api.DocumentAttributeAudio, (attr) => !attr.voice);
}
get voice() {
return this._documentByAttribute(api_1.Api.DocumentAttributeAudio, (attr) => !!attr.voice);
}
get video() {
return this._documentByAttribute(api_1.Api.DocumentAttributeVideo);
}
get videoNote() {
return this._documentByAttribute(api_1.Api.DocumentAttributeVideo, (attr) => !!attr.roundMessage);
}
get gif() {
return this._documentByAttribute(api_1.Api.DocumentAttributeAnimated);
}
get sticker() {
return this._documentByAttribute(api_1.Api.DocumentAttributeSticker);
}
get contact() {
if (this.media instanceof api_1.Api.MessageMediaContact) {
return this.media;
}
}
get game() {
if (this.media instanceof api_1.Api.MessageMediaGame) {
return this.media.game;
}
}
get geo() {
if (this.media instanceof api_1.Api.MessageMediaGeo ||
this.media instanceof api_1.Api.MessageMediaGeoLive ||
this.media instanceof api_1.Api.MessageMediaVenue) {
return this.media.geo;
}
}
get invoice() {
if (this.media instanceof api_1.Api.MessageMediaInvoice) {
return this.media;
}
}
get poll() {
if (this.media instanceof api_1.Api.MessageMediaPoll) {
return this.media;
}
}
get venue() {
if (this.media instanceof api_1.Api.MessageMediaVenue) {
return this.media;
}
}
get dice() {
if (this.media instanceof api_1.Api.MessageMediaDice) {
return this.media;
}
}
get actionEntities() {
return this._actionEntities;
}
get viaBot() {
return this._viaBot;
}
get viaInputBot() {
return this._viaInputBot;
}
get replyToMsgId() {
var _a;
return (_a = this.replyTo) === null || _a === void 0 ? void 0 : _a.replyToMsgId;
}
get toId() {
if (this._client && !this.out && this.isPrivate) {
return new api_1.Api.PeerUser({
userId: (0, users_1._selfId)(this._client),
});
}
return this.peerId;
}
getEntitiesText(cls) {
let ent = this.entities;
if (!ent || ent.length == 0)
return;
if (cls) {
ent = ent.filter((v) => v instanceof cls);
}
const texts = utils.getInnerText(this.message || "", ent);
const zip = (rows) => rows[0].map((_, c) => rows.map((row) => row[c]));
return zip([ent, texts]);
}
async getReplyMessage() {
if (!this._replyMessage && this._client) {
if (!this.replyTo)
return undefined;
// Bots cannot access other bots' messages by their ID.
// However they can access them through replies...
this._replyMessage = (await this._client.getMessages(this.isChannel ? await this.getInputChat() : undefined, {
ids: new api_1.Api.InputMessageReplyTo({ id: this.id }),
}))[0];
if (!this._replyMessage) {
// ...unless the current message got deleted.
//
// If that's the case, give it a second chance accessing
// directly by its ID.
this._replyMessage = (await this._client.getMessages(this.isChannel ? this._inputChat : undefined, {
ids: this.replyToMsgId,
}))[0];
}
}
return this._replyMessage;
}
async respond(params) {
if (this._client) {
return this._client.sendMessage((await this.getInputChat()), params);
}
}
async reply(params) {
if (this._client) {
params.replyTo = this.id;
return this._client.sendMessage((await this.getInputChat()), params);
}
}
async forwardTo(entity) {
if (this._client) {
entity = await this._client.getInputEntity(entity);
const params = {
messages: [this.id],
fromPeer: (await this.getInputChat()),
};
return this._client.forwardMessages(entity, params);
}
}
async edit(params) {
const param = params;
if (this.fwdFrom || !this.out || !this._client)
return undefined;
if (param.linkPreview == undefined) {
param.linkPreview = !!this.webPreview;
}
if (param.buttons == undefined) {
param.buttons = this.replyMarkup;
}
param.message = this.id;
return this._client.editMessage((await this.getInputChat()), param);
}
async delete({ revoke } = { revoke: false }) {
if (this._client) {
return this._client.deleteMessages(await this.getInputChat(), [this.id], {
revoke,
});
}
}
async pin(params) {
if (this._client) {
const entity = await this.getInputChat();
if (entity === undefined) {
throw Error("Failed to pin message due to cannot get input chat.");
}
return this._client.pinMessage(entity, this.id, params);
}
}
async unpin(params) {
if (this._client) {
const entity = await this.getInputChat();
if (entity === undefined) {
throw Error("Failed to unpin message due to cannot get input chat.");
}
return this._client.unpinMessage(entity, this.id, params);
}
}
async downloadMedia(params) {
// small hack for patched method
if (this._client)
return this._client.downloadMedia(this, params || {});
}
async markAsRead() {
if (this._client) {
const entity = await this.getInputChat();
if (entity === undefined) {
throw Error(`Failed to mark message id ${this.id} as read due to cannot get input chat.`);
}
return this._client.markAsRead(entity, this.id);
}
}
async click({ i, j, text, filter, data, sharePhone, shareGeo, password, }) {
if (!this.client) {
return;
}
if (data) {
const chat = await this.getInputChat();
if (!chat) {
return;
}
const button = new api_1.Api.KeyboardButtonCallback({
text: "",
data: data,
});
return await new messageButton_1.MessageButton(this.client, button, chat, undefined, this.id).click({
sharePhone: sharePhone,
shareGeo: shareGeo,
password: password,
});
}
if (this.poll) {
function findPoll(answers) {
if (i != undefined) {
if (Array.isArray(i)) {
const corrects = [];
for (let x = 0; x < i.length; x++) {
corrects.push(answers[x].option);
}
return corrects;
}
return [answers[i].option];
}
if (text != undefined) {
if (typeof text == "function") {
for (const answer of answers) {
if (text(answer.text)) {
return [answer.option];
}
}
}
else {
for (const answer of answers) {
if (answer.text == text) {
return [answer.option];
}
}
}
return;
}
if (filter != undefined) {
for (const answer of answers) {
if (filter(answer)) {
return [answer.option];
}
}
return;
}
}
const options = findPoll(this.poll.poll.answers) || [];
return await this.client.invoke(new api_1.Api.messages.SendVote({
peer: this.inputChat,
msgId: this.id,
options: options,
}));
}
if (!(await this.getButtons())) {
return; // Accessing the property sets this._buttons[_flat]
}
function findButton(self) {
if (!self._buttonsFlat || !self._buttons) {
return;
}
if (Array.isArray(i)) {
i = i[0];
}
if (text != undefined) {
if (typeof text == "function") {
for (const button of self._buttonsFlat) {
if (text(button.text)) {
return button;
}
}
}
else {
for (const button of self._buttonsFlat) {
if (button.text == text) {
return button;
}
}
}
return;
}
if (filter != undefined) {
for (const button of self._buttonsFlat) {
if (filter(button)) {
return button;
}
}
return;
}
if (i == undefined) {
i = 0;
}
if (j == undefined) {
return self._buttonsFlat[i];
}
else {
return self._buttons[i][j];
}
}
const button = findButton(this);
if (button) {
return await button.click({
sharePhone: sharePhone,
shareGeo: shareGeo,
password: password,
});
}
}
/**
* Helper methods to set the buttons given the input sender and chat.
*/
_setButtons(chat, bot) {
if (this.client &&
(this.replyMarkup instanceof api_1.Api.ReplyInlineMarkup ||
this.replyMarkup instanceof api_1.Api.ReplyKeyboardMarkup)) {
this._buttons = [];
this._buttonsFlat = [];
for (const row of this.replyMarkup.rows) {
const tmp = [];
for (const button of row.buttons) {
const btn = new messageButton_1.MessageButton(this.client, button, chat, bot, this.id);
tmp.push(btn);
this._buttonsFlat.push(btn);
}
this._buttons.push(tmp);
}
}
}
/**
*Returns the input peer of the bot that's needed for the reply markup.
This is necessary for `KeyboardButtonSwitchInline` since we need
to know what bot we want to start. Raises ``Error`` if the bot
cannot be found but is needed. Returns `None` if it's not needed.
*/
_neededMarkupBot() {
if (!this.client || this.replyMarkup == undefined) {
return;
}
if (!(this.replyMarkup instanceof api_1.Api.ReplyInlineMarkup ||
this.replyMarkup instanceof api_1.Api.ReplyKeyboardMarkup)) {
return;
}
for (const row of this.replyMarkup.rows) {
for (const button of row.buttons) {
if (button instanceof api_1.Api.KeyboardButtonSwitchInline) {
if (button.samePeer || !this.viaBotId) {
const bot = this._inputSender;
if (!bot)
throw new Error("No input sender");
return bot;
}
else {
const ent = this.client._entityCache.get(this.viaBotId);
if (!ent)
throw new Error("No input sender");
return ent;
}
}
}
}
}
// TODO fix this
_documentByAttribute(kind, condition) {
const doc = this.document;
if (doc) {
for (const attr of doc.attributes) {
if (attr instanceof kind) {
if (condition == undefined ||
(typeof condition == "function" && condition(attr))) {
return doc;
}
return undefined;
}
}
}
}
}
exports.CustomMessage = CustomMessage;