feat(client): searchMessages method

also added an object for search filters
This commit is contained in:
teidesu 2021-04-08 22:56:40 +03:00
parent 451fdd0cfc
commit 3a2537cd1a
4 changed files with 228 additions and 0 deletions

View file

@ -24,6 +24,7 @@ import { getHistory } from './methods/messages/get-history'
import { getMessages } from './methods/messages/get-messages'
import { iterHistory } from './methods/messages/iter-history'
import { _parseEntities } from './methods/messages/parse-entities'
import { searchMessages } from './methods/messages/search-messages'
import { sendPhoto } from './methods/messages/send-photo'
import { sendText } from './methods/messages/send-text'
import {
@ -590,6 +591,63 @@ export class TelegramClient extends BaseTelegramClient {
): Promise<[string, tl.TypeMessageEntity[] | undefined]> {
return _parseEntities.apply(this, arguments)
}
/**
* Search for messages inside a specific chat
*
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`.
* @param params Additional search parameters
*/
searchMessages(
chatId: InputPeerLike,
params?: {
/**
* Text query string. Required for text-only messages,
* optional for media.
*
* Defaults to `""` (empty string)
*/
query?: string
/**
* Sequential number of the first message to be returned.
*
* Defaults to `0`.
*/
offset?: number
/**
* Limits the number of messages to be retrieved.
*
* By default, no limit is applied and all messages are returned
*/
limit?: number
/**
* Filter the results using some filter.
* Defaults to {@link SearchFilters.Empty} (i.e. will return all messages)
*
* @link SearchFilters
*/
filter?: tl.TypeMessagesFilter
/**
* Search for messages sent by a specific user.
*
* Pass their marked ID, username, phone or `"me"` or `"self"`
*/
fromUser?: InputPeerLike
/**
* Chunk size, which will be passed as `limit` parameter
* for `messages.search`. Usually you shouldn't care about this.
*
* Defaults to `100`
*/
chunkSize?: number
}
): AsyncIterableIterator<Message> {
return searchMessages.apply(this, arguments)
}
/**
* Send a single photo
*

View file

@ -0,0 +1,119 @@
import { TelegramClient } from '../../client'
import { InputPeerLike, Message, MtCuteTypeAssertionError } from '../../types'
import { tl } from '@mtcute/tl'
import {
createUsersChatsIndex,
normalizeToInputPeer,
} from '../../utils/peer-utils'
import { SearchFilters } from '../../types'
/**
* Search for messages inside a specific chat
*
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`.
* @param params Additional search parameters
* @internal
*/
export async function* searchMessages(
this: TelegramClient,
chatId: InputPeerLike,
params?: {
/**
* Text query string. Required for text-only messages,
* optional for media.
*
* Defaults to `""` (empty string)
*/
query?: string
/**
* Sequential number of the first message to be returned.
*
* Defaults to `0`.
*/
offset?: number
/**
* Limits the number of messages to be retrieved.
*
* By default, no limit is applied and all messages are returned
*/
limit?: number
/**
* Filter the results using some filter.
* Defaults to {@link SearchFilters.Empty} (i.e. will return all messages)
*
* @link SearchFilters
*/
filter?: tl.TypeMessagesFilter
/**
* Search for messages sent by a specific user.
*
* Pass their marked ID, username, phone or `"me"` or `"self"`
*/
fromUser?: InputPeerLike
/**
* Chunk size, which will be passed as `limit` parameter
* for `messages.search`. Usually you shouldn't care about this.
*
* Defaults to `100`
*/
chunkSize?: number
}
): AsyncIterableIterator<Message> {
if (!params) params = {}
let current = 0
let offset = params.offset || 0
const total = params.limit || Infinity
const limit = Math.min(params.chunkSize || 100, total)
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
const fromUser =
(params.fromUser
? normalizeToInputPeer(await this.resolvePeer(params.fromUser))
: null) || undefined
for (;;) {
const res = await this.call({
_: 'messages.search',
peer,
q: params.query || '',
filter: params.filter || SearchFilters.Empty,
minDate: 0,
maxDate: 0,
offsetId: 0,
addOffset: offset,
limit,
minId: 0,
maxId: 0,
fromId: fromUser,
hash: 0,
})
if (res._ === 'messages.messagesNotModified')
throw new MtCuteTypeAssertionError(
'searchMessages',
'!messages.messagesNotModified',
res._
)
const { users, chats } = createUsersChatsIndex(res)
const msgs = res.messages.map(
(msg) => new Message(this, msg, users, chats)
)
if (!msgs.length) break
offset += msgs.length
yield* msgs
current += msgs.length
if (current >= total) break
}
}

View file

@ -1,2 +1,3 @@
export * from './message-entity'
export * from './message'
export * from './search-filters'

View file

@ -0,0 +1,50 @@
import { tl } from '@mtcute/tl'
/**
* Search filters to be used in {@link TelegramClient.searchMessages}
* and {@link TelegramClient.searchGlobal}.
*
* Note that due to Telegram API limitations, you can't combine filters,
* and can only use a limited pre-defined set.
*
* This object simply exports static TL objects for convenience,
* if it does not expose something, simply pass a TL object
* directly.
*
* - `Empty`: Search for all messages (used by default)
* - `Photo`: Search for photos
* - `Video`: Search for videos
* - `PhotoAndVideo`: Search for photos and videos
* - `Document`: Search for documents (generic files, not including audio, video, etc.)
* - `Url`: Search for messages containing URLs and text links
* - `Gif`: Search for messages containing GIFs
* - `Voice`: Search for messages containing voice notes
* - `Audio`: Search for messages containing audio files
* - `ChatPhotoChange`: Search for chat photo changes
* - `Call`: Search for calls
* - `Round`: Search for round messages (aka video notes)
* - `RoundAndVoice`: Search for round messages (aka video notes) and voice notes
* - `MyMention`: Search for mentions of yourself
* - `Location`: Search for geolocations
* - `Contact`: Search for contacts
* - `Pinned`: Search for pinned messages
*/
export const SearchFilters = {
Empty: { _: 'inputMessagesFilterEmpty' } as tl.TypeMessagesFilter,
Photo: { _: 'inputMessagesFilterPhotos' } as tl.TypeMessagesFilter,
Video: { _: 'inputMessagesFilterVideo' } as tl.TypeMessagesFilter,
PhotoAndVideo: { _: 'inputMessagesFilterPhotoVideo' } as tl.TypeMessagesFilter,
Document: { _: 'inputMessagesFilterDocument' } as tl.TypeMessagesFilter,
Url: { _: 'inputMessagesFilterUrl' } as tl.TypeMessagesFilter,
Gif: { _: 'inputMessagesFilterGif' } as tl.TypeMessagesFilter,
Voice: { _: 'inputMessagesFilterVoice' } as tl.TypeMessagesFilter,
Audio: { _: 'inputMessagesFilterMusic' } as tl.TypeMessagesFilter,
ChatPhotoChange: { _: 'inputMessagesFilterChatPhotos' } as tl.TypeMessagesFilter,
Call: { _: 'inputMessagesFilterPhoneCalls' } as tl.TypeMessagesFilter,
Round: { _: 'inputMessagesFilterRoundVideo' } as tl.TypeMessagesFilter,
RoundAndVoice: { _: 'inputMessagesFilterRoundVoice' } as tl.TypeMessagesFilter,
MyMention: { _: 'inputMessagesFilterMyMentions' } as tl.TypeMessagesFilter,
Location: { _: 'inputMessagesFilterGeo' } as tl.TypeMessagesFilter,
Contact: { _: 'inputMessagesFilterContacts' } as tl.TypeMessagesFilter,
Pinned: { _: 'inputMessagesFilterPinned' } as tl.TypeMessagesFilter,
} as const