feat(client): support reactions
This commit is contained in:
parent
96300a795e
commit
9039830572
9 changed files with 512 additions and 6 deletions
|
@ -33,9 +33,11 @@ import {
|
||||||
MaybeDynamic,
|
MaybeDynamic,
|
||||||
Message,
|
Message,
|
||||||
MessageMedia,
|
MessageMedia,
|
||||||
|
MessageReactions,
|
||||||
ParsedUpdate,
|
ParsedUpdate,
|
||||||
PartialExcept,
|
PartialExcept,
|
||||||
PartialOnly,
|
PartialOnly,
|
||||||
|
PeerReaction,
|
||||||
PeersIndex,
|
PeersIndex,
|
||||||
Photo,
|
Photo,
|
||||||
Poll,
|
Poll,
|
||||||
|
@ -172,19 +174,23 @@ import {
|
||||||
} from './methods/messages/get-discussion-message'
|
} from './methods/messages/get-discussion-message'
|
||||||
import { getHistory } from './methods/messages/get-history'
|
import { getHistory } from './methods/messages/get-history'
|
||||||
import { getMessageGroup } from './methods/messages/get-message-group'
|
import { getMessageGroup } from './methods/messages/get-message-group'
|
||||||
|
import { getMessageReactions } from './methods/messages/get-message-reactions'
|
||||||
import { getMessagesUnsafe } from './methods/messages/get-messages-unsafe'
|
import { getMessagesUnsafe } from './methods/messages/get-messages-unsafe'
|
||||||
import { getMessages } from './methods/messages/get-messages'
|
import { getMessages } from './methods/messages/get-messages'
|
||||||
|
import { getReactionUsers } from './methods/messages/get-reaction-users'
|
||||||
import { getScheduledMessages } from './methods/messages/get-scheduled-messages'
|
import { getScheduledMessages } from './methods/messages/get-scheduled-messages'
|
||||||
import { iterHistory } from './methods/messages/iter-history'
|
import { iterHistory } from './methods/messages/iter-history'
|
||||||
import { _normalizeInline } from './methods/messages/normalize-inline'
|
import { _normalizeInline } from './methods/messages/normalize-inline'
|
||||||
import { _parseEntities } from './methods/messages/parse-entities'
|
import { _parseEntities } from './methods/messages/parse-entities'
|
||||||
import { pinMessage } from './methods/messages/pin-message'
|
import { pinMessage } from './methods/messages/pin-message'
|
||||||
import { readHistory } from './methods/messages/read-history'
|
import { readHistory } from './methods/messages/read-history'
|
||||||
|
import { readReactions } from './methods/messages/read-reactions'
|
||||||
import { searchGlobal } from './methods/messages/search-global'
|
import { searchGlobal } from './methods/messages/search-global'
|
||||||
import { searchMessages } from './methods/messages/search-messages'
|
import { searchMessages } from './methods/messages/search-messages'
|
||||||
import { sendCopy } from './methods/messages/send-copy'
|
import { sendCopy } from './methods/messages/send-copy'
|
||||||
import { sendMediaGroup } from './methods/messages/send-media-group'
|
import { sendMediaGroup } from './methods/messages/send-media-group'
|
||||||
import { sendMedia } from './methods/messages/send-media'
|
import { sendMedia } from './methods/messages/send-media'
|
||||||
|
import { sendReaction } from './methods/messages/send-reaction'
|
||||||
import { sendScheduled } from './methods/messages/send-scheduled'
|
import { sendScheduled } from './methods/messages/send-scheduled'
|
||||||
import { sendText } from './methods/messages/send-text'
|
import { sendText } from './methods/messages/send-text'
|
||||||
import { sendTyping } from './methods/messages/send-typing'
|
import { sendTyping } from './methods/messages/send-typing'
|
||||||
|
@ -2430,6 +2436,36 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* @param message ID of one of the messages in the group
|
* @param message ID of one of the messages in the group
|
||||||
*/
|
*/
|
||||||
getMessageGroup(chatId: InputPeerLike, message: number): Promise<Message[]>
|
getMessageGroup(chatId: InputPeerLike, message: number): Promise<Message[]>
|
||||||
|
/**
|
||||||
|
* Get reactions to a message.
|
||||||
|
*
|
||||||
|
* > Apps should short-poll reactions for visible messages
|
||||||
|
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||||
|
* > but only if `message.reactions` is set
|
||||||
|
*
|
||||||
|
* @param chatId ID of the chat with the message
|
||||||
|
* @param messages Message ID
|
||||||
|
* @returns Reactions to the corresponding message, or `null` if there are none
|
||||||
|
*/
|
||||||
|
getMessageReactions(
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messages: number
|
||||||
|
): Promise<MessageReactions | null>
|
||||||
|
/**
|
||||||
|
* Get reactions to messages.
|
||||||
|
*
|
||||||
|
* > Apps should short-poll reactions for visible messages
|
||||||
|
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||||
|
* > but only if `message.reactions` is set
|
||||||
|
*
|
||||||
|
* @param chatId ID of the chat with messages
|
||||||
|
* @param messages Message IDs
|
||||||
|
* @returns Reactions to corresponding messages, or `null` if there are none
|
||||||
|
*/
|
||||||
|
getMessageReactions(
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messages: number[]
|
||||||
|
): Promise<(MessageReactions | null)[]>
|
||||||
/**
|
/**
|
||||||
* Get a single message from PM or legacy group by its ID.
|
* Get a single message from PM or legacy group by its ID.
|
||||||
* For channels, use {@link getMessages}.
|
* For channels, use {@link getMessages}.
|
||||||
|
@ -2496,6 +2532,37 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
messageIds: number[],
|
messageIds: number[],
|
||||||
fromReply?: boolean
|
fromReply?: boolean
|
||||||
): Promise<(Message | null)[]>
|
): Promise<(Message | null)[]>
|
||||||
|
/**
|
||||||
|
* Get users who have reacted to the message.
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID
|
||||||
|
* @param messageId Message ID
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
getReactionUsers(
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messageId: number,
|
||||||
|
params?: {
|
||||||
|
/**
|
||||||
|
* Get only reactions with the specified emoji
|
||||||
|
*/
|
||||||
|
emoji?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limit the number of events returned.
|
||||||
|
*
|
||||||
|
* Defaults to `Infinity`, i.e. all events are returned
|
||||||
|
*/
|
||||||
|
limit?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chunk size, usually not needed.
|
||||||
|
*
|
||||||
|
* Defaults to `100`
|
||||||
|
*/
|
||||||
|
chunkSize?: number
|
||||||
|
}
|
||||||
|
): AsyncIterableIterator<PeerReaction>
|
||||||
/**
|
/**
|
||||||
* Get a single scheduled message in chat by its ID
|
* Get a single scheduled message in chat by its ID
|
||||||
*
|
*
|
||||||
|
@ -2603,6 +2670,12 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
message?: number,
|
message?: number,
|
||||||
clearMentions?: boolean
|
clearMentions?: boolean
|
||||||
): Promise<void>
|
): Promise<void>
|
||||||
|
/**
|
||||||
|
* Mark all reactions in chat as read.
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID
|
||||||
|
*/
|
||||||
|
readReactions(chatId: InputPeerLike): Promise<void>
|
||||||
/**
|
/**
|
||||||
* Search for messages globally from all of your chats
|
* Search for messages globally from all of your chats
|
||||||
*
|
*
|
||||||
|
@ -2979,6 +3052,21 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
clearDraft?: boolean
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message>
|
): Promise<Message>
|
||||||
|
/**
|
||||||
|
* Send or remove a reaction.
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID with the message to react to
|
||||||
|
* @param message Message ID to react to
|
||||||
|
* @param emoji Reaction emoji (or `null` to remove)
|
||||||
|
* @param big (default: `false`) Whether to use a big reaction
|
||||||
|
* @returns Message to which the reaction was sent
|
||||||
|
*/
|
||||||
|
sendReaction(
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
message: number,
|
||||||
|
emoji: string | null,
|
||||||
|
big?: boolean
|
||||||
|
): Promise<Message>
|
||||||
/**
|
/**
|
||||||
* Send s previously scheduled message.
|
* Send s previously scheduled message.
|
||||||
*
|
*
|
||||||
|
@ -3891,19 +3979,23 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
getDiscussionMessage = getDiscussionMessage
|
getDiscussionMessage = getDiscussionMessage
|
||||||
getHistory = getHistory
|
getHistory = getHistory
|
||||||
getMessageGroup = getMessageGroup
|
getMessageGroup = getMessageGroup
|
||||||
|
getMessageReactions = getMessageReactions
|
||||||
getMessagesUnsafe = getMessagesUnsafe
|
getMessagesUnsafe = getMessagesUnsafe
|
||||||
getMessages = getMessages
|
getMessages = getMessages
|
||||||
|
getReactionUsers = getReactionUsers
|
||||||
getScheduledMessages = getScheduledMessages
|
getScheduledMessages = getScheduledMessages
|
||||||
iterHistory = iterHistory
|
iterHistory = iterHistory
|
||||||
protected _normalizeInline = _normalizeInline
|
protected _normalizeInline = _normalizeInline
|
||||||
protected _parseEntities = _parseEntities
|
protected _parseEntities = _parseEntities
|
||||||
pinMessage = pinMessage
|
pinMessage = pinMessage
|
||||||
readHistory = readHistory
|
readHistory = readHistory
|
||||||
|
readReactions = readReactions
|
||||||
searchGlobal = searchGlobal
|
searchGlobal = searchGlobal
|
||||||
searchMessages = searchMessages
|
searchMessages = searchMessages
|
||||||
sendCopy = sendCopy
|
sendCopy = sendCopy
|
||||||
sendMediaGroup = sendMediaGroup
|
sendMediaGroup = sendMediaGroup
|
||||||
sendMedia = sendMedia
|
sendMedia = sendMedia
|
||||||
|
sendReaction = sendReaction
|
||||||
sendScheduled = sendScheduled
|
sendScheduled = sendScheduled
|
||||||
sendText = sendText
|
sendText = sendText
|
||||||
sendTyping = sendTyping
|
sendTyping = sendTyping
|
||||||
|
|
|
@ -55,6 +55,8 @@ import {
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
BotChatJoinRequestUpdate,
|
BotChatJoinRequestUpdate,
|
||||||
ChatJoinRequestUpdate,
|
ChatJoinRequestUpdate,
|
||||||
|
PeerReaction,
|
||||||
|
MessageReactions,
|
||||||
} from '../types'
|
} from '../types'
|
||||||
|
|
||||||
// @copy
|
// @copy
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import { InputPeerLike, PeersIndex, MessageReactions } from '../../types'
|
||||||
|
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||||
|
import { getMarkedPeerId, MaybeArray } from '@mtcute/core'
|
||||||
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get reactions to a message.
|
||||||
|
*
|
||||||
|
* > Apps should short-poll reactions for visible messages
|
||||||
|
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||||
|
* > but only if `message.reactions` is set
|
||||||
|
*
|
||||||
|
* @param chatId ID of the chat with the message
|
||||||
|
* @param messages Message ID
|
||||||
|
* @returns Reactions to the corresponding message, or `null` if there are none
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function getMessageReactions(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messages: number
|
||||||
|
): Promise<MessageReactions | null>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get reactions to messages.
|
||||||
|
*
|
||||||
|
* > Apps should short-poll reactions for visible messages
|
||||||
|
* > (that weren't sent by the user) once every 15-30 seconds,
|
||||||
|
* > but only if `message.reactions` is set
|
||||||
|
*
|
||||||
|
* @param chatId ID of the chat with messages
|
||||||
|
* @param messages Message IDs
|
||||||
|
* @returns Reactions to corresponding messages, or `null` if there are none
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function getMessageReactions(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messages: number[]
|
||||||
|
): Promise<(MessageReactions | null)[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function getMessageReactions(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messages: MaybeArray<number>
|
||||||
|
): Promise<MaybeArray<MessageReactions | null>> {
|
||||||
|
const single = !Array.isArray(messages)
|
||||||
|
if (!Array.isArray(messages)) {
|
||||||
|
messages = [messages]
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await this.call({
|
||||||
|
_: 'messages.getMessagesReactions',
|
||||||
|
peer: await this.resolvePeer(chatId),
|
||||||
|
id: messages,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertIsUpdatesGroup('messages.getMessagesReactions', res)
|
||||||
|
|
||||||
|
// normally the group contains updateMessageReactions
|
||||||
|
// for each message requested that has reactions
|
||||||
|
//
|
||||||
|
// these updates are not ordered in any way, so
|
||||||
|
// we don't need to pass them to updates engine
|
||||||
|
|
||||||
|
const index: Record<number, MessageReactions> = {}
|
||||||
|
|
||||||
|
const peers = PeersIndex.from(res)
|
||||||
|
|
||||||
|
for (const update of res.updates) {
|
||||||
|
assertTypeIs(
|
||||||
|
'messages.getMessagesReactions',
|
||||||
|
update,
|
||||||
|
'updateMessageReactions'
|
||||||
|
)
|
||||||
|
|
||||||
|
index[update.msgId] = new MessageReactions(
|
||||||
|
this,
|
||||||
|
update.msgId,
|
||||||
|
getMarkedPeerId(update.peer),
|
||||||
|
update.reactions,
|
||||||
|
peers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (single) {
|
||||||
|
return index[messages[0]] ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages.map((messageId) => index[messageId] ?? null)
|
||||||
|
}
|
77
packages/client/src/methods/messages/get-reaction-users.ts
Normal file
77
packages/client/src/methods/messages/get-reaction-users.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import {
|
||||||
|
InputPeerLike,
|
||||||
|
PeerReaction,
|
||||||
|
PeersIndex,
|
||||||
|
} from '../../types'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get users who have reacted to the message.
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID
|
||||||
|
* @param messageId Message ID
|
||||||
|
* @param params
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function* getReactionUsers(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
messageId: number,
|
||||||
|
params?: {
|
||||||
|
/**
|
||||||
|
* Get only reactions with the specified emoji
|
||||||
|
*/
|
||||||
|
emoji?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limit the number of events returned.
|
||||||
|
*
|
||||||
|
* Defaults to `Infinity`, i.e. all events are returned
|
||||||
|
*/
|
||||||
|
limit?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chunk size, usually not needed.
|
||||||
|
*
|
||||||
|
* Defaults to `100`
|
||||||
|
*/
|
||||||
|
chunkSize?: number
|
||||||
|
}
|
||||||
|
): AsyncIterableIterator<PeerReaction> {
|
||||||
|
if (!params) params = {}
|
||||||
|
|
||||||
|
const peer = await this.resolvePeer(chatId)
|
||||||
|
|
||||||
|
let current = 0
|
||||||
|
let offset: string | undefined = undefined
|
||||||
|
const total = params.limit || Infinity
|
||||||
|
const chunkSize = Math.min(params.chunkSize ?? 100, total)
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
const res: tl.RpcCallReturn['messages.getMessageReactionsList'] =
|
||||||
|
await this.call({
|
||||||
|
_: 'messages.getMessageReactionsList',
|
||||||
|
peer,
|
||||||
|
id: messageId,
|
||||||
|
reaction: params.emoji,
|
||||||
|
limit: Math.min(chunkSize, total - current),
|
||||||
|
offset,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!res.reactions.length) break
|
||||||
|
|
||||||
|
offset = res.nextOffset
|
||||||
|
|
||||||
|
const peers = PeersIndex.from(res)
|
||||||
|
|
||||||
|
for (const reaction of res.reactions) {
|
||||||
|
const parsed = new PeerReaction(this, reaction, peers)
|
||||||
|
|
||||||
|
current += 1
|
||||||
|
yield parsed
|
||||||
|
|
||||||
|
if (current >= total) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
packages/client/src/methods/messages/read-reactions.ts
Normal file
20
packages/client/src/methods/messages/read-reactions.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import { InputPeerLike } from '../../types'
|
||||||
|
import { createDummyUpdate } from '../../utils/updates-utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark all reactions in chat as read.
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function readReactions(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
): Promise<void> {
|
||||||
|
const res = await this.call({
|
||||||
|
_: 'messages.readReactions',
|
||||||
|
peer: await this.resolvePeer(chatId)
|
||||||
|
})
|
||||||
|
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount))
|
||||||
|
}
|
60
packages/client/src/methods/messages/send-reaction.ts
Normal file
60
packages/client/src/methods/messages/send-reaction.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import {
|
||||||
|
InputPeerLike,
|
||||||
|
Message,
|
||||||
|
MtTypeAssertionError,
|
||||||
|
PeersIndex,
|
||||||
|
} from '../../types'
|
||||||
|
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send or remove a reaction.
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID with the message to react to
|
||||||
|
* @param message Message ID to react to
|
||||||
|
* @param emoji Reaction emoji (or `null` to remove)
|
||||||
|
* @param big Whether to use a big reaction
|
||||||
|
* @returns Message to which the reaction was sent
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function sendReaction(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
message: number,
|
||||||
|
emoji: string | null,
|
||||||
|
big = false
|
||||||
|
): Promise<Message> {
|
||||||
|
const res = await this.call({
|
||||||
|
_: 'messages.sendReaction',
|
||||||
|
peer: await this.resolvePeer(chatId),
|
||||||
|
msgId: message,
|
||||||
|
reaction: emoji ?? undefined,
|
||||||
|
big,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertIsUpdatesGroup('messages.sendReaction', res)
|
||||||
|
|
||||||
|
// normally the group contains 2 updates:
|
||||||
|
// updateEditChannelMessage
|
||||||
|
// updateMessageReactions
|
||||||
|
// idk why, they contain literally the same data
|
||||||
|
// so we can just return the message from the first one
|
||||||
|
|
||||||
|
this._handleUpdate(res, true)
|
||||||
|
|
||||||
|
const upd = res.updates.find(
|
||||||
|
(it) => it._ === 'updateEditChannelMessage'
|
||||||
|
) as tl.RawUpdateEditChannelMessage | undefined
|
||||||
|
if (!upd) {
|
||||||
|
throw new MtTypeAssertionError(
|
||||||
|
'messages.sendReaction (@ .updates[*])',
|
||||||
|
'updateEditChannelMessage',
|
||||||
|
'undefined'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const peers = PeersIndex.from(res)
|
||||||
|
|
||||||
|
return new Message(this, upd.message, peers)
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ export * from './message'
|
||||||
export * from './search-filters'
|
export * from './search-filters'
|
||||||
export * from './draft-message'
|
export * from './draft-message'
|
||||||
export * from './dialog'
|
export * from './dialog'
|
||||||
|
export * from './reactions'
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import { User, Chat, InputPeerLike, PeersIndex } from '../peers'
|
import { User, Chat, InputPeerLike, PeersIndex } from '../peers'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { BotKeyboard, ReplyMarkup } from '../bots'
|
import { BotKeyboard, ReplyMarkup } from '../bots'
|
||||||
import { assertNever, getMarkedPeerId, toggleChannelIdMark } from "@mtcute/core";
|
import { assertNever, getMarkedPeerId, toggleChannelIdMark } from '@mtcute/core'
|
||||||
import {
|
import { MtArgumentError, MtTypeAssertionError } from '../errors'
|
||||||
MtArgumentError,
|
|
||||||
MtTypeAssertionError,
|
|
||||||
} from '../errors'
|
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import { MessageEntity } from './message-entity'
|
import { MessageEntity } from './message-entity'
|
||||||
import { makeInspectable } from '../utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
@ -13,6 +10,7 @@ import { InputMediaLike, WebPage } from '../media'
|
||||||
import { _messageActionFromTl, MessageAction } from './message-action'
|
import { _messageActionFromTl, MessageAction } from './message-action'
|
||||||
import { _messageMediaFromTl, MessageMedia } from './message-media'
|
import { _messageMediaFromTl, MessageMedia } from './message-media'
|
||||||
import { FormattedString } from '../parser'
|
import { FormattedString } from '../parser'
|
||||||
|
import { MessageReactions } from './reactions'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message or a service message
|
* A message or a service message
|
||||||
|
@ -314,7 +312,7 @@ export class Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.comments) {
|
if (r.comments) {
|
||||||
const o = (obj as unknown) as Message.MessageCommentsInfo
|
const o = obj as unknown as Message.MessageCommentsInfo
|
||||||
o.discussion = getMarkedPeerId(r.channelId!, 'channel')
|
o.discussion = getMarkedPeerId(r.channelId!, 'channel')
|
||||||
o.repliers =
|
o.repliers =
|
||||||
r.recentRepliers?.map((it) => getMarkedPeerId(it)) ?? []
|
r.recentRepliers?.map((it) => getMarkedPeerId(it)) ?? []
|
||||||
|
@ -490,6 +488,34 @@ export class Message {
|
||||||
return this._markup
|
return this._markup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this message can be forwarded
|
||||||
|
*
|
||||||
|
* `false` for service mesasges and private restricted chats/chanenls
|
||||||
|
*/
|
||||||
|
get canBeForwarded(): boolean {
|
||||||
|
return this.raw._ === 'message' && !this.raw.noforwards
|
||||||
|
}
|
||||||
|
|
||||||
|
private _reactions?: MessageReactions | null
|
||||||
|
get reactions(): MessageReactions | null {
|
||||||
|
if (this._reactions === undefined) {
|
||||||
|
if (this.raw._ === 'messageService' || !this.raw.reactions) {
|
||||||
|
this._reactions = null
|
||||||
|
} else {
|
||||||
|
this._reactions = new MessageReactions(
|
||||||
|
this.client,
|
||||||
|
this.raw.id,
|
||||||
|
getMarkedPeerId(this.raw.peerId),
|
||||||
|
this.raw.reactions,
|
||||||
|
this._peers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._reactions
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generated permalink to this message, only for groups and channels
|
* Generated permalink to this message, only for groups and channels
|
||||||
*
|
*
|
||||||
|
@ -892,6 +918,21 @@ export class Message {
|
||||||
clearMentions
|
clearMentions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React to this message
|
||||||
|
*
|
||||||
|
* @param emoji Reaction emoji
|
||||||
|
* @param big Whether to use a big reaction
|
||||||
|
*/
|
||||||
|
async react(emoji: string | null, big?: boolean): Promise<Message> {
|
||||||
|
return this.client.sendReaction(
|
||||||
|
this.chat.inputPeer,
|
||||||
|
this.raw.id,
|
||||||
|
emoji,
|
||||||
|
big
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeInspectable(Message, ['isScheduled'], ['link'])
|
makeInspectable(Message, ['isScheduled'], ['link'])
|
||||||
|
|
118
packages/client/src/types/messages/reactions.ts
Normal file
118
packages/client/src/types/messages/reactions.ts
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
import { makeInspectable } from '../utils'
|
||||||
|
import { getMarkedPeerId } from '@mtcute/core'
|
||||||
|
import { PeersIndex, User } from '../peers'
|
||||||
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
|
|
||||||
|
export class PeerReaction {
|
||||||
|
constructor(
|
||||||
|
readonly client: TelegramClient,
|
||||||
|
readonly raw: tl.RawMessagePeerReaction,
|
||||||
|
readonly _peers: PeersIndex
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emoji representing the reaction
|
||||||
|
*/
|
||||||
|
get emoji(): string {
|
||||||
|
return this.raw.reaction!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this is a big reaction
|
||||||
|
*/
|
||||||
|
get big(): boolean {
|
||||||
|
return this.raw.big!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this reaction is unread by the current user
|
||||||
|
*/
|
||||||
|
get unread(): boolean {
|
||||||
|
return this.raw.unread!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the user who has reacted
|
||||||
|
*/
|
||||||
|
get userId(): number {
|
||||||
|
return getMarkedPeerId(this.raw.peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private _user?: User
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User who has reacted
|
||||||
|
*/
|
||||||
|
get user(): User {
|
||||||
|
if (!this._user) {
|
||||||
|
assertTypeIs('PeerReaction#user', this.raw.peerId, 'peerUser')
|
||||||
|
|
||||||
|
this._user = new User(
|
||||||
|
this.client,
|
||||||
|
this._peers.user(this.raw.peerId.userId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(PeerReaction)
|
||||||
|
|
||||||
|
export class MessageReactions {
|
||||||
|
constructor(
|
||||||
|
readonly client: TelegramClient,
|
||||||
|
readonly messageId: number,
|
||||||
|
readonly chatId: number,
|
||||||
|
readonly raw: tl.RawMessageReactions,
|
||||||
|
readonly _peers: PeersIndex
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether you can use {@link getUsers}
|
||||||
|
* (or {@link TelegramClient.getReactionUsers})
|
||||||
|
* to get the users who reacted to this message
|
||||||
|
*/
|
||||||
|
get usersVisible(): boolean {
|
||||||
|
return this.raw.canSeeList!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reactions on the message, along with their counts
|
||||||
|
*/
|
||||||
|
get reactions(): tl.TypeReactionCount[] {
|
||||||
|
return this.raw.results
|
||||||
|
}
|
||||||
|
|
||||||
|
private _recentReactions?: PeerReaction[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recently reacted users.
|
||||||
|
* To get a full list of users, use {@link getUsers}
|
||||||
|
*/
|
||||||
|
get recentReactions(): PeerReaction[] {
|
||||||
|
if (!this.raw.recentReactions) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._recentReactions) {
|
||||||
|
this._recentReactions = this.raw.recentReactions.map(
|
||||||
|
(reaction) =>
|
||||||
|
new PeerReaction(this.client, reaction, this._peers)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._recentReactions
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the users who reacted to this message
|
||||||
|
*/
|
||||||
|
getUsers(params?: Parameters<TelegramClient['getReactionUsers']>[2]): AsyncIterableIterator<PeerReaction> {
|
||||||
|
return this.client.getReactionUsers(this.messageId, this.chatId, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(MessageReactions)
|
Loading…
Reference in a new issue