|
@@ -6,7 +6,7 @@ import type {
|
|
|
FileLike,
|
|
|
MarkupLike,
|
|
|
MessageIDLike,
|
|
|
- MessageLike,
|
|
|
+ MessageLike
|
|
|
} from "../define";
|
|
|
import { RequestIter } from "../requestIter";
|
|
|
import {
|
|
@@ -14,11 +14,13 @@ import {
|
|
|
_entityType,
|
|
|
TotalList,
|
|
|
isArrayLike,
|
|
|
- groupBy,
|
|
|
+ groupBy
|
|
|
} from "../Helpers";
|
|
|
import { getMessageId, getPeerId } from "../Utils";
|
|
|
import type { TelegramClient } from "../";
|
|
|
import { utils } from "../";
|
|
|
+import { _parseMessageText } from "./messageParse";
|
|
|
+import { _getPeer } from "./users";
|
|
|
|
|
|
const _MAX_CHUNK_SIZE = 100;
|
|
|
|
|
@@ -49,17 +51,17 @@ export class _MessagesIter extends RequestIter {
|
|
|
lastId?: number;
|
|
|
|
|
|
async _init({
|
|
|
- entity,
|
|
|
- offsetId,
|
|
|
- minId,
|
|
|
- maxId,
|
|
|
- fromUser,
|
|
|
- offsetDate,
|
|
|
- addOffset,
|
|
|
- filter,
|
|
|
- search,
|
|
|
- replyTo,
|
|
|
- }: MessageIterParams) {
|
|
|
+ entity,
|
|
|
+ offsetId,
|
|
|
+ minId,
|
|
|
+ maxId,
|
|
|
+ fromUser,
|
|
|
+ offsetDate,
|
|
|
+ addOffset,
|
|
|
+ filter,
|
|
|
+ search,
|
|
|
+ replyTo
|
|
|
+ }: MessageIterParams) {
|
|
|
if (entity) {
|
|
|
this.entity = await this.client.getInputEntity(entity);
|
|
|
} else {
|
|
@@ -116,7 +118,7 @@ export class _MessagesIter extends RequestIter {
|
|
|
offsetRate: undefined,
|
|
|
offsetPeer: new Api.InputPeerEmpty(),
|
|
|
offsetId: offsetId,
|
|
|
- limit: 1,
|
|
|
+ limit: 1
|
|
|
});
|
|
|
} else if (replyTo !== undefined) {
|
|
|
this.request = new Api.messages.GetReplies({
|
|
@@ -128,7 +130,7 @@ export class _MessagesIter extends RequestIter {
|
|
|
limit: 0,
|
|
|
maxId: 0,
|
|
|
minId: 0,
|
|
|
- hash: 0,
|
|
|
+ hash: 0
|
|
|
});
|
|
|
} else if (
|
|
|
search !== undefined ||
|
|
@@ -153,7 +155,7 @@ export class _MessagesIter extends RequestIter {
|
|
|
maxId: 0,
|
|
|
minId: 0,
|
|
|
hash: 0,
|
|
|
- fromId: fromUser,
|
|
|
+ fromId: fromUser
|
|
|
});
|
|
|
if (
|
|
|
filter instanceof Api.InputMessagesFilterEmpty &&
|
|
@@ -163,7 +165,7 @@ export class _MessagesIter extends RequestIter {
|
|
|
) {
|
|
|
for await (const m of this.client.iterMessages(this.entity, {
|
|
|
limit: 1,
|
|
|
- offsetDate: offsetDate,
|
|
|
+ offsetDate: offsetDate
|
|
|
})) {
|
|
|
this.request.offsetId = m.id + 1;
|
|
|
}
|
|
@@ -177,7 +179,7 @@ export class _MessagesIter extends RequestIter {
|
|
|
minId: 0,
|
|
|
maxId: 0,
|
|
|
addOffset: addOffset,
|
|
|
- hash: 0,
|
|
|
+ hash: 0
|
|
|
});
|
|
|
}
|
|
|
if (this.limit <= 0) {
|
|
@@ -247,7 +249,8 @@ export class _MessagesIter extends RequestIter {
|
|
|
try {
|
|
|
// if this fails it shouldn't be a big problem
|
|
|
message._finishInit(this.client, entities, this.entity);
|
|
|
- } catch (e) {}
|
|
|
+ } catch (e) {
|
|
|
+ }
|
|
|
message._entities = entities;
|
|
|
this.buffer?.push(message);
|
|
|
}
|
|
@@ -293,7 +296,7 @@ export class _MessagesIter extends RequestIter {
|
|
|
this.request.maxDate = -1;
|
|
|
} else {
|
|
|
if (!(this.request instanceof Api.messages.SearchGlobal)) {
|
|
|
- this.request.offsetDate = lastMessage.date;
|
|
|
+ this.request.offsetDate = lastMessage.date!;
|
|
|
}
|
|
|
}
|
|
|
if (this.request instanceof Api.messages.SearchGlobal) {
|
|
@@ -352,13 +355,13 @@ export class _IDsIter extends RequestIter {
|
|
|
r = await this.client.invoke(
|
|
|
new Api.channels.GetMessages({
|
|
|
channel: this._entity,
|
|
|
- id: ids,
|
|
|
+ id: ids
|
|
|
})
|
|
|
);
|
|
|
} catch (e) {
|
|
|
if (e.message == "MESSAGE_IDS_EMPTY") {
|
|
|
r = new Api.messages.MessagesNotModified({
|
|
|
- count: ids.length,
|
|
|
+ count: ids.length
|
|
|
});
|
|
|
} else {
|
|
|
throw e;
|
|
@@ -367,11 +370,11 @@ export class _IDsIter extends RequestIter {
|
|
|
} else {
|
|
|
r = await this.client.invoke(
|
|
|
new Api.messages.GetMessages({
|
|
|
- id: ids,
|
|
|
+ id: ids
|
|
|
})
|
|
|
);
|
|
|
if (this._entity) {
|
|
|
- fromId = await this.client._getPeer(this._entity);
|
|
|
+ fromId = await _getPeer(this.client, this._entity);
|
|
|
}
|
|
|
}
|
|
|
if (r instanceof Api.messages.MessagesNotModified) {
|
|
@@ -400,57 +403,152 @@ export class _IDsIter extends RequestIter {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Interface for iterating over messages. used in both {@link iterMessages} and {@link getMessages}.
|
|
|
+ */
|
|
|
export interface IterMessagesParams {
|
|
|
+ /** Number of messages to be retrieved.<br/>
|
|
|
+ * Due to limitations with the API retrieving more than 3000 messages will take longer than half a minute. (might even take longer)<br/>
|
|
|
+ * if undefined is passed instead of a number the library will try to retrieve all the messages.*/
|
|
|
limit?: number;
|
|
|
+ /** Offset date (messages previous to this date will be retrieved). Exclusive. */
|
|
|
offsetDate?: DateLike;
|
|
|
+ /** Offset message ID (only messages previous to the given ID will be retrieved). Exclusive. */
|
|
|
offsetId?: number;
|
|
|
+ /** All the messages with a higher (newer) ID or equal to this will be excluded. */
|
|
|
maxId?: number;
|
|
|
+ /** All the messages with a lower (older) ID or equal to this will be excluded. */
|
|
|
minId?: number;
|
|
|
+ /** Additional message offset (all of the specified offsets + this offset = older messages). */
|
|
|
addOffset?: number;
|
|
|
+ /** The string to be used as a search query. */
|
|
|
search?: string;
|
|
|
+ /** The filter to use when returning messages.<br/>
|
|
|
+ * For instance, InputMessagesFilterPhotos would yield only messages containing photos.
|
|
|
+ */
|
|
|
filter?: Api.TypeMessagesFilter | Api.TypeMessagesFilter[];
|
|
|
+ /** Only messages from this user will be returned. */
|
|
|
fromUser?: EntityLike;
|
|
|
+ /** Wait time (in seconds) between different GetHistory requests.<br/>
|
|
|
+ * Use this parameter to avoid hitting the FloodWaitError as needed.<br/>
|
|
|
+ * If left to undefined, it will default to 1 second only if the number of messages is higher than 3000.
|
|
|
+ * If the ids parameter is used, this time will default to 10 seconds only if the amount of IDs is higher than 300.
|
|
|
+ */
|
|
|
waitTime?: number;
|
|
|
+ /** A single integer ID (or several IDs) for the message that should be returned.<br/>
|
|
|
+ * This parameter takes precedence over the rest (which will be ignored if this is set).<br/>
|
|
|
+ * This can for instance be used to get the message with ID 123 from a channel.<br/>
|
|
|
+ * **Note** that if the message doesn"t exist, undefined will appear in its place.
|
|
|
+ */
|
|
|
ids?: number | number[] | Api.TypeInputMessage | Api.TypeInputMessage[];
|
|
|
+ /** If set to `true`, the messages will be returned in reverse order (from oldest to newest, instead of the default newest to oldest).<br/>
|
|
|
+ * This also means that the meaning of offsetId and offsetDate parameters is reversed, although they will still be exclusive.<br/>
|
|
|
+ * `minId` becomes equivalent to `offsetId` instead of being `maxId` as well since messages are returned in ascending order.<br/>
|
|
|
+ * You cannot use this if both entity and ids are undefined.
|
|
|
+ */
|
|
|
reverse?: boolean;
|
|
|
+ /** If set to a message ID, the messages that reply to this ID will be returned.<br/>
|
|
|
+ * This feature is also known as comments in posts of broadcast channels, or viewing threads in groups.<br/>
|
|
|
+ * This feature can only be used in broadcast channels and their linked supergroups. Using it in a chat or private conversation will result in PEER_ID_INVALID error.<br/>
|
|
|
+ * When using this parameter, the filter and search parameters have no effect, since Telegram's API doesn't support searching messages in replies.
|
|
|
+ */
|
|
|
replyTo?: number;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Interface for sending a message. only message is required
|
|
|
+ */
|
|
|
export interface SendMessageParams {
|
|
|
+ /** The message to be sent, or another message object to resend as a copy.<br/>
|
|
|
+ * The maximum length for a message is 35,000 bytes or 4,096 characters.<br/>
|
|
|
+ * Longer messages will not be sliced automatically, and you should slice them manually if the text to send is longer than said length. */
|
|
|
message: MessageLike;
|
|
|
+ /** Whether to reply to a message or not. If an integer is provided, it should be the ID of the message that it should reply to. */
|
|
|
replyTo?: number | Api.Message;
|
|
|
+ /** Optional attributes that override the inferred ones, like DocumentAttributeFilename and so on. */
|
|
|
+ attributes?: Api.TypeDocumentAttribute[];
|
|
|
+ /** See the {@link parseMode} property for allowed values. Markdown parsing will be used by default. */
|
|
|
parseMode?: any;
|
|
|
+ /** A list of message formatting entities. When provided, the parseMode is ignored. */
|
|
|
formattingEntities?: Api.TypeMessageEntity[];
|
|
|
+ /** Should the link preview be shown? */
|
|
|
linkPreview?: boolean;
|
|
|
- file?: FileLike | FileLike[];
|
|
|
+ /** Sends a message with a file attached (e.g. a photo, video, audio or document). The message may be empty. */
|
|
|
+ file?: FileLike;
|
|
|
+ /** Optional JPEG thumbnail (for documents). Telegram will ignore this parameter unless you pass a .jpg file!<br/>
|
|
|
+ * The file must also be small in dimensions and in disk size. Successful thumbnails were files below 20kB and 320x320px.<br/>
|
|
|
+ * Width/height and dimensions/size ratios may be important.
|
|
|
+ * For Telegram to accept a thumbnail, you must provide the dimensions of the underlying media through `attributes:` with DocumentAttributesVideo.
|
|
|
+ */
|
|
|
+ thumb?: FileLike;
|
|
|
+ /** Whether to send the given file as a document or not. */
|
|
|
forceDocument?: false;
|
|
|
+ /** Whether the existing draft should be cleared or not. */
|
|
|
clearDraft?: false;
|
|
|
+ /** The matrix (list of lists), row list or button to be shown after sending the message.<br/>
|
|
|
+ * This parameter will only work if you have signed in as a bot. You can also pass your own ReplyMarkup here.<br/>
|
|
|
+ * <br/>
|
|
|
+ * All the following limits apply together:
|
|
|
+ * - There can be 100 buttons at most (any more are ignored).
|
|
|
+ * - There can be 8 buttons per row at most (more are ignored).
|
|
|
+ * - The maximum callback data per button is 64 bytes.
|
|
|
+ * - The maximum data that can be embedded in total is just over 4KB, shared between inline callback data and text.
|
|
|
+ */
|
|
|
buttons?: MarkupLike;
|
|
|
+ /** Whether the message should notify people in a broadcast channel or not. Defaults to false, which means it will notify them. Set it to True to alter this behaviour. */
|
|
|
silent?: boolean;
|
|
|
+ /** Whether the sent video supports streaming or not.<br/>
|
|
|
+ * Note that Telegram only recognizes as streamable some formats like MP4, and others like AVI or MKV will not work.<br/>
|
|
|
+ * You should convert these to MP4 before sending if you want them to be streamable. Unsupported formats will result in VideoContentTypeError. */
|
|
|
+ supportStreaming?: boolean;
|
|
|
+ /** If set, the message won't send immediately, and instead it will be scheduled to be automatically sent at a later time. */
|
|
|
schedule?: DateLike;
|
|
|
}
|
|
|
|
|
|
+/** interface used for forwarding messages */
|
|
|
export interface ForwardMessagesParams {
|
|
|
+ /** The message(s) to forward, or their integer IDs. */
|
|
|
messages: MessageIDLike[];
|
|
|
+ /** If the given messages are integer IDs and not instances of the Message class, this must be specified in order for the forward to work.<br/> */
|
|
|
fromPeer: EntityLike;
|
|
|
+ /** Whether the message should notify people with sound or not.<br/>
|
|
|
+ * Defaults to false (send with a notification sound unless the person has the chat muted). Set it to true to alter this behaviour. */
|
|
|
silent?: boolean;
|
|
|
+ /** If set, the message(s) won't forward immediately, and instead they will be scheduled to be automatically sent at a later time. */
|
|
|
schedule?: DateLike;
|
|
|
}
|
|
|
|
|
|
+/** Interface for editing messages */
|
|
|
export interface EditMessageParams {
|
|
|
+ /** The ID of the message (or Message itself) to be edited. If the entity was a Message, then this message will be treated as the new text. */
|
|
|
message: Api.Message | number;
|
|
|
+ /** The new text of the message. Does nothing if the entity was a Message. */
|
|
|
text: string;
|
|
|
+ /** See the {@link TelegramClient.parseMode} property for allowed values. Markdown parsing will be used by default. */
|
|
|
parseMode?: any;
|
|
|
+ /** A list of message formatting entities. When provided, the parseMode is ignored. */
|
|
|
formattingEntities?: Api.TypeMessageEntity[];
|
|
|
+ /** Should the link preview be shown? */
|
|
|
linkPreview?: boolean;
|
|
|
+ /** The file object that should replace the existing media in the message. // not supported yet. */
|
|
|
file?: FileLike | FileLike[];
|
|
|
+ /** thumbnail to be edited. // not supported yet */
|
|
|
forceDocument?: false;
|
|
|
+ /** The matrix (list of lists), row list or button to be shown after sending the message.<br/>
|
|
|
+ * This parameter will only work if you have signed in as a bot. You can also pass your own ReplyMarkup here.<br/>
|
|
|
+ * <br/>
|
|
|
+ * All the following limits apply together:
|
|
|
+ * - There can be 100 buttons at most (any more are ignored).
|
|
|
+ * - There can be 8 buttons per row at most (more are ignored).
|
|
|
+ * - The maximum callback data per button is 64 bytes.
|
|
|
+ * - The maximum data that can be embedded in total is just over 4KB, shared between inline callback data and text.
|
|
|
+ */
|
|
|
buttons?: MarkupLike;
|
|
|
+ /** If set, the message won't be edited immediately, and instead it will be scheduled to be automatically edited at a later time. */
|
|
|
schedule?: DateLike;
|
|
|
}
|
|
|
|
|
|
-// MessageMethods {
|
|
|
-
|
|
|
+// MessageMethods
|
|
|
export function iterMessages(
|
|
|
client: TelegramClient,
|
|
|
entity: EntityLike | undefined,
|
|
@@ -467,7 +565,7 @@ export function iterMessages(
|
|
|
waitTime,
|
|
|
ids,
|
|
|
reverse = false,
|
|
|
- replyTo,
|
|
|
+ replyTo
|
|
|
}: IterMessagesParams
|
|
|
) {
|
|
|
if (ids) {
|
|
@@ -482,11 +580,11 @@ export function iterMessages(
|
|
|
idsArray.length,
|
|
|
{
|
|
|
reverse: reverse,
|
|
|
- waitTime: waitTime,
|
|
|
+ waitTime: waitTime
|
|
|
},
|
|
|
{
|
|
|
entity: entity,
|
|
|
- ids: idsArray,
|
|
|
+ ids: idsArray
|
|
|
}
|
|
|
);
|
|
|
}
|
|
@@ -495,7 +593,7 @@ export function iterMessages(
|
|
|
limit || 1,
|
|
|
{
|
|
|
waitTime: waitTime,
|
|
|
- reverse: reverse,
|
|
|
+ reverse: reverse
|
|
|
},
|
|
|
{
|
|
|
entity: entity,
|
|
@@ -507,11 +605,12 @@ export function iterMessages(
|
|
|
addOffset: addOffset,
|
|
|
filter: filter,
|
|
|
search: search,
|
|
|
- replyTo: replyTo,
|
|
|
+ replyTo: replyTo
|
|
|
}
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+/** @hidden */
|
|
|
export async function getMessages(
|
|
|
client: TelegramClient,
|
|
|
entity: EntityLike | undefined,
|
|
@@ -537,27 +636,44 @@ export async function getMessages(
|
|
|
}
|
|
|
|
|
|
// region Message
|
|
|
-
|
|
|
+/** @hidden */
|
|
|
export async function sendMessage(
|
|
|
client: TelegramClient,
|
|
|
entity: EntityLike,
|
|
|
{
|
|
|
message,
|
|
|
replyTo,
|
|
|
+ attributes,
|
|
|
parseMode,
|
|
|
formattingEntities,
|
|
|
linkPreview = true,
|
|
|
file,
|
|
|
+ thumb,
|
|
|
forceDocument,
|
|
|
clearDraft,
|
|
|
buttons,
|
|
|
silent,
|
|
|
- schedule,
|
|
|
+ supportStreaming,
|
|
|
+ schedule
|
|
|
}: SendMessageParams
|
|
|
) {
|
|
|
if (file) {
|
|
|
- throw new Error("Not Supported Yet");
|
|
|
- //return this.sendFile();
|
|
|
+ return client.sendFile(entity, {
|
|
|
+ file: file,
|
|
|
+ caption: message ? (typeof message == "string" ? message : message.message) : "",
|
|
|
+ forceDocument: forceDocument,
|
|
|
+ clearDraft: clearDraft,
|
|
|
+ replyTo: replyTo,
|
|
|
+ attributes: attributes,
|
|
|
+ thumb: thumb,
|
|
|
+ supportsStreaming: supportStreaming,
|
|
|
+ parseMode: parseMode,
|
|
|
+ formattingEntities: formattingEntities,
|
|
|
+ silent: silent,
|
|
|
+ scheduleDate: schedule,
|
|
|
+ buttons: buttons
|
|
|
+ });
|
|
|
+
|
|
|
}
|
|
|
entity = await client.getInputEntity(entity);
|
|
|
let markup, request;
|
|
@@ -596,12 +712,13 @@ export async function sendMessage(
|
|
|
entities: message.entities,
|
|
|
clearDraft: clearDraft,
|
|
|
noWebpage: !(message.media instanceof Api.MessageMediaWebPage),
|
|
|
- scheduleDate: schedule,
|
|
|
+ scheduleDate: schedule
|
|
|
});
|
|
|
message = message.message;
|
|
|
} else {
|
|
|
if (formattingEntities == undefined) {
|
|
|
- [message, formattingEntities] = await client._parseMessageText(
|
|
|
+ [message, formattingEntities] = _parseMessageText(
|
|
|
+ client,
|
|
|
message,
|
|
|
parseMode
|
|
|
);
|
|
@@ -620,21 +737,21 @@ export async function sendMessage(
|
|
|
clearDraft: clearDraft,
|
|
|
silent: silent,
|
|
|
replyMarkup: client.buildReplyMarkup(buttons),
|
|
|
- scheduleDate: schedule,
|
|
|
+ scheduleDate: schedule
|
|
|
});
|
|
|
}
|
|
|
const result = await client.invoke(request);
|
|
|
if (result instanceof Api.UpdateShortSentMessage) {
|
|
|
const msg = new Message({
|
|
|
id: result.id,
|
|
|
- peerId: await client._getPeer(entity),
|
|
|
+ peerId: await _getPeer(client, entity),
|
|
|
message: message,
|
|
|
date: result.date,
|
|
|
out: result.out,
|
|
|
media: result.media,
|
|
|
entities: result.entities,
|
|
|
replyMarkup: request.replyMarkup,
|
|
|
- ttlPeriod: result.ttlPeriod,
|
|
|
+ ttlPeriod: result.ttlPeriod
|
|
|
});
|
|
|
msg._finishInit(client, new Map(), entity);
|
|
|
return msg;
|
|
@@ -642,6 +759,7 @@ export async function sendMessage(
|
|
|
return client._getResponseMessage(request, result, entity) as Message;
|
|
|
}
|
|
|
|
|
|
+/** @hidden */
|
|
|
export async function forwardMessages(
|
|
|
client: TelegramClient,
|
|
|
entity: EntityLike,
|
|
@@ -666,10 +784,8 @@ export async function forwardMessages(
|
|
|
}
|
|
|
};
|
|
|
const sent: Message[] = [];
|
|
|
- for (let [chatId, chunk] of groupBy(messages, getKey) as Map<
|
|
|
- number,
|
|
|
- Message[] | number[]
|
|
|
- >) {
|
|
|
+ for (let [chatId, chunk] of groupBy(messages, getKey) as Map<number,
|
|
|
+ Message[] | number[]>) {
|
|
|
let chat;
|
|
|
let numbers: number[] = [];
|
|
|
if (typeof chunk[0] == "number") {
|
|
@@ -685,7 +801,7 @@ export async function forwardMessages(
|
|
|
id: numbers,
|
|
|
toPeer: entity,
|
|
|
silent: silent,
|
|
|
- scheduleDate: schedule,
|
|
|
+ scheduleDate: schedule
|
|
|
});
|
|
|
const result = await client.invoke(request);
|
|
|
sent.push(
|
|
@@ -695,11 +811,7 @@ export async function forwardMessages(
|
|
|
return sent;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Used to edit a message by changing it's text or media
|
|
|
- * message refers to the message to be edited not what to edit
|
|
|
- * text refers to the new text
|
|
|
- */
|
|
|
+/** @hidden */
|
|
|
export async function editMessage(
|
|
|
client: TelegramClient,
|
|
|
entity: EntityLike,
|
|
@@ -712,12 +824,13 @@ export async function editMessage(
|
|
|
file,
|
|
|
forceDocument,
|
|
|
buttons,
|
|
|
- schedule,
|
|
|
+ schedule
|
|
|
}: EditMessageParams
|
|
|
) {
|
|
|
entity = await client.getInputEntity(entity);
|
|
|
if (formattingEntities == undefined) {
|
|
|
- [text, formattingEntities] = await client._parseMessageText(
|
|
|
+ [text, formattingEntities] = _parseMessageText(
|
|
|
+ client,
|
|
|
text,
|
|
|
parseMode
|
|
|
);
|
|
@@ -730,7 +843,7 @@ export async function editMessage(
|
|
|
entities: formattingEntities,
|
|
|
//media: no media for now,
|
|
|
replyMarkup: client.buildReplyMarkup(buttons),
|
|
|
- scheduleDate: schedule,
|
|
|
+ scheduleDate: schedule
|
|
|
});
|
|
|
const result = await client.invoke(request);
|
|
|
return client._getResponseMessage(request, result, entity) as Message;
|