feat: updated to layer 166
This commit is contained in:
parent
49d9d5999d
commit
fc42dcb973
32 changed files with 842 additions and 179 deletions
|
@ -66,6 +66,7 @@ import { markChatUnread } from './methods/chats/mark-chat-unread.js'
|
||||||
import { reorderUsernames } from './methods/chats/reorder-usernames.js'
|
import { reorderUsernames } from './methods/chats/reorder-usernames.js'
|
||||||
import { restrictChatMember } from './methods/chats/restrict-chat-member.js'
|
import { restrictChatMember } from './methods/chats/restrict-chat-member.js'
|
||||||
import { saveDraft } from './methods/chats/save-draft.js'
|
import { saveDraft } from './methods/chats/save-draft.js'
|
||||||
|
import { setChatColor } from './methods/chats/set-chat-color.js'
|
||||||
import { setChatDefaultPermissions } from './methods/chats/set-chat-default-permissions.js'
|
import { setChatDefaultPermissions } from './methods/chats/set-chat-default-permissions.js'
|
||||||
import { setChatDescription } from './methods/chats/set-chat-description.js'
|
import { setChatDescription } from './methods/chats/set-chat-description.js'
|
||||||
import { setChatPhoto } from './methods/chats/set-chat-photo.js'
|
import { setChatPhoto } from './methods/chats/set-chat-photo.js'
|
||||||
|
@ -153,6 +154,7 @@ import { sendCopy, SendCopyParams } from './methods/messages/send-copy.js'
|
||||||
import { sendCopyGroup, SendCopyGroupParams } from './methods/messages/send-copy-group.js'
|
import { sendCopyGroup, SendCopyGroupParams } from './methods/messages/send-copy-group.js'
|
||||||
import { sendMedia } from './methods/messages/send-media.js'
|
import { sendMedia } from './methods/messages/send-media.js'
|
||||||
import { sendMediaGroup } from './methods/messages/send-media-group.js'
|
import { sendMediaGroup } from './methods/messages/send-media-group.js'
|
||||||
|
import { QuoteParamsFrom, quoteWithMedia, quoteWithMediaGroup, quoteWithText } from './methods/messages/send-quote.js'
|
||||||
import { sendReaction } from './methods/messages/send-reaction.js'
|
import { sendReaction } from './methods/messages/send-reaction.js'
|
||||||
import { replyMedia, replyMediaGroup, replyText } from './methods/messages/send-reply.js'
|
import { replyMedia, replyMediaGroup, replyText } from './methods/messages/send-reply.js'
|
||||||
import { sendScheduled } from './methods/messages/send-scheduled.js'
|
import { sendScheduled } from './methods/messages/send-scheduled.js'
|
||||||
|
@ -1687,6 +1689,39 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* @param draft Draft message, or `null` to delete.
|
* @param draft Draft message, or `null` to delete.
|
||||||
*/
|
*/
|
||||||
saveDraft(chatId: InputPeerLike, draft: null | Omit<tl.RawDraftMessage, '_' | 'date'>): Promise<void>
|
saveDraft(chatId: InputPeerLike, draft: null | Omit<tl.RawDraftMessage, '_' | 'date'>): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set chat name/replies color and optionally background pattern
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
setChatColor(params: {
|
||||||
|
/**
|
||||||
|
* Peer where to update the color.
|
||||||
|
*
|
||||||
|
* By default will change the color for the current user
|
||||||
|
*/
|
||||||
|
peer?: InputPeerLike
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color identificator
|
||||||
|
*
|
||||||
|
* Note that this value is **not** an RGB color representation. Instead, it is
|
||||||
|
* a number which should be used to pick a color from a predefined
|
||||||
|
* list of colors:
|
||||||
|
* - `0-6` are the default colors used by Telegram clients:
|
||||||
|
* `red, orange, purple, green, sea, blue, pink`
|
||||||
|
* - `>= 7` are returned by `help.getAppConfig`.
|
||||||
|
*/
|
||||||
|
color: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Background pattern emoji ID.
|
||||||
|
*
|
||||||
|
* Must be an adaptive emoji, otherwise the request will fail.
|
||||||
|
*/
|
||||||
|
backgroundEmojiId?: tl.Long
|
||||||
|
}): Promise<void>
|
||||||
/**
|
/**
|
||||||
* Change default chat permissions for all members.
|
* Change default chat permissions for all members.
|
||||||
*
|
*
|
||||||
|
@ -2916,6 +2951,14 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*/
|
*/
|
||||||
disableWebPreview?: boolean
|
disableWebPreview?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For bots: new reply markup.
|
* For bots: new reply markup.
|
||||||
* If omitted, existing markup will be removed.
|
* If omitted, existing markup will be removed.
|
||||||
|
@ -3001,6 +3044,14 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* to the client's update handler.
|
* to the client's update handler.
|
||||||
*/
|
*/
|
||||||
shouldDispatch?: true
|
shouldDispatch?: true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
},
|
},
|
||||||
): Promise<Message>
|
): Promise<Message>
|
||||||
/**
|
/**
|
||||||
|
@ -3224,7 +3275,7 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
/**
|
/**
|
||||||
* For messages containing a reply, fetch the message that is being replied.
|
* For messages containing a reply, fetch the message that is being replied.
|
||||||
*
|
*
|
||||||
* Note that even if a message has {@link replyToMessageId},
|
* Note that even if a message has {@link replyToMessage},
|
||||||
* the message itself may have been deleted, in which case
|
* the message itself may have been deleted, in which case
|
||||||
* this method will also return `null`.
|
* this method will also return `null`.
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
|
@ -3668,6 +3719,14 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
medias: (InputMediaLike | string)[],
|
medias: (InputMediaLike | string)[],
|
||||||
params?: CommonSendParams & {
|
params?: CommonSendParams & {
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that will be called after some part has been uploaded.
|
* Function that will be called after some part has been uploaded.
|
||||||
* Only used when a file that requires uploading is passed,
|
* Only used when a file that requires uploading is passed,
|
||||||
|
@ -3703,6 +3762,14 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*/
|
*/
|
||||||
replyMarkup?: ReplyMarkup
|
replyMarkup?: ReplyMarkup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invert?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override caption for `media`.
|
* Override caption for `media`.
|
||||||
*
|
*
|
||||||
|
@ -3730,6 +3797,30 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
},
|
},
|
||||||
): Promise<Message>
|
): Promise<Message>
|
||||||
|
/** Send a text in reply to a given quote */
|
||||||
|
quoteWithText(
|
||||||
|
message: Message,
|
||||||
|
params: QuoteParamsFrom<Parameters<typeof sendText>[3]> & {
|
||||||
|
/** Text to send */
|
||||||
|
text: Parameters<typeof sendText>[2]
|
||||||
|
},
|
||||||
|
): ReturnType<typeof sendText>
|
||||||
|
/** Send a media in reply to a given quote */
|
||||||
|
quoteWithMedia(
|
||||||
|
message: Message,
|
||||||
|
params: QuoteParamsFrom<Parameters<typeof sendMedia>[3]> & {
|
||||||
|
/** Media to send */
|
||||||
|
media: Parameters<typeof sendMedia>[2]
|
||||||
|
},
|
||||||
|
): ReturnType<typeof sendMedia>
|
||||||
|
/** Send a media group in reply to a given quote */
|
||||||
|
quoteWithMediaGroup(
|
||||||
|
message: Message,
|
||||||
|
params: QuoteParamsFrom<Parameters<typeof sendMediaGroup>[3]> & {
|
||||||
|
/** Media group to send */
|
||||||
|
medias: Parameters<typeof sendMediaGroup>[2]
|
||||||
|
},
|
||||||
|
): ReturnType<typeof sendMediaGroup>
|
||||||
/**
|
/**
|
||||||
* Send or remove a reaction.
|
* Send or remove a reaction.
|
||||||
*
|
*
|
||||||
|
@ -3804,6 +3895,14 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* Whether to disable links preview in this message
|
* Whether to disable links preview in this message
|
||||||
*/
|
*/
|
||||||
disableWebPreview?: boolean
|
disableWebPreview?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
},
|
},
|
||||||
): Promise<Message>
|
): Promise<Message>
|
||||||
/**
|
/**
|
||||||
|
@ -5194,6 +5293,7 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
reorderUsernames = reorderUsernames.bind(null, this)
|
reorderUsernames = reorderUsernames.bind(null, this)
|
||||||
restrictChatMember = restrictChatMember.bind(null, this)
|
restrictChatMember = restrictChatMember.bind(null, this)
|
||||||
saveDraft = saveDraft.bind(null, this)
|
saveDraft = saveDraft.bind(null, this)
|
||||||
|
setChatColor = setChatColor.bind(null, this)
|
||||||
setChatDefaultPermissions = setChatDefaultPermissions.bind(null, this)
|
setChatDefaultPermissions = setChatDefaultPermissions.bind(null, this)
|
||||||
setChatDescription = setChatDescription.bind(null, this)
|
setChatDescription = setChatDescription.bind(null, this)
|
||||||
setChatPhoto = setChatPhoto.bind(null, this)
|
setChatPhoto = setChatPhoto.bind(null, this)
|
||||||
|
@ -5288,6 +5388,9 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
sendCopy = sendCopy.bind(null, this)
|
sendCopy = sendCopy.bind(null, this)
|
||||||
sendMediaGroup = sendMediaGroup.bind(null, this)
|
sendMediaGroup = sendMediaGroup.bind(null, this)
|
||||||
sendMedia = sendMedia.bind(null, this)
|
sendMedia = sendMedia.bind(null, this)
|
||||||
|
quoteWithText = quoteWithText.bind(null, this)
|
||||||
|
quoteWithMedia = quoteWithMedia.bind(null, this)
|
||||||
|
quoteWithMediaGroup = quoteWithMediaGroup.bind(null, this)
|
||||||
sendReaction = sendReaction.bind(null, this)
|
sendReaction = sendReaction.bind(null, this)
|
||||||
replyText = replyText.bind(null, this)
|
replyText = replyText.bind(null, this)
|
||||||
replyMedia = replyMedia.bind(null, this)
|
replyMedia = replyMedia.bind(null, this)
|
||||||
|
|
71
packages/client/src/methods/chats/set-chat-color.ts
Normal file
71
packages/client/src/methods/chats/set-chat-color.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { BaseTelegramClient, MtTypeAssertionError, tl } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
|
import { isInputPeerChannel, isInputPeerUser, normalizeToInputChannel } from '../../utils/index.js'
|
||||||
|
import { getAuthState } from '../auth/_state.js'
|
||||||
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Set chat name/replies color and optionally background pattern
|
||||||
|
*/
|
||||||
|
export async function setChatColor(
|
||||||
|
client: BaseTelegramClient,
|
||||||
|
params: {
|
||||||
|
/**
|
||||||
|
* Peer where to update the color.
|
||||||
|
*
|
||||||
|
* By default will change the color for the current user
|
||||||
|
*/
|
||||||
|
peer?: InputPeerLike
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color identificator
|
||||||
|
*
|
||||||
|
* Note that this value is **not** an RGB color representation. Instead, it is
|
||||||
|
* a number which should be used to pick a color from a predefined
|
||||||
|
* list of colors:
|
||||||
|
* - `0-6` are the default colors used by Telegram clients:
|
||||||
|
* `red, orange, purple, green, sea, blue, pink`
|
||||||
|
* - `>= 7` are returned by `help.getAppConfig`.
|
||||||
|
*/
|
||||||
|
color: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Background pattern emoji ID.
|
||||||
|
*
|
||||||
|
* Must be an adaptive emoji, otherwise the request will fail.
|
||||||
|
*/
|
||||||
|
backgroundEmojiId?: tl.Long
|
||||||
|
},
|
||||||
|
): Promise<void> {
|
||||||
|
const { color, backgroundEmojiId } = params
|
||||||
|
const peer = await resolvePeer(client, params.peer ?? 'me')
|
||||||
|
|
||||||
|
if (isInputPeerChannel(peer)) {
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'channels.updateColor',
|
||||||
|
channel: normalizeToInputChannel(peer),
|
||||||
|
color,
|
||||||
|
backgroundEmojiId,
|
||||||
|
})
|
||||||
|
|
||||||
|
client.network.handleUpdate(res)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInputPeerUser(peer)) {
|
||||||
|
if (peer._ !== 'inputPeerSelf' && peer.userId !== getAuthState(client).userId) {
|
||||||
|
throw new MtTypeAssertionError('setChatColor', 'inputPeerSelf | inputPeerUser', peer._)
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.call({
|
||||||
|
_: 'account.updateColor',
|
||||||
|
color,
|
||||||
|
backgroundEmojiId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MtInvalidPeerTypeError(peer, 'channel | user')
|
||||||
|
}
|
|
@ -202,6 +202,16 @@ export async function _normalizeInputMedia(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (media.type === 'webpage') {
|
||||||
|
return {
|
||||||
|
_: 'inputMediaWebPage',
|
||||||
|
forceLargeMedia: media.size === 'large',
|
||||||
|
forceSmallMedia: media.size === 'small',
|
||||||
|
optional: !media.required,
|
||||||
|
url: media.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let inputFile: tl.TypeInputFile | undefined = undefined
|
let inputFile: tl.TypeInputFile | undefined = undefined
|
||||||
let thumb: tl.TypeInputFile | undefined = undefined
|
let thumb: tl.TypeInputFile | undefined = undefined
|
||||||
let mime = 'application/octet-stream'
|
let mime = 'application/octet-stream'
|
||||||
|
|
|
@ -80,7 +80,8 @@ export async function uploadMedia(
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
return parseDocument(res.document, res) as any
|
return parseDocument(res.document, res) as any
|
||||||
case 'inputMediaStory':
|
case 'inputMediaStory':
|
||||||
throw new MtArgumentError("This media (story) can't be uploaded")
|
case 'inputMediaWebPage':
|
||||||
|
throw new MtArgumentError(`This media (${normMedia._}) can't be uploaded`)
|
||||||
default:
|
default:
|
||||||
assertNever(normMedia)
|
assertNever(normMedia)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,14 @@ export async function editInlineMessage(
|
||||||
*/
|
*/
|
||||||
disableWebPreview?: boolean
|
disableWebPreview?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For bots: new reply markup.
|
* For bots: new reply markup.
|
||||||
* If omitted, existing markup will be removed.
|
* If omitted, existing markup will be removed.
|
||||||
|
@ -108,6 +116,7 @@ export async function editInlineMessage(
|
||||||
message: content,
|
message: content,
|
||||||
entities,
|
entities,
|
||||||
media,
|
media,
|
||||||
|
invertMedia: params.invertMedia,
|
||||||
},
|
},
|
||||||
{ dcId: id.dcId },
|
{ dcId: id.dcId },
|
||||||
)
|
)
|
||||||
|
|
|
@ -84,6 +84,14 @@ export async function editMessage(
|
||||||
* to the client's update handler.
|
* to the client's update handler.
|
||||||
*/
|
*/
|
||||||
shouldDispatch?: true
|
shouldDispatch?: true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
},
|
},
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
const { chatId, message } = normalizeInputMessageId(params)
|
const { chatId, message } = normalizeInputMessageId(params)
|
||||||
|
@ -119,6 +127,7 @@ export async function editMessage(
|
||||||
message: content,
|
message: content,
|
||||||
entities,
|
entities,
|
||||||
media,
|
media,
|
||||||
|
invertMedia: params.invertMedia,
|
||||||
})
|
})
|
||||||
|
|
||||||
return _findMessageInUpdate(client, res, true, !params.shouldDispatch)
|
return _findMessageInUpdate(client, res, true, !params.shouldDispatch)
|
||||||
|
|
|
@ -7,12 +7,12 @@ import { getMessagesUnsafe } from './get-messages-unsafe.js'
|
||||||
/**
|
/**
|
||||||
* For messages containing a reply, fetch the message that is being replied.
|
* For messages containing a reply, fetch the message that is being replied.
|
||||||
*
|
*
|
||||||
* Note that even if a message has {@link replyToMessageId},
|
* Note that even if a message has {@link replyToMessage},
|
||||||
* the message itself may have been deleted, in which case
|
* the message itself may have been deleted, in which case
|
||||||
* this method will also return `null`.
|
* this method will also return `null`.
|
||||||
*/
|
*/
|
||||||
export async function getReplyTo(client: BaseTelegramClient, message: Message): Promise<Message | null> {
|
export async function getReplyTo(client: BaseTelegramClient, message: Message): Promise<Message | null> {
|
||||||
if (!message.replyToMessageId) {
|
if (!message.replyToMessage?.id) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,12 @@ export function answerText(
|
||||||
message: Message,
|
message: Message,
|
||||||
...params: ParametersSkip2<typeof sendText>
|
...params: ParametersSkip2<typeof sendText>
|
||||||
): ReturnType<typeof sendText> {
|
): ReturnType<typeof sendText> {
|
||||||
if (!message.isTopicMessage || !message.replyToThreadId) {
|
if (!message.isTopicMessage || !message.replyToMessage?.threadId) {
|
||||||
return sendText(client, message.chat.inputPeer, ...params)
|
return sendText(client, message.chat.inputPeer, ...params)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [text, params_ = {}] = params
|
const [text, params_ = {}] = params
|
||||||
params_.replyTo = message.replyToThreadId
|
params_.replyTo = message.replyToMessage.threadId
|
||||||
|
|
||||||
return sendText(client, message.chat.inputPeer, text, params_)
|
return sendText(client, message.chat.inputPeer, text, params_)
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,12 @@ export function answerMedia(
|
||||||
message: Message,
|
message: Message,
|
||||||
...params: ParametersSkip2<typeof sendMedia>
|
...params: ParametersSkip2<typeof sendMedia>
|
||||||
): ReturnType<typeof sendMedia> {
|
): ReturnType<typeof sendMedia> {
|
||||||
if (!message.isTopicMessage || !message.replyToThreadId) {
|
if (!message.isTopicMessage || !message.replyToMessage?.threadId) {
|
||||||
return sendMedia(client, message.chat.inputPeer, ...params)
|
return sendMedia(client, message.chat.inputPeer, ...params)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [media, params_ = {}] = params
|
const [media, params_ = {}] = params
|
||||||
params_.replyTo = message.replyToThreadId
|
params_.replyTo = message.replyToMessage.threadId
|
||||||
|
|
||||||
return sendMedia(client, message.chat.inputPeer, media, params_)
|
return sendMedia(client, message.chat.inputPeer, media, params_)
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ export function answerMediaGroup(
|
||||||
message: Message,
|
message: Message,
|
||||||
...params: ParametersSkip2<typeof sendMediaGroup>
|
...params: ParametersSkip2<typeof sendMediaGroup>
|
||||||
): ReturnType<typeof sendMediaGroup> {
|
): ReturnType<typeof sendMediaGroup> {
|
||||||
if (!message.isTopicMessage || !message.replyToThreadId) {
|
if (!message.isTopicMessage || !message.replyToMessage?.threadId) {
|
||||||
return sendMediaGroup(client, message.chat.inputPeer, ...params)
|
return sendMediaGroup(client, message.chat.inputPeer, ...params)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [media, params_ = {}] = params
|
const [media, params_ = {}] = params
|
||||||
params_.replyTo = message.replyToThreadId
|
params_.replyTo = message.replyToMessage.threadId
|
||||||
|
|
||||||
return sendMediaGroup(client, message.chat.inputPeer, media, params_)
|
return sendMediaGroup(client, message.chat.inputPeer, media, params_)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { BaseTelegramClient, getMarkedPeerId, MtArgumentError } from '@mtcute/core'
|
import { BaseTelegramClient, getMarkedPeerId, MtArgumentError, tl } from '@mtcute/core'
|
||||||
|
|
||||||
import { MtMessageNotFoundError } from '../../types/errors.js'
|
import { MtMessageNotFoundError } from '../../types/errors.js'
|
||||||
import { Message } from '../../types/messages/message.js'
|
import { Message } from '../../types/messages/message.js'
|
||||||
import { InputPeerLike } from '../../types/peers/index.js'
|
import { InputPeerLike } from '../../types/peers/index.js'
|
||||||
import { normalizeMessageId } from '../../utils/index.js'
|
import { normalizeMessageId, normalizeToInputUser } from '../../utils/index.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
import { _getDiscussionMessage } from './get-discussion-message.js'
|
import { _getDiscussionMessage } from './get-discussion-message.js'
|
||||||
import { getMessages } from './get-messages.js'
|
import { getMessages } from './get-messages.js'
|
||||||
|
@ -14,6 +14,8 @@ export interface CommonSendParams {
|
||||||
* Message to reply to. Either a message object or message ID.
|
* Message to reply to. Either a message object or message ID.
|
||||||
*
|
*
|
||||||
* For forums - can also be an ID of the topic (i.e. its top message ID)
|
* For forums - can also be an ID of the topic (i.e. its top message ID)
|
||||||
|
*
|
||||||
|
* Can also be a message from another chat, in which case a quote will be sent.
|
||||||
*/
|
*/
|
||||||
replyTo?: number | Message
|
replyTo?: number | Message
|
||||||
|
|
||||||
|
@ -37,6 +39,28 @@ export interface CommonSendParams {
|
||||||
*/
|
*/
|
||||||
commentTo?: number | Message
|
commentTo?: number | Message
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Story to reply to.
|
||||||
|
*
|
||||||
|
* Must be the story sent by the peer you are sending the message to.
|
||||||
|
*
|
||||||
|
* Can't be used together with {@link replyTo} or {@link commentTo}.
|
||||||
|
*/
|
||||||
|
replyToStory?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quoted text. Must be exactly contained in the message
|
||||||
|
* being quoted to be accepted by the server
|
||||||
|
*/
|
||||||
|
quoteText?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entities contained in the quoted text.
|
||||||
|
* Must be exactly contained in the message
|
||||||
|
* being quoted to be accepted by the server
|
||||||
|
*/
|
||||||
|
quoteEntities?: tl.TypeMessageEntity[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse mode to use to parse entities before sending
|
* Parse mode to use to parse entities before sending
|
||||||
* the message. Defaults to current default parse mode (if any).
|
* the message. Defaults to current default parse mode (if any).
|
||||||
|
@ -98,6 +122,7 @@ export async function _processCommonSendParameters(
|
||||||
let peer = await resolvePeer(client, chatId)
|
let peer = await resolvePeer(client, chatId)
|
||||||
|
|
||||||
let replyTo = normalizeMessageId(params.replyTo)
|
let replyTo = normalizeMessageId(params.replyTo)
|
||||||
|
const replyToPeer = typeof params.replyTo === 'number' ? peer : params.replyTo?.chat.inputPeer
|
||||||
|
|
||||||
if (params.commentTo) {
|
if (params.commentTo) {
|
||||||
[peer, replyTo] = await _getDiscussionMessage(client, peer, normalizeMessageId(params.commentTo)!)
|
[peer, replyTo] = await _getDiscussionMessage(client, peer, normalizeMessageId(params.commentTo)!)
|
||||||
|
@ -115,5 +140,30 @@ export async function _processCommonSendParameters(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { peer, replyTo }
|
if (params.replyToStory && replyTo) {
|
||||||
|
throw new MtArgumentError('replyTo/commentTo and replyToStory cannot be used together')
|
||||||
|
}
|
||||||
|
|
||||||
|
let tlReplyTo: tl.TypeInputReplyTo | undefined = undefined
|
||||||
|
|
||||||
|
if (replyTo) {
|
||||||
|
tlReplyTo = {
|
||||||
|
_: 'inputReplyToMessage',
|
||||||
|
replyToMsgId: replyTo,
|
||||||
|
replyToPeerId: replyToPeer,
|
||||||
|
quoteText: params.quoteText,
|
||||||
|
quoteEntities: params.quoteEntities,
|
||||||
|
}
|
||||||
|
} else if (params.replyToStory) {
|
||||||
|
tlReplyTo = {
|
||||||
|
_: 'inputReplyToStory',
|
||||||
|
storyId: params.replyToStory,
|
||||||
|
userId: normalizeToInputUser(peer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
peer,
|
||||||
|
replyTo: tlReplyTo,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,14 @@ export async function sendMediaGroup(
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
medias: (InputMediaLike | string)[],
|
medias: (InputMediaLike | string)[],
|
||||||
params?: CommonSendParams & {
|
params?: CommonSendParams & {
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that will be called after some part has been uploaded.
|
* Function that will be called after some part has been uploaded.
|
||||||
* Only used when a file that requires uploading is passed,
|
* Only used when a file that requires uploading is passed,
|
||||||
|
@ -93,16 +101,12 @@ export async function sendMediaGroup(
|
||||||
peer,
|
peer,
|
||||||
multiMedia,
|
multiMedia,
|
||||||
silent: params.silent,
|
silent: params.silent,
|
||||||
replyTo: replyTo ?
|
replyTo,
|
||||||
{
|
|
||||||
_: 'inputReplyToMessage',
|
|
||||||
replyToMsgId: replyTo,
|
|
||||||
} :
|
|
||||||
undefined,
|
|
||||||
scheduleDate: normalizeDate(params.schedule),
|
scheduleDate: normalizeDate(params.schedule),
|
||||||
clearDraft: params.clearDraft,
|
clearDraft: params.clearDraft,
|
||||||
noforwards: params.forbidForwards,
|
noforwards: params.forbidForwards,
|
||||||
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
||||||
|
invertMedia: params.invertMedia,
|
||||||
})
|
})
|
||||||
|
|
||||||
assertIsUpdatesGroup('sendMediaGroup', res)
|
assertIsUpdatesGroup('sendMediaGroup', res)
|
||||||
|
|
|
@ -36,6 +36,14 @@ export async function sendMedia(
|
||||||
*/
|
*/
|
||||||
replyMarkup?: ReplyMarkup
|
replyMarkup?: ReplyMarkup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invert?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override caption for `media`.
|
* Override caption for `media`.
|
||||||
*
|
*
|
||||||
|
@ -92,12 +100,7 @@ export async function sendMedia(
|
||||||
peer,
|
peer,
|
||||||
media: inputMedia,
|
media: inputMedia,
|
||||||
silent: params.silent,
|
silent: params.silent,
|
||||||
replyTo: replyTo ?
|
replyTo,
|
||||||
{
|
|
||||||
_: 'inputReplyToMessage',
|
|
||||||
replyToMsgId: replyTo,
|
|
||||||
} :
|
|
||||||
undefined,
|
|
||||||
randomId: randomLong(),
|
randomId: randomLong(),
|
||||||
scheduleDate: normalizeDate(params.schedule),
|
scheduleDate: normalizeDate(params.schedule),
|
||||||
replyMarkup,
|
replyMarkup,
|
||||||
|
@ -106,6 +109,7 @@ export async function sendMedia(
|
||||||
clearDraft: params.clearDraft,
|
clearDraft: params.clearDraft,
|
||||||
noforwards: params.forbidForwards,
|
noforwards: params.forbidForwards,
|
||||||
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
||||||
|
invertMedia: params.invert,
|
||||||
})
|
})
|
||||||
|
|
||||||
const msg = _findMessageInUpdate(client, res, false, !params.shouldDispatch)
|
const msg = _findMessageInUpdate(client, res, false, !params.shouldDispatch)
|
||||||
|
|
106
packages/client/src/methods/messages/send-quote.ts
Normal file
106
packages/client/src/methods/messages/send-quote.ts
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { InputPeerLike } from '../../index.js'
|
||||||
|
import { Message } from '../../types/messages/message.js'
|
||||||
|
import { sendMedia } from './send-media.js'
|
||||||
|
import { sendMediaGroup } from './send-media-group.js'
|
||||||
|
import { sendText } from './send-text.js'
|
||||||
|
|
||||||
|
// @exported
|
||||||
|
export type QuoteParamsFrom<T> = Omit<NonNullable<T>, 'quoteText' | 'quoteEntities'> & {
|
||||||
|
/**
|
||||||
|
* Destination chat ID, username, phone, `"me"` or `"self"`
|
||||||
|
*
|
||||||
|
* @default `message.chat`
|
||||||
|
*/
|
||||||
|
toChatId?: InputPeerLike
|
||||||
|
|
||||||
|
/** Index of the first character to quote (inclusive) */
|
||||||
|
start: number
|
||||||
|
|
||||||
|
/** Index of the last character to quote (exclusive) */
|
||||||
|
end: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractQuote(message: Message, from: number, to: number): [string, tl.TypeMessageEntity[] | undefined] {
|
||||||
|
const { raw } = message
|
||||||
|
if (raw._ === 'messageService') throw new MtArgumentError('Cannot quote service message')
|
||||||
|
|
||||||
|
if (!raw.message) throw new MtArgumentError('Cannot quote empty message')
|
||||||
|
|
||||||
|
const text = raw.message
|
||||||
|
if (from < 0) from = 0
|
||||||
|
if (to > text.length) to = text.length
|
||||||
|
|
||||||
|
if (from >= to) throw new MtArgumentError('Invalid quote range')
|
||||||
|
|
||||||
|
if (!raw.entities) return [text.slice(from, to), undefined]
|
||||||
|
|
||||||
|
const entities: tl.TypeMessageEntity[] = []
|
||||||
|
|
||||||
|
for (const ent of raw.entities) {
|
||||||
|
const start = ent.offset
|
||||||
|
const end = ent.offset + ent.length
|
||||||
|
|
||||||
|
if (start >= to || end <= from) continue
|
||||||
|
|
||||||
|
const newStart = Math.max(start, from) - from
|
||||||
|
const newEnd = Math.min(end, to) - from
|
||||||
|
|
||||||
|
const newEnt = { ...ent, offset: newStart, length: newEnd - newStart }
|
||||||
|
entities.push(newEnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [text.slice(from, to), entities]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a text in reply to a given quote */
|
||||||
|
export function quoteWithText(
|
||||||
|
client: BaseTelegramClient,
|
||||||
|
message: Message,
|
||||||
|
params: QuoteParamsFrom<Parameters<typeof sendText>[3]> & {
|
||||||
|
/** Text to send */
|
||||||
|
text: Parameters<typeof sendText>[2]
|
||||||
|
},
|
||||||
|
): ReturnType<typeof sendText> {
|
||||||
|
const { toChatId = message.chat, start, end, text, ...params__ } = params
|
||||||
|
const params_ = params__ as NonNullable<Parameters<typeof sendText>[3]>
|
||||||
|
params_.replyTo = message
|
||||||
|
;[params_.quoteText, params_.quoteEntities] = extractQuote(message, params.start, params.end)
|
||||||
|
|
||||||
|
return sendText(client, toChatId, text, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media in reply to a given quote */
|
||||||
|
export function quoteWithMedia(
|
||||||
|
client: BaseTelegramClient,
|
||||||
|
message: Message,
|
||||||
|
params: QuoteParamsFrom<Parameters<typeof sendMedia>[3]> & {
|
||||||
|
/** Media to send */
|
||||||
|
media: Parameters<typeof sendMedia>[2]
|
||||||
|
},
|
||||||
|
): ReturnType<typeof sendMedia> {
|
||||||
|
const { toChatId = message.chat, start, end, media, ...params__ } = params
|
||||||
|
const params_ = params__ as NonNullable<Parameters<typeof sendMedia>[3]>
|
||||||
|
params_.replyTo = message
|
||||||
|
;[params_.quoteText, params_.quoteEntities] = extractQuote(message, params.start, params.end)
|
||||||
|
|
||||||
|
return sendMedia(client, toChatId, media, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media group in reply to a given quote */
|
||||||
|
export function quoteWithMediaGroup(
|
||||||
|
client: BaseTelegramClient,
|
||||||
|
message: Message,
|
||||||
|
params: QuoteParamsFrom<Parameters<typeof sendMediaGroup>[3]> & {
|
||||||
|
/** Media group to send */
|
||||||
|
medias: Parameters<typeof sendMediaGroup>[2]
|
||||||
|
},
|
||||||
|
): ReturnType<typeof sendMediaGroup> {
|
||||||
|
const { toChatId, start, end, medias, ...params__ } = params
|
||||||
|
const params_ = params__ as NonNullable<Parameters<typeof sendMediaGroup>[3]>
|
||||||
|
params_.replyTo = message
|
||||||
|
;[params_.quoteText, params_.quoteEntities] = extractQuote(message, params.start, params.end)
|
||||||
|
|
||||||
|
return sendMediaGroup(client, message.chat.inputPeer, medias, params_)
|
||||||
|
}
|
|
@ -45,6 +45,14 @@ export async function sendText(
|
||||||
* Whether to disable links preview in this message
|
* Whether to disable links preview in this message
|
||||||
*/
|
*/
|
||||||
disableWebPreview?: boolean
|
disableWebPreview?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
},
|
},
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
@ -59,12 +67,7 @@ export async function sendText(
|
||||||
peer,
|
peer,
|
||||||
noWebpage: params.disableWebPreview,
|
noWebpage: params.disableWebPreview,
|
||||||
silent: params.silent,
|
silent: params.silent,
|
||||||
replyTo: replyTo ?
|
replyTo,
|
||||||
{
|
|
||||||
_: 'inputReplyToMessage',
|
|
||||||
replyToMsgId: replyTo,
|
|
||||||
} :
|
|
||||||
undefined,
|
|
||||||
randomId: randomLong(),
|
randomId: randomLong(),
|
||||||
scheduleDate: normalizeDate(params.schedule),
|
scheduleDate: normalizeDate(params.schedule),
|
||||||
replyMarkup,
|
replyMarkup,
|
||||||
|
@ -73,6 +76,7 @@ export async function sendText(
|
||||||
clearDraft: params.clearDraft,
|
clearDraft: params.clearDraft,
|
||||||
noforwards: params.forbidForwards,
|
noforwards: params.forbidForwards,
|
||||||
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
||||||
|
invertMedia: params.invertMedia,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res._ === 'updateShortSentMessage') {
|
if (res._ === 'updateShortSentMessage') {
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import { assertNever, BaseTelegramClient, tl } from '@mtcute/core'
|
import { assertNever, BaseTelegramClient, tl } from '@mtcute/core'
|
||||||
|
|
||||||
import { _parseEntities } from '../../../methods/messages/parse-entities.js'
|
import { _parseEntities } from '../../../methods/messages/parse-entities.js'
|
||||||
import { InputMediaContact, InputMediaGeo, InputMediaGeoLive, InputMediaVenue } from '../../media/index.js'
|
import {
|
||||||
|
InputMediaContact,
|
||||||
|
InputMediaGeo,
|
||||||
|
InputMediaGeoLive,
|
||||||
|
InputMediaVenue,
|
||||||
|
InputMediaWebpage,
|
||||||
|
} from '../../media/index.js'
|
||||||
import { FormattedString } from '../../parser.js'
|
import { FormattedString } from '../../parser.js'
|
||||||
import { BotKeyboard, ReplyMarkup } from '../keyboards.js'
|
import { BotKeyboard, ReplyMarkup } from '../keyboards.js'
|
||||||
|
|
||||||
|
@ -31,6 +37,14 @@ export interface InputInlineMessageText {
|
||||||
* Whether to disable links preview in this message
|
* Whether to disable links preview in this message
|
||||||
*/
|
*/
|
||||||
disableWebPreview?: boolean
|
disableWebPreview?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,6 +69,14 @@ export interface InputInlineMessageMedia {
|
||||||
* Message reply markup
|
* Message reply markup
|
||||||
*/
|
*/
|
||||||
replyMarkup?: ReplyMarkup
|
replyMarkup?: ReplyMarkup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,6 +131,32 @@ export interface InputInlineMessageContact extends InputMediaContact {
|
||||||
replyMarkup?: ReplyMarkup
|
replyMarkup?: ReplyMarkup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InputInlineMessageWebpage extends InputMediaWebpage {
|
||||||
|
/**
|
||||||
|
* Text of the message
|
||||||
|
*/
|
||||||
|
text: string | FormattedString<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text markup entities.
|
||||||
|
* If passed, parse mode is ignored
|
||||||
|
*/
|
||||||
|
entities?: tl.TypeMessageEntity[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message reply markup
|
||||||
|
*/
|
||||||
|
replyMarkup?: ReplyMarkup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to invert media position.
|
||||||
|
*
|
||||||
|
* Currently only supported for web previews and makes the
|
||||||
|
* client render the preview above the caption and not below.
|
||||||
|
*/
|
||||||
|
invertMedia?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type InputInlineMessage =
|
export type InputInlineMessage =
|
||||||
| InputInlineMessageText
|
| InputInlineMessageText
|
||||||
| InputInlineMessageMedia
|
| InputInlineMessageMedia
|
||||||
|
@ -117,6 +165,7 @@ export type InputInlineMessage =
|
||||||
| InputInlineMessageVenue
|
| InputInlineMessageVenue
|
||||||
| InputInlineMessageGame
|
| InputInlineMessageGame
|
||||||
| InputInlineMessageContact
|
| InputInlineMessageContact
|
||||||
|
| InputInlineMessageWebpage
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
export namespace BotInlineMessage {
|
export namespace BotInlineMessage {
|
||||||
|
@ -203,6 +252,16 @@ export namespace BotInlineMessage {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an inline message containing a webpage
|
||||||
|
*/
|
||||||
|
export function webpage(params: Omit<InputInlineMessageWebpage, 'type'>): InputInlineMessageWebpage {
|
||||||
|
const ret = params as tl.Mutable<InputInlineMessageWebpage>
|
||||||
|
ret.type = 'webpage'
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export async function _convertToTl(
|
export async function _convertToTl(
|
||||||
client: BaseTelegramClient,
|
client: BaseTelegramClient,
|
||||||
|
@ -218,6 +277,7 @@ export namespace BotInlineMessage {
|
||||||
message,
|
message,
|
||||||
entities,
|
entities,
|
||||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
||||||
|
invertMedia: obj.invertMedia,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'media': {
|
case 'media': {
|
||||||
|
@ -228,6 +288,7 @@ export namespace BotInlineMessage {
|
||||||
message,
|
message,
|
||||||
entities,
|
entities,
|
||||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
||||||
|
invertMedia: obj.invertMedia,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'geo':
|
case 'geo':
|
||||||
|
@ -274,6 +335,21 @@ export namespace BotInlineMessage {
|
||||||
vcard: obj.vcard ?? '',
|
vcard: obj.vcard ?? '',
|
||||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
||||||
}
|
}
|
||||||
|
case 'webpage': {
|
||||||
|
const [message, entities] = await _parseEntities(client, obj.text, parseMode, obj.entities)
|
||||||
|
|
||||||
|
return {
|
||||||
|
_: 'inputBotInlineMessageMediaWebPage',
|
||||||
|
message,
|
||||||
|
entities,
|
||||||
|
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
|
||||||
|
invertMedia: obj.invertMedia,
|
||||||
|
forceLargeMedia: obj.size === 'large',
|
||||||
|
forceSmallMedia: obj.size === 'small',
|
||||||
|
optional: !obj.required,
|
||||||
|
url: obj.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assertNever(obj)
|
assertNever(obj)
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,8 +424,8 @@ export class Conversation {
|
||||||
}
|
}
|
||||||
|
|
||||||
const pred = filter ?
|
const pred = filter ?
|
||||||
(msg: Message) => (msg.replyToMessageId === msgId ? filter(msg) : false) :
|
(msg: Message) => (msg.replyToMessage?.id === msgId ? filter(msg) : false) :
|
||||||
(msg: Message) => msg.replyToMessageId === msgId
|
(msg: Message) => msg.replyToMessage?.id === msgId
|
||||||
|
|
||||||
return this.waitForNewMessage(pred, params?.timeout)
|
return this.waitForNewMessage(pred, params?.timeout)
|
||||||
}
|
}
|
||||||
|
|
|
@ -567,6 +567,28 @@ export interface InputMediaStory extends CaptionMixin {
|
||||||
id: number
|
id: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A webpage to be sent */
|
||||||
|
export interface InputMediaWebpage extends CaptionMixin {
|
||||||
|
type: 'webpage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the link must be present in the message
|
||||||
|
* for the preview to appear
|
||||||
|
*/
|
||||||
|
required?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, size of the media in the preview
|
||||||
|
* is determined based on content type.
|
||||||
|
*
|
||||||
|
* You can override this behaviour by passing the wanted size here
|
||||||
|
*/
|
||||||
|
size?: 'large' | 'small'
|
||||||
|
|
||||||
|
/** Webpage URL */
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input media that can be sent somewhere.
|
* Input media that can be sent somewhere.
|
||||||
*
|
*
|
||||||
|
@ -594,6 +616,7 @@ export type InputMediaLike =
|
||||||
| InputMediaPoll
|
| InputMediaPoll
|
||||||
| InputMediaQuiz
|
| InputMediaQuiz
|
||||||
| InputMediaStory
|
| InputMediaStory
|
||||||
|
| InputMediaWebpage
|
||||||
| tl.TypeInputMedia
|
| tl.TypeInputMedia
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
@ -843,6 +866,20 @@ export namespace InputMedia {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a webpage to be sent
|
||||||
|
*
|
||||||
|
* @param url Webpage URL
|
||||||
|
* @param params Additional parameters
|
||||||
|
*/
|
||||||
|
export function webpage(url: string, params: OmitTypeAndFile<InputMediaWebpage, 'url'> = {}): InputMediaWebpage {
|
||||||
|
const ret = params as tl.Mutable<InputMediaWebpage>
|
||||||
|
ret.type = 'webpage'
|
||||||
|
ret.url = url
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a document to be sent, which subtype
|
* Create a document to be sent, which subtype
|
||||||
* is inferred automatically by file contents.
|
* is inferred automatically by file contents.
|
||||||
|
|
|
@ -18,10 +18,12 @@ export class DraftMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message this message will reply to
|
* Information about replies/quotes in this message
|
||||||
*/
|
*/
|
||||||
get replyToMessageId(): number | null {
|
get replyToMessage(): tl.RawInputReplyToMessage | null {
|
||||||
return this.raw.replyToMsgId ?? null
|
if (this.raw.replyTo?._ !== 'inputReplyToMessage') return null
|
||||||
|
|
||||||
|
return this.raw.replyTo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,6 +4,8 @@ export * from './input-message-id.js'
|
||||||
export * from './message.js'
|
export * from './message.js'
|
||||||
export * from './message-action.js'
|
export * from './message-action.js'
|
||||||
export * from './message-entity.js'
|
export * from './message-entity.js'
|
||||||
|
export * from './message-forward.js'
|
||||||
export * from './message-media.js'
|
export * from './message-media.js'
|
||||||
export * from './message-reactions.js'
|
export * from './message-reactions.js'
|
||||||
|
export * from './message-replies.js'
|
||||||
export * from './search-filters.js'
|
export * from './search-filters.js'
|
||||||
|
|
149
packages/client/src/types/messages/message-forward.ts
Normal file
149
packages/client/src/types/messages/message-forward.ts
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import { MtTypeAssertionError, tl } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { Chat } from '../peers/chat.js'
|
||||||
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
import { User } from '../peers/user.js'
|
||||||
|
import { MessageEntity } from './message-entity.js'
|
||||||
|
import { _messageMediaFromTl, MessageMedia } from './message-media.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about forwarded message origin
|
||||||
|
*/
|
||||||
|
export class MessageForwardInfo {
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.RawMessageFwdHeader,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date the original message was sent
|
||||||
|
*/
|
||||||
|
get date(): Date {
|
||||||
|
return new Date(this.raw.date * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sender of the original message (either user or a channel)
|
||||||
|
* or their name (for users with private forwards)
|
||||||
|
*/
|
||||||
|
get sender(): User | Chat | string {
|
||||||
|
if (this.raw.fromName) {
|
||||||
|
return this.raw.fromName
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.raw.fromId) {
|
||||||
|
switch (this.raw.fromId._) {
|
||||||
|
case 'peerChannel':
|
||||||
|
return new Chat(this._peers.chat(this.raw.fromId.channelId))
|
||||||
|
case 'peerUser':
|
||||||
|
return new User(this._peers.user(this.raw.fromId.userId))
|
||||||
|
default:
|
||||||
|
throw new MtTypeAssertionError('raw.fwdFrom.fromId', 'peerUser | peerChannel', this.raw.fromId._)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MtTypeAssertionError('MessageForwardInfo', 'to have fromId or fromName', 'neither')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For "saved" messages (i.e. messages forwarded to yourself,
|
||||||
|
* "Saved Messages"), the peer where the message was originally sent
|
||||||
|
*/
|
||||||
|
fromChat(): User | Chat | null {
|
||||||
|
if (!this.raw.savedFromPeer) return null
|
||||||
|
|
||||||
|
return Chat._parseFromPeer(this.raw.savedFromPeer, this._peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For messages forwarded from channels,
|
||||||
|
* identifier of the original message in the channel
|
||||||
|
*/
|
||||||
|
get fromMessageId(): number | null {
|
||||||
|
return this.raw.savedFromMsgId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For messages forwarded from channels,
|
||||||
|
* signature of the post author (if present)
|
||||||
|
*/
|
||||||
|
get signature(): string | null {
|
||||||
|
return this.raw.postAuthor ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memoizeGetters(MessageForwardInfo, ['sender', 'fromChat'])
|
||||||
|
makeInspectable(MessageForwardInfo)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a message that this message is a reply to
|
||||||
|
*/
|
||||||
|
export class MessageReplyInfo {
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.RawMessageReplyHeader,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/** Whether this message is a reply to another scheduled message */
|
||||||
|
get isScheduled(): boolean {
|
||||||
|
return this.raw.replyToScheduled!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether this message was sent to a forum topic */
|
||||||
|
get isForumTopic(): boolean {
|
||||||
|
return this.raw.forumTopic!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether this message is quoting another message */
|
||||||
|
get isQuote(): boolean {
|
||||||
|
return this.raw.quote!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If replied-to message is available, its ID
|
||||||
|
*/
|
||||||
|
get id(): number | null {
|
||||||
|
return this.raw.replyToMsgId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ID of the replies thread where this message belongs to */
|
||||||
|
get threadId(): number | null {
|
||||||
|
return this.raw.replyToTopId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If replied-to message is available, chat where the message was sent.
|
||||||
|
*
|
||||||
|
* If `null`, the message was sent in the same chat.
|
||||||
|
*/
|
||||||
|
get chat(): Chat | null {
|
||||||
|
return this.raw.replyToPeerId ? Chat._parseFromPeer(this.raw.replyToPeerId, this._peers) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If this message is a quote, text of the quote */
|
||||||
|
get quoteText(): string {
|
||||||
|
return this.raw.quoteText ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Message entities contained in the quote */
|
||||||
|
get quoteEntities(): MessageEntity[] {
|
||||||
|
return this.raw.quoteEntities?.map((e) => new MessageEntity(e)) ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Media contained in the replied-to message
|
||||||
|
*
|
||||||
|
* Only available in case the replied-to message is in a different chat
|
||||||
|
* (i.e. {@link chat} is not `null`)
|
||||||
|
*/
|
||||||
|
get media(): MessageMedia {
|
||||||
|
if (!this.raw.replyMedia) return null
|
||||||
|
|
||||||
|
return _messageMediaFromTl(this._peers, this.raw.replyMedia)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memoizeGetters(MessageReplyInfo, ['chat', 'quoteEntities', 'media'])
|
||||||
|
makeInspectable(MessageReplyInfo)
|
79
packages/client/src/types/messages/message-replies.ts
Normal file
79
packages/client/src/types/messages/message-replies.ts
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import { getMarkedPeerId, tl } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { Chat } from '../peers/chat.js'
|
||||||
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
import { User } from '../peers/user.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about replies to a message
|
||||||
|
*/
|
||||||
|
export class MessageRepliesInfo {
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.RawMessageReplies,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this message is a channel post that has a comments thread
|
||||||
|
* in the linked discussion group
|
||||||
|
*/
|
||||||
|
get hasComments(): boolean {
|
||||||
|
return this.raw.comments!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total number of replies
|
||||||
|
*/
|
||||||
|
get count(): number {
|
||||||
|
return this.raw.replies
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this reply thread has unread messages
|
||||||
|
*/
|
||||||
|
get hasUnread(): boolean {
|
||||||
|
return this.raw.readMaxId !== undefined && this.raw.readMaxId !== this.raw.maxId
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the last message in the thread (if any)
|
||||||
|
*/
|
||||||
|
get lastMessageId(): number | null {
|
||||||
|
return this.raw.maxId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the last read message in the thread (if any)
|
||||||
|
*/
|
||||||
|
get lastReadMessageId(): number | null {
|
||||||
|
return this.raw.readMaxId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the discussion group for the post
|
||||||
|
*/
|
||||||
|
get discussion(): number {
|
||||||
|
return getMarkedPeerId(this.raw.channelId!, 'channel')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last few commenters to the post (usually 3)
|
||||||
|
*/
|
||||||
|
get repliers(): (User | Chat)[] {
|
||||||
|
return this.raw.recentRepliers!.map((it) => {
|
||||||
|
switch (it._) {
|
||||||
|
case 'peerUser':
|
||||||
|
return new User(this._peers.user(it.userId))
|
||||||
|
case 'peerChannel':
|
||||||
|
return new Chat(this._peers.chat(it.channelId))
|
||||||
|
default:
|
||||||
|
throw new Error('Unexpected peer type: ' + it._)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memoizeGetters(MessageRepliesInfo, ['discussion', 'repliers'])
|
||||||
|
makeInspectable(MessageRepliesInfo)
|
|
@ -16,82 +16,10 @@ import { PeersIndex } from '../peers/peers-index.js'
|
||||||
import { User } from '../peers/user.js'
|
import { User } from '../peers/user.js'
|
||||||
import { _messageActionFromTl, MessageAction } from './message-action.js'
|
import { _messageActionFromTl, MessageAction } from './message-action.js'
|
||||||
import { MessageEntity } from './message-entity.js'
|
import { MessageEntity } from './message-entity.js'
|
||||||
|
import { MessageForwardInfo, MessageReplyInfo } from './message-forward.js'
|
||||||
import { _messageMediaFromTl, MessageMedia } from './message-media.js'
|
import { _messageMediaFromTl, MessageMedia } from './message-media.js'
|
||||||
import { MessageReactions } from './message-reactions.js'
|
import { MessageReactions } from './message-reactions.js'
|
||||||
|
import { MessageRepliesInfo } from './message-replies.js'
|
||||||
/** Information about a forward */
|
|
||||||
export interface MessageForwardInfo {
|
|
||||||
/**
|
|
||||||
* Date the original message was sent
|
|
||||||
*/
|
|
||||||
date: Date
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sender of the original message (either user or a channel)
|
|
||||||
* or their name (for users with private forwards)
|
|
||||||
*/
|
|
||||||
sender: User | Chat | string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For messages forwarded from channels,
|
|
||||||
* identifier of the original message in the channel
|
|
||||||
*/
|
|
||||||
fromMessageId?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For messages forwarded from channels,
|
|
||||||
* signature of the post author (if present)
|
|
||||||
*/
|
|
||||||
signature?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Information about replies to a message */
|
|
||||||
export interface MessageRepliesInfo {
|
|
||||||
/**
|
|
||||||
* Whether this message is a channel post that has a comments thread
|
|
||||||
* in the linked discussion group
|
|
||||||
*/
|
|
||||||
hasComments: false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total number of replies
|
|
||||||
*/
|
|
||||||
count: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this reply thread has unread messages
|
|
||||||
*/
|
|
||||||
hasUnread: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID of the last message in the thread (if any)
|
|
||||||
*/
|
|
||||||
lastMessageId?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID of the last read message in the thread (if any)
|
|
||||||
*/
|
|
||||||
lastReadMessageId?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Information about comments to a channel post */
|
|
||||||
export interface MessageCommentsInfo extends Omit<MessageRepliesInfo, 'isComments'> {
|
|
||||||
/**
|
|
||||||
* Whether this message is a channel post that has a comments thread
|
|
||||||
* in the linked discussion group
|
|
||||||
*/
|
|
||||||
isComments: true
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID of the discussion group for the post
|
|
||||||
*/
|
|
||||||
discussion: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IDs of the last few commenters to the post
|
|
||||||
*/
|
|
||||||
repliers: number[]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Telegram message.
|
* A Telegram message.
|
||||||
|
@ -226,33 +154,8 @@ export class Message {
|
||||||
if (this.raw._ !== 'message' || !this.raw.fwdFrom) {
|
if (this.raw._ !== 'message' || !this.raw.fwdFrom) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const fwd = this.raw.fwdFrom
|
|
||||||
|
|
||||||
let sender: User | Chat | string
|
return new MessageForwardInfo(this.raw.fwdFrom, this._peers)
|
||||||
|
|
||||||
if (fwd.fromName) {
|
|
||||||
sender = fwd.fromName
|
|
||||||
} else if (fwd.fromId) {
|
|
||||||
switch (fwd.fromId._) {
|
|
||||||
case 'peerChannel':
|
|
||||||
sender = new Chat(this._peers.chat(fwd.fromId.channelId))
|
|
||||||
break
|
|
||||||
case 'peerUser':
|
|
||||||
sender = new User(this._peers.user(fwd.fromId.userId))
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
throw new MtTypeAssertionError('raw.fwdFrom.fromId', 'peerUser | peerChannel', fwd.fromId._)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
date: new Date(fwd.date * 1000),
|
|
||||||
sender,
|
|
||||||
fromMessageId: fwd.savedFromMsgId,
|
|
||||||
signature: fwd.postAuthor,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -275,51 +178,29 @@ export class Message {
|
||||||
/**
|
/**
|
||||||
* Information about comments (for channels) or replies (for groups)
|
* Information about comments (for channels) or replies (for groups)
|
||||||
*/
|
*/
|
||||||
get replies(): MessageRepliesInfo | MessageCommentsInfo | null {
|
get replies(): MessageRepliesInfo | null {
|
||||||
if (this.raw._ !== 'message' || !this.raw.replies) return null
|
if (this.raw._ !== 'message' || !this.raw.replies) return null
|
||||||
|
|
||||||
const r = this.raw.replies
|
return new MessageRepliesInfo(this.raw.replies, this._peers)
|
||||||
const obj: MessageRepliesInfo = {
|
|
||||||
hasComments: r.comments as false,
|
|
||||||
count: r.replies,
|
|
||||||
hasUnread: r.readMaxId !== undefined && r.readMaxId !== r.maxId,
|
|
||||||
lastMessageId: r.maxId,
|
|
||||||
lastReadMessageId: r.readMaxId,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r.comments) {
|
|
||||||
const o = obj as unknown as MessageCommentsInfo
|
|
||||||
o.discussion = getMarkedPeerId(r.channelId!, 'channel')
|
|
||||||
o.repliers = r.recentRepliers?.map((it) => getMarkedPeerId(it)) ?? []
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For replies, the ID of the message that current message
|
* For replies, information about the that is being replied to.
|
||||||
* replies to.
|
*
|
||||||
|
* Mutually exclusive with {@link replyToStory}
|
||||||
*/
|
*/
|
||||||
get replyToMessageId(): number | null {
|
get replyToMessage(): MessageReplyInfo | null {
|
||||||
if (this.raw.replyTo?._ !== 'messageReplyHeader') return null
|
if (this.raw.replyTo?._ !== 'messageReplyHeader') return null
|
||||||
|
|
||||||
return this.raw.replyTo.replyToMsgId ?? null
|
return new MessageReplyInfo(this.raw.replyTo, this._peers)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For replies, ID of the thread/topic
|
|
||||||
* (i.e. ID of the top message in the thread/topic)
|
|
||||||
*/
|
|
||||||
get replyToThreadId(): number | null {
|
|
||||||
if (this.raw.replyTo?._ !== 'messageReplyHeader') return null
|
|
||||||
|
|
||||||
return this.raw.replyTo.replyToTopId ?? null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For replies, information about the story that is being replied to
|
* For replies, information about the story that is being replied to
|
||||||
|
*
|
||||||
|
* Mutually exclusive with {@link replyToMessage}
|
||||||
*/
|
*/
|
||||||
get replyToStoryId(): tl.RawMessageReplyStoryHeader | null {
|
get replyToStory(): tl.RawMessageReplyStoryHeader | null {
|
||||||
if (this.raw.replyTo?._ !== 'messageReplyStoryHeader') return null
|
if (this.raw.replyTo?._ !== 'messageReplyStoryHeader') return null
|
||||||
|
|
||||||
return this.raw.replyTo
|
return this.raw.replyTo
|
||||||
|
|
|
@ -464,6 +464,33 @@ export class Chat {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name color of this chat, which should also be used when
|
||||||
|
* rendering replies to their messages and web previews sent by them.
|
||||||
|
*
|
||||||
|
* Note that this value is **not** an RGB color representation. Instead, it is
|
||||||
|
* a number which should be used to pick a color from a predefined
|
||||||
|
* list of colors:
|
||||||
|
* - `0-6` are the default colors used by Telegram clients:
|
||||||
|
* `red, orange, purple, green, sea, blue, pink`
|
||||||
|
* - `>= 7` are returned by `help.getAppConfig`.
|
||||||
|
*/
|
||||||
|
get color(): number {
|
||||||
|
if (this.peer._ !== 'channel' && this.peer._ !== 'user') return this.peer.id % 7
|
||||||
|
|
||||||
|
return this.peer.color ?? this.peer.id % 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the emoji that should be used as a background pattern
|
||||||
|
* when rendering replies to this user's messages.
|
||||||
|
*/
|
||||||
|
get replyBackgroundEmojiId(): tl.Long | null {
|
||||||
|
if (this.peer._ !== 'channel' && this.peer._ !== 'user') return null
|
||||||
|
|
||||||
|
return this.peer.backgroundEmojiId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a {@link User} from this chat.
|
* Get a {@link User} from this chat.
|
||||||
*
|
*
|
||||||
|
|
|
@ -320,6 +320,29 @@ export class User {
|
||||||
return this.raw.storiesMaxId ?? 0
|
return this.raw.storiesMaxId ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name color of this user, which should also be used when
|
||||||
|
* rendering replies to their messages and web previews sent by them.
|
||||||
|
*
|
||||||
|
* Note that this value is **not** an RGB color representation. Instead, it is
|
||||||
|
* a number which should be used to pick a color from a predefined
|
||||||
|
* list of colors:
|
||||||
|
* - `0-6` are the default colors used by Telegram clients:
|
||||||
|
* `red, orange, purple, green, sea, blue, pink`
|
||||||
|
* - `>= 7` are returned by `help.getAppConfig`.
|
||||||
|
*/
|
||||||
|
get color(): number {
|
||||||
|
return this.raw.color ?? this.raw.id % 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the emoji that should be used as a background pattern
|
||||||
|
* when rendering replies to this user's messages.
|
||||||
|
*/
|
||||||
|
get replyBackgroundEmojiId(): tl.Long | null {
|
||||||
|
return this.raw.backgroundEmojiId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mention for the user.
|
* Create a mention for the user.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { makeInspectable } from '../../utils/index.js'
|
||||||
* Information about boosts in a channel
|
* Information about boosts in a channel
|
||||||
*/
|
*/
|
||||||
export class BoostStats {
|
export class BoostStats {
|
||||||
constructor(readonly raw: tl.stories.RawBoostsStatus) {}
|
constructor(readonly raw: tl.premium.RawBoostsStatus) {}
|
||||||
|
|
||||||
/** Whether this channel is being boosted by the current user */
|
/** Whether this channel is being boosted by the current user */
|
||||||
get isBoosting(): boolean {
|
get isBoosting(): boolean {
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "workspace:^165.0.0",
|
"@mtcute/tl": "workspace:^166.0.0",
|
||||||
"@mtcute/tl-runtime": "workspace:^1.0.0",
|
"@mtcute/tl-runtime": "workspace:^1.0.0",
|
||||||
"@types/events": "3.0.0",
|
"@types/events": "3.0.0",
|
||||||
"@types/node": "18.16.0",
|
"@types/node": "18.16.0",
|
||||||
|
@ -58,4 +58,4 @@
|
||||||
"node-forge": "1.3.1",
|
"node-forge": "1.3.1",
|
||||||
"ws": "8.13.0"
|
"ws": "8.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -85,6 +85,21 @@ export class MessageContext extends Message implements UpdateContext<Message> {
|
||||||
return this.client.replyMediaGroup(this, ...params)
|
return this.client.replyMediaGroup(this, ...params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Send a text message in reply to this message */
|
||||||
|
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]) {
|
||||||
|
return this.client.quoteWithText(this, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media in reply to this message */
|
||||||
|
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]) {
|
||||||
|
return this.client.quoteWithMedia(this, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media group in reply to this message */
|
||||||
|
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]) {
|
||||||
|
return this.client.quoteWithMediaGroup(this, params)
|
||||||
|
}
|
||||||
|
|
||||||
/** Send a text as a comment to this message */
|
/** Send a text as a comment to this message */
|
||||||
commentText(...params: ParametersSkip1<TelegramClient['commentText']>) {
|
commentText(...params: ParametersSkip1<TelegramClient['commentText']>) {
|
||||||
return this.client.commentText(this, ...params)
|
return this.client.commentText(this, ...params)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
Message,
|
Message,
|
||||||
MessageAction,
|
MessageAction,
|
||||||
MessageMediaType,
|
MessageMediaType,
|
||||||
|
MessageReplyInfo,
|
||||||
RawDocument,
|
RawDocument,
|
||||||
RawLocation,
|
RawLocation,
|
||||||
Sticker,
|
Sticker,
|
||||||
|
@ -35,7 +36,7 @@ export const outgoing: UpdateFilter<Message, { isOutgoing: true }> = (msg) => ms
|
||||||
/**
|
/**
|
||||||
* Filter messages that are replies to some other message
|
* Filter messages that are replies to some other message
|
||||||
*/
|
*/
|
||||||
export const reply: UpdateFilter<Message, { replyToMessageId: number }> = (msg) => msg.replyToMessageId !== null
|
export const reply: UpdateFilter<Message, { replyToMessage: MessageReplyInfo }> = (msg) => msg.replyToMessage !== null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing some media
|
* Filter messages containing some media
|
||||||
|
@ -220,7 +221,7 @@ export const replyTo =
|
||||||
filter?: UpdateFilter<Message, Mod, State>,
|
filter?: UpdateFilter<Message, Mod, State>,
|
||||||
): UpdateFilter<MessageContext, { getReplyTo: () => Promise<Message & Mod> }, State> =>
|
): UpdateFilter<MessageContext, { getReplyTo: () => Promise<Message & Mod> }, State> =>
|
||||||
async (msg, state) => {
|
async (msg, state) => {
|
||||||
if (!msg.replyToMessageId) return false
|
if (!msg.replyToMessage?.id) return false
|
||||||
|
|
||||||
const reply = await msg.getReplyTo()
|
const reply = await msg.getReplyTo()
|
||||||
if (!reply) return false
|
if (!reply) return false
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "workspace:^165.0.0",
|
"@mtcute/tl": "workspace:^166.0.0",
|
||||||
"htmlparser2": "^6.0.1",
|
"htmlparser2": "^6.0.1",
|
||||||
"long": "5.2.3"
|
"long": "5.2.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "workspace:^165.0.0",
|
"@mtcute/tl": "workspace:^166.0.0",
|
||||||
"long": "5.2.3"
|
"long": "5.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> TL schema and related utils used for mtcute.
|
> TL schema and related utils used for mtcute.
|
||||||
|
|
||||||
Generated from TL layer **165** (last updated on 04.10.2023).
|
Generated from TL layer **166** (last updated on 29.10.2023).
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mtcute/tl",
|
"name": "@mtcute/tl",
|
||||||
"version": "165.0.0",
|
"version": "166.0.0",
|
||||||
"description": "TL schema used for mtcute",
|
"description": "TL schema used for mtcute",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Alina Sireneva <alina@tei.su>",
|
"author": "Alina Sireneva <alina@tei.su>",
|
||||||
|
|
Loading…
Reference in a new issue