feat(client): support all possible inline results and messages
This commit is contained in:
parent
03bf248658
commit
d469b81a85
8 changed files with 1060 additions and 35 deletions
|
@ -1630,7 +1630,7 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
||||
* @param medias Medias contained in the message.
|
||||
* @param params Additional sending parameters
|
||||
* @see InputMedia
|
||||
* @link InputMedia
|
||||
*/
|
||||
sendMediaGroup(
|
||||
chatId: InputPeerLike,
|
||||
|
@ -1698,7 +1698,7 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
* and Bot API compatible File ID, which will be wrapped
|
||||
* in {@link InputMedia.auto}
|
||||
* @param params Additional sending parameters
|
||||
* @see InputMedia
|
||||
* @link InputMedia
|
||||
*/
|
||||
sendMedia(
|
||||
chatId: InputPeerLike,
|
||||
|
|
|
@ -16,7 +16,7 @@ import { tl } from '@mtcute/tl'
|
|||
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
||||
* @param medias Medias contained in the message.
|
||||
* @param params Additional sending parameters
|
||||
* @see InputMedia
|
||||
* @link InputMedia
|
||||
* @internal
|
||||
*/
|
||||
export async function sendMediaGroup(
|
||||
|
|
|
@ -18,7 +18,7 @@ import { normalizeDate, randomUlong } from '../../utils/misc-utils'
|
|||
* and Bot API compatible File ID, which will be wrapped
|
||||
* in {@link InputMedia.auto}
|
||||
* @param params Additional sending parameters
|
||||
* @see InputMedia
|
||||
* @link InputMedia
|
||||
* @internal
|
||||
*/
|
||||
export async function sendMedia(
|
||||
|
|
|
@ -2,6 +2,9 @@ import { tl } from '@mtcute/tl'
|
|||
import { BotKeyboard, ReplyMarkup } from '../keyboards'
|
||||
import { TelegramClient } from '../../../client'
|
||||
|
||||
/**
|
||||
* Inline message containing only text
|
||||
*/
|
||||
export interface InputInlineMessageText {
|
||||
type: 'text'
|
||||
|
||||
|
@ -27,8 +30,145 @@ export interface InputInlineMessageText {
|
|||
disableWebPreview?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline message containing media, which is automatically
|
||||
* inferred from the result itself.
|
||||
*/
|
||||
export interface InputInlineMessageMedia {
|
||||
type: 'media'
|
||||
|
||||
/**
|
||||
* Caption for the media
|
||||
*/
|
||||
text?: string
|
||||
|
||||
/**
|
||||
* Caption markup entities.
|
||||
* If passed, parse mode is ignored
|
||||
*/
|
||||
entities?: tl.TypeMessageEntity[]
|
||||
|
||||
/**
|
||||
* Message reply markup
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline message containing a geolocation
|
||||
*/
|
||||
export interface InputInlineMessageGeo {
|
||||
type: 'geo'
|
||||
|
||||
/**
|
||||
* Latitude of the geolocation
|
||||
*/
|
||||
latitude: number
|
||||
|
||||
/**
|
||||
* Longitude of the geolocation
|
||||
*/
|
||||
longitude: number
|
||||
|
||||
/**
|
||||
* For live locations, direction in which the location
|
||||
* moves, in degrees (1-360)
|
||||
*/
|
||||
heading?: number
|
||||
|
||||
/**
|
||||
* For live locations, period for which this live location
|
||||
* will be updated
|
||||
*/
|
||||
period?: number
|
||||
|
||||
/**
|
||||
* For live locations, a maximum distance to another
|
||||
* chat member for proximity alerts, in meters (0-100000)
|
||||
*/
|
||||
proximityNotificationRadius?: number
|
||||
|
||||
/**
|
||||
* Message's reply markup
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline message containing a venue
|
||||
*/
|
||||
export interface InputInlineMessageVenue {
|
||||
type: 'venue'
|
||||
|
||||
/**
|
||||
* Latitude of the geolocation
|
||||
*/
|
||||
latitude: number
|
||||
|
||||
/**
|
||||
* Longitude of the geolocation
|
||||
*/
|
||||
longitude: number
|
||||
|
||||
/**
|
||||
* Venue name
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Venue address
|
||||
*/
|
||||
address: string
|
||||
|
||||
/**
|
||||
* When available, source from where this venue was acquired
|
||||
*/
|
||||
source?: {
|
||||
/**
|
||||
* Provider name (`foursquare` or `gplaces` for Google Places)
|
||||
*/
|
||||
provider?: 'foursquare' | 'gplaces'
|
||||
|
||||
/**
|
||||
* Venue ID in the provider's DB
|
||||
*/
|
||||
id: string
|
||||
|
||||
/**
|
||||
* Venue type in the provider's DB
|
||||
*
|
||||
* - [Supported types for Foursquare](https://developer.foursquare.com/docs/build-with-foursquare/categories/)
|
||||
* (use names, lowercase them, replace spaces and " & " with `_` (underscore) and remove other symbols,
|
||||
* and use `/` (slash) as hierarchy separator)
|
||||
* - [Supported types for Google Places](https://developers.google.com/places/web-service/supported_types)
|
||||
*/
|
||||
type: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Message's reply markup
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline message containing a game
|
||||
*/
|
||||
export interface InputInlineMessageGame {
|
||||
type: 'game'
|
||||
|
||||
/**
|
||||
* Message's reply markup
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
}
|
||||
|
||||
export type InputInlineMessage =
|
||||
| InputInlineMessageText
|
||||
| InputInlineMessageMedia
|
||||
| InputInlineMessageGeo
|
||||
| InputInlineMessageVenue
|
||||
| InputInlineMessageGame
|
||||
|
||||
export namespace BotInlineMessage {
|
||||
export function text (
|
||||
|
@ -44,6 +184,52 @@ export namespace BotInlineMessage {
|
|||
}
|
||||
}
|
||||
|
||||
export function media (
|
||||
text?: string,
|
||||
params?: Omit<InputInlineMessageMedia, 'type' | 'text'>,
|
||||
): InputInlineMessageMedia {
|
||||
return {
|
||||
type: 'media',
|
||||
text,
|
||||
...(
|
||||
params || {}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
export function geo (
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
params?: Omit<InputInlineMessageGeo, 'type' | 'latitude' | 'longitude'>,
|
||||
): InputInlineMessageGeo {
|
||||
return {
|
||||
type: 'geo',
|
||||
latitude,
|
||||
longitude,
|
||||
...(
|
||||
params || {}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
export function venue (
|
||||
params: Omit<InputInlineMessageVenue, 'type'>,
|
||||
): InputInlineMessageVenue {
|
||||
return {
|
||||
type: 'venue',
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function game (
|
||||
params: Omit<InputInlineMessageGame, 'type'>,
|
||||
): InputInlineMessageGame {
|
||||
return {
|
||||
type: 'game',
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export async function _convertToTl (
|
||||
client: TelegramClient,
|
||||
obj: InputInlineMessage,
|
||||
|
@ -60,6 +246,56 @@ export namespace BotInlineMessage {
|
|||
}
|
||||
}
|
||||
|
||||
if (obj.type === 'media') {
|
||||
const [message, entities] = await client['_parseEntities'](obj.text, parseMode, obj.entities)
|
||||
|
||||
return {
|
||||
_: 'inputBotInlineMessageMediaAuto',
|
||||
message,
|
||||
entities,
|
||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup)
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.type === 'geo') {
|
||||
return {
|
||||
_: 'inputBotInlineMessageMediaGeo',
|
||||
geoPoint: {
|
||||
_: 'inputGeoPoint',
|
||||
lat: obj.latitude,
|
||||
long: obj.longitude
|
||||
},
|
||||
heading: obj.heading,
|
||||
period: obj.period,
|
||||
proximityNotificationRadius: obj.proximityNotificationRadius,
|
||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup)
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.type === 'venue') {
|
||||
return {
|
||||
_: 'inputBotInlineMessageMediaVenue',
|
||||
geoPoint: {
|
||||
_: 'inputGeoPoint',
|
||||
lat: obj.latitude,
|
||||
long: obj.longitude
|
||||
},
|
||||
title: obj.title,
|
||||
address: obj.address,
|
||||
provider: obj.source?.provider ?? '',
|
||||
venueId: obj.source?.id ?? '',
|
||||
venueType: obj.source?.type ?? '',
|
||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup)
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.type === 'game') {
|
||||
return {
|
||||
_: 'inputBotInlineMessageGame',
|
||||
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup)
|
||||
}
|
||||
}
|
||||
|
||||
return obj as never
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { tl } from '@mtcute/tl'
|
||||
import { BotInlineMessage, InputInlineMessage } from './input-inline-message'
|
||||
import { TelegramClient } from '../../../client'
|
||||
import { fileIdToInputDocument, fileIdToInputPhoto } from '@mtcute/file-id'
|
||||
import { extractFileName } from '../../../utils/file-utils'
|
||||
import { MtCuteArgumentError } from '../../errors'
|
||||
|
||||
interface BaseInputInlineResult {
|
||||
/**
|
||||
|
@ -19,7 +22,7 @@ interface BaseInputInlineResult {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents an input article.
|
||||
* Inline result containing an article.
|
||||
*
|
||||
* If `message` is not provided, a {@link InputInlineMessageText} is created
|
||||
* with web preview enabled and text generated as follows:
|
||||
|
@ -63,40 +66,615 @@ export interface InputInlineResultArticle extends BaseInputInlineResult {
|
|||
hideUrl?: boolean
|
||||
|
||||
/**
|
||||
* Article thumbnail URL (only jpeg).
|
||||
* Article thumbnail URL (must be jpeg).
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
}
|
||||
|
||||
export type InputInlineResult = InputInlineResultArticle
|
||||
/**
|
||||
* Inline result containing an animation (silent mp4 or gif).
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used
|
||||
* with empty caption
|
||||
*/
|
||||
export interface InputInlineResultGif extends BaseInputInlineResult {
|
||||
type: 'gif'
|
||||
|
||||
/**
|
||||
* The animation itself.
|
||||
*
|
||||
* Can be a URL, a TDLib and Bot API compatible File ID,
|
||||
* or a TL object representing either of them.
|
||||
*/
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument
|
||||
|
||||
/**
|
||||
* Media MIME type, defaults to `video/mp4`, only applicable
|
||||
* to URLs.
|
||||
*
|
||||
* Usually unnecessary, since Telegram automatically infers it.
|
||||
*/
|
||||
mime?: string
|
||||
|
||||
/**
|
||||
* Title of the result
|
||||
*/
|
||||
title?: string
|
||||
|
||||
/**
|
||||
* Animation thumbnail URL. Defaults to `media`,
|
||||
* only applicable in case `media` is a URL
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
|
||||
/**
|
||||
* Thumbnail MIME type (defaults to `image/jpeg`)
|
||||
*/
|
||||
thumbMime?: string
|
||||
|
||||
/**
|
||||
* Width of the animation in pixels
|
||||
*/
|
||||
width?: number
|
||||
|
||||
/**
|
||||
* Height of the animation in pixels
|
||||
*/
|
||||
height?: number
|
||||
|
||||
/**
|
||||
* Duration of the animation in seconds
|
||||
*/
|
||||
duration?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a video (only MP4)
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used
|
||||
* with empty caption for non-embed videos, {@link InputInlineMessageText}
|
||||
* is used with text containing the URL for embed videos.
|
||||
*/
|
||||
export interface InputInlineResultVideo extends BaseInputInlineResult {
|
||||
type: 'video'
|
||||
|
||||
/**
|
||||
* The video itself, or a page containing an embedded video
|
||||
*
|
||||
* Can be a URL, a TDLib and Bot API compatible File ID,
|
||||
* or a TL object representing either of them.
|
||||
*/
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument
|
||||
|
||||
/**
|
||||
* In case `media` is a URL, whether that URL is a link
|
||||
* to an embedded video player.
|
||||
*
|
||||
* In such case, thumbnail must be passed explicitly.
|
||||
*/
|
||||
isEmbed?: boolean
|
||||
|
||||
/**
|
||||
* Title of the result
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Description of the result
|
||||
*/
|
||||
description?: string
|
||||
|
||||
/**
|
||||
* Video thumbnail URL (must be jpeg). Defaults to `media`,
|
||||
* only applicable in case `media` is a URL.
|
||||
*
|
||||
* Must be provided explicitly if this is an embed video.
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
|
||||
/**
|
||||
* Width of the video in pixels
|
||||
*/
|
||||
width?: number
|
||||
|
||||
/**
|
||||
* Height of the video in pixels
|
||||
*/
|
||||
height?: number
|
||||
|
||||
/**
|
||||
* Duration of the video in seconds
|
||||
*/
|
||||
duration?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing an audio file
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used
|
||||
* with empty caption.
|
||||
*/
|
||||
export interface InputInlineResultAudio extends BaseInputInlineResult {
|
||||
type: 'audio'
|
||||
|
||||
/**
|
||||
* The audio itself
|
||||
*
|
||||
* Can be a URL, a TDLib and Bot API compatible File ID,
|
||||
* or a TL object representing either of them.
|
||||
*/
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument
|
||||
|
||||
/**
|
||||
* MIME type of the audio file, defaults to `audio/mpeg`
|
||||
*
|
||||
* Usually unnecessary, since Telegram infers it automatically.
|
||||
*/
|
||||
mime?: string
|
||||
|
||||
/**
|
||||
* Title of the audio track
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Performer of the audio track
|
||||
*/
|
||||
performer?: string
|
||||
|
||||
/**
|
||||
* Duration of the audio in seconds
|
||||
*/
|
||||
duration?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a voice note
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used
|
||||
* with empty caption.
|
||||
*/
|
||||
export interface InputInlineResultVoice extends BaseInputInlineResult {
|
||||
type: 'voice'
|
||||
|
||||
/**
|
||||
* The voice itself (.ogg, preferably encoded with OPUS)
|
||||
*
|
||||
* Can be a URL, a TDLib and Bot API compatible File ID,
|
||||
* or a TL object representing either of them.
|
||||
*/
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument
|
||||
|
||||
/**
|
||||
* Title of the result
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Duration of the voice note in seconds
|
||||
*/
|
||||
duration?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a photo
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used
|
||||
* with empty caption.
|
||||
*/
|
||||
export interface InputInlineResultPhoto extends BaseInputInlineResult {
|
||||
type: 'photo'
|
||||
|
||||
/**
|
||||
* The photo itself
|
||||
*
|
||||
* Can be a URL, a TDLib and Bot API compatible File ID,
|
||||
* or a TL object representing either of them.
|
||||
*/
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputPhoto
|
||||
|
||||
/**
|
||||
* Title of the result
|
||||
*/
|
||||
title?: string
|
||||
|
||||
/**
|
||||
* Description of the result
|
||||
*/
|
||||
description?: string
|
||||
|
||||
/**
|
||||
* Width of the photo in pixels
|
||||
*/
|
||||
width?: number
|
||||
|
||||
/**
|
||||
* Height of the photo in pixels
|
||||
*/
|
||||
height?: number
|
||||
|
||||
/**
|
||||
* Photo thumbnail URL (must be jpeg). Defaults to `media`,
|
||||
* only applicable in case `media` is a URL
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a sticker
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used.
|
||||
*/
|
||||
export interface InputInlineResultSticker extends BaseInputInlineResult {
|
||||
type: 'sticker'
|
||||
|
||||
/**
|
||||
* The sticker itself. Can't be a URL.
|
||||
*/
|
||||
media: string | tl.RawInputDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a document
|
||||
*
|
||||
* If `message` is not provided, {@link InputInlineMessageMedia} is used
|
||||
* with empty caption.
|
||||
*/
|
||||
export interface InputInlineResultFile extends BaseInputInlineResult {
|
||||
type: 'file'
|
||||
|
||||
/**
|
||||
* The file itself
|
||||
*
|
||||
* Can be a URL, a TDLib and Bot API compatible File ID,
|
||||
* or a TL object representing either of them.
|
||||
*/
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument
|
||||
|
||||
/**
|
||||
* MIME type of the file.
|
||||
*
|
||||
* Due to some Telegram limitation, you can only send
|
||||
* PDF and ZIP files (`application/pdf` and `application/zip`
|
||||
* MIMEs respectively).
|
||||
*
|
||||
* Must be provided if `media` is a URL
|
||||
*/
|
||||
mime?: string
|
||||
|
||||
/**
|
||||
* Title of the result
|
||||
*/
|
||||
title?: string
|
||||
|
||||
/**
|
||||
* Description of the result
|
||||
*/
|
||||
description?: string
|
||||
|
||||
/**
|
||||
* Photo thumbnail URL (must be jpeg). Defaults to `media`,
|
||||
* only applicable in case `media` is a URL
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a geolocation.
|
||||
*
|
||||
* If `message` is not passed, a {@link InputInlineMessageGeo} is
|
||||
* used, with the `latitude` and `longitude` parameters set
|
||||
* accordingly
|
||||
*/
|
||||
export interface InputInlineResultGeo extends BaseInputInlineResult {
|
||||
type: 'geo'
|
||||
|
||||
/**
|
||||
* Title of the result
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Latitude of the geolocation
|
||||
*/
|
||||
latitude: number
|
||||
|
||||
/**
|
||||
* Longitude of the geolocation
|
||||
*/
|
||||
longitude: number
|
||||
|
||||
/**
|
||||
* Location thumbnail URL (must be jpeg).
|
||||
*
|
||||
* By default, Telegram generates one based on
|
||||
* the location set by `latitude` and `longitude`
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a venue.
|
||||
*
|
||||
* If `message` is not passed, an error is thrown.
|
||||
*/
|
||||
export interface InputInlineResultVenue extends BaseInputInlineResult {
|
||||
type: 'venue'
|
||||
|
||||
/**
|
||||
* Title of the venue
|
||||
*/
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Address of the venue
|
||||
*/
|
||||
address: string
|
||||
|
||||
/**
|
||||
* Venue thumbnail URL (must be jpeg).
|
||||
*
|
||||
* By default, Telegram generates one based on
|
||||
* the location in the `message`
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a game.
|
||||
*
|
||||
* If `message` is not passed, {@link InputInlineMessageGame} is used.
|
||||
*
|
||||
* Note that `message` can only be {@link InputInlineMessageGame}
|
||||
*/
|
||||
export interface InputInlineResultGame extends BaseInputInlineResult {
|
||||
type: 'game'
|
||||
|
||||
/**
|
||||
* Short name of the game
|
||||
*/
|
||||
shortName: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline result containing a contact.
|
||||
*
|
||||
* If `message` is not passed, {@link InputInlineMessageContact} is used.
|
||||
*/
|
||||
export interface InputInlineResultContact extends BaseInputInlineResult {
|
||||
type: 'contact'
|
||||
|
||||
/**
|
||||
* First name of the contact
|
||||
*/
|
||||
firstName: string
|
||||
|
||||
/**
|
||||
* Last name of the contact
|
||||
*/
|
||||
lastName?: string
|
||||
|
||||
/**
|
||||
* Phone number of the contact
|
||||
*/
|
||||
phone: string
|
||||
|
||||
/**
|
||||
* Contact thumbnail URL (i.e. their avatar) (must be jpeg)
|
||||
*/
|
||||
thumb?: string | tl.RawInputWebDocument
|
||||
}
|
||||
|
||||
export type InputInlineResult =
|
||||
| InputInlineResultArticle
|
||||
| InputInlineResultGif
|
||||
| InputInlineResultVideo
|
||||
| InputInlineResultAudio
|
||||
| InputInlineResultVoice
|
||||
| InputInlineResultPhoto
|
||||
| InputInlineResultSticker
|
||||
| InputInlineResultFile
|
||||
| InputInlineResultGeo
|
||||
| InputInlineResultVenue
|
||||
| InputInlineResultGame
|
||||
| InputInlineResultContact
|
||||
|
||||
export namespace BotInline {
|
||||
export function article(
|
||||
params: Omit<InputInlineResultArticle, 'type'>
|
||||
id: string,
|
||||
params: Omit<InputInlineResultArticle, 'type' | 'id'>
|
||||
): InputInlineResultArticle {
|
||||
return {
|
||||
id,
|
||||
type: 'article',
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function gif(
|
||||
id: string,
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument,
|
||||
params: Omit<InputInlineResultGif, 'type' | 'id' | 'media'>
|
||||
): InputInlineResultGif {
|
||||
return {
|
||||
id,
|
||||
media,
|
||||
type: 'gif',
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function video(
|
||||
id: string,
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument,
|
||||
params: Omit<InputInlineResultVideo, 'type' | 'id' | 'media'>
|
||||
): InputInlineResultVideo {
|
||||
return {
|
||||
id,
|
||||
type: 'video',
|
||||
media,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function audio(
|
||||
id: string,
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument,
|
||||
params: Omit<InputInlineResultAudio, 'type' | 'id' | 'media'>
|
||||
): InputInlineResultAudio {
|
||||
return {
|
||||
id,
|
||||
type: 'audio',
|
||||
media,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function voice(
|
||||
id: string,
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument,
|
||||
params: Omit<InputInlineResultVoice, 'type' | 'id' | 'media'>
|
||||
): InputInlineResultVoice {
|
||||
return {
|
||||
id,
|
||||
type: 'voice',
|
||||
media,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function photo(
|
||||
id: string,
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputPhoto,
|
||||
params: Omit<InputInlineResultPhoto, 'type' | 'id' | 'media'>
|
||||
): InputInlineResultPhoto {
|
||||
return {
|
||||
id,
|
||||
type: 'photo',
|
||||
media,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function sticker(
|
||||
id: string,
|
||||
media: string | tl.RawInputDocument
|
||||
): InputInlineResultSticker {
|
||||
return {
|
||||
id,
|
||||
type: 'sticker',
|
||||
media,
|
||||
}
|
||||
}
|
||||
|
||||
export function file(
|
||||
id: string,
|
||||
media: string | tl.RawInputWebDocument | tl.RawInputDocument,
|
||||
params: Omit<InputInlineResultFile, 'type' | 'id' | 'media'>
|
||||
): InputInlineResultFile {
|
||||
return {
|
||||
id,
|
||||
type: 'file',
|
||||
media,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function geo(
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
params: Omit<InputInlineResultGeo, 'type' | 'latitude' | 'longitude'>
|
||||
): InputInlineResultGeo {
|
||||
return {
|
||||
type: 'geo',
|
||||
latitude,
|
||||
longitude,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function venue(
|
||||
id: string,
|
||||
params: Omit<InputInlineResultVenue, 'type' | 'id'>
|
||||
): InputInlineResultVenue {
|
||||
return {
|
||||
id,
|
||||
type: 'venue',
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function contact(
|
||||
id: string,
|
||||
params: Omit<InputInlineResultContact, 'type' | 'id'>
|
||||
): InputInlineResultContact {
|
||||
return {
|
||||
id,
|
||||
type: 'contact',
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
export function game(
|
||||
id: string,
|
||||
shortName: string,
|
||||
params?: Omit<InputInlineResultGame, 'type' | 'id' | 'shortName'>
|
||||
): InputInlineResultGame {
|
||||
return {
|
||||
id,
|
||||
type: 'game',
|
||||
shortName,
|
||||
...(params || {})
|
||||
}
|
||||
}
|
||||
|
||||
export async function _convertToTl(
|
||||
client: TelegramClient,
|
||||
obj: InputInlineResult,
|
||||
parseMode?: string | null
|
||||
): Promise<tl.TypeInputBotInlineResult> {
|
||||
const normalizeThumb = (
|
||||
obj: InputInlineResult,
|
||||
fallback?: string
|
||||
): tl.RawInputWebDocument | undefined => {
|
||||
if (obj.type !== 'voice' && obj.type !== 'audio' && obj.type !== 'sticker' && obj.type !== 'game') {
|
||||
if (!obj.thumb || typeof obj.thumb === 'string') {
|
||||
if (!obj.thumb && !fallback) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputWebDocument',
|
||||
size: 0,
|
||||
url: obj.thumb || fallback!,
|
||||
mimeType:
|
||||
obj.type === 'gif'
|
||||
? obj.thumbMime ?? 'image/jpeg'
|
||||
: 'image/jpeg',
|
||||
attributes: [],
|
||||
}
|
||||
} else {
|
||||
return obj.thumb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.type === 'article') {
|
||||
let sendMessage: tl.TypeInputBotInlineMessage
|
||||
if (obj.message) {
|
||||
sendMessage = await BotInlineMessage._convertToTl(client, obj.message, parseMode)
|
||||
sendMessage = await BotInlineMessage._convertToTl(
|
||||
client,
|
||||
obj.message,
|
||||
parseMode
|
||||
)
|
||||
} else {
|
||||
let message = obj.title
|
||||
const entities: tl.TypeMessageEntity[] = [
|
||||
{
|
||||
_: 'messageEntityBold',
|
||||
offset: 0,
|
||||
length: message.length
|
||||
}
|
||||
length: message.length,
|
||||
},
|
||||
]
|
||||
|
||||
if (obj.url) {
|
||||
|
@ -104,7 +682,7 @@ export namespace BotInline {
|
|||
_: 'messageEntityTextUrl',
|
||||
url: obj.url,
|
||||
offset: 0,
|
||||
length: message.length
|
||||
length: message.length,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -115,7 +693,7 @@ export namespace BotInline {
|
|||
sendMessage = {
|
||||
_: 'inputBotInlineMessageText',
|
||||
message,
|
||||
entities
|
||||
entities,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,24 +704,235 @@ export namespace BotInline {
|
|||
title: obj.title,
|
||||
description: obj.description,
|
||||
url: obj.hideUrl ? undefined : obj.url,
|
||||
content: obj.url && obj.hideUrl ? {
|
||||
content:
|
||||
obj.url && obj.hideUrl
|
||||
? {
|
||||
_: 'inputWebDocument',
|
||||
url: obj.url,
|
||||
mimeType: 'text/html',
|
||||
size: 0,
|
||||
attributes: []
|
||||
} : undefined,
|
||||
thumb: typeof obj.thumb === 'string' ? {
|
||||
_: 'inputWebDocument',
|
||||
size: 0,
|
||||
url: obj.thumb,
|
||||
mimeType: 'image/jpeg',
|
||||
attributes: [],
|
||||
} : obj.thumb,
|
||||
}
|
||||
: undefined,
|
||||
thumb:
|
||||
typeof obj.thumb === 'string'
|
||||
? normalizeThumb(obj)
|
||||
: obj.thumb,
|
||||
sendMessage,
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.type === 'game') {
|
||||
let sendMessage: tl.TypeInputBotInlineMessage
|
||||
if (obj.message) {
|
||||
sendMessage = await BotInlineMessage._convertToTl(
|
||||
client,
|
||||
obj.message,
|
||||
parseMode
|
||||
)
|
||||
if (sendMessage._ !== 'inputBotInlineMessageGame') {
|
||||
throw new MtCuteArgumentError('game inline result must contain a game inline message')
|
||||
}
|
||||
} else {
|
||||
sendMessage = {
|
||||
_: 'inputBotInlineMessageGame'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputBotInlineResultGame',
|
||||
id: obj.id,
|
||||
shortName: obj.shortName,
|
||||
sendMessage
|
||||
}
|
||||
}
|
||||
|
||||
return obj as never
|
||||
let sendMessage: tl.TypeInputBotInlineMessage
|
||||
if (obj.message) {
|
||||
sendMessage = await BotInlineMessage._convertToTl(
|
||||
client,
|
||||
obj.message,
|
||||
parseMode
|
||||
)
|
||||
} else {
|
||||
if (obj.type === 'venue')
|
||||
throw new MtCuteArgumentError('message bust be supplied for venue inline result')
|
||||
|
||||
if (
|
||||
obj.type === 'video' &&
|
||||
obj.isEmbed &&
|
||||
typeof obj.media === 'string'
|
||||
) {
|
||||
sendMessage = {
|
||||
_: 'inputBotInlineMessageText',
|
||||
message: obj.media,
|
||||
}
|
||||
} else if (obj.type === 'geo') {
|
||||
sendMessage = {
|
||||
_: 'inputBotInlineMessageMediaGeo',
|
||||
geoPoint: {
|
||||
_: 'inputGeoPoint',
|
||||
lat: obj.latitude,
|
||||
long: obj.longitude,
|
||||
},
|
||||
}
|
||||
} else if (obj.type === 'contact') {
|
||||
sendMessage = {
|
||||
_: 'inputBotInlineMessageMediaContact',
|
||||
phoneNumber: obj.phone,
|
||||
firstName: obj.firstName,
|
||||
lastName: obj.lastName ?? '',
|
||||
vcard: ''
|
||||
|
||||
}
|
||||
} else {
|
||||
sendMessage = {
|
||||
_: 'inputBotInlineMessageMediaAuto',
|
||||
message: '',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let media:
|
||||
| tl.TypeInputWebDocument
|
||||
| tl.TypeInputDocument
|
||||
| tl.TypeInputPhoto
|
||||
| undefined = undefined
|
||||
if (obj.type !== 'geo' && obj.type !== 'venue' && obj.type !== 'contact') {
|
||||
if (typeof obj.media === 'string') {
|
||||
// file id or url
|
||||
if (obj.media.match(/^https?:\/\//)) {
|
||||
if (obj.type === 'sticker')
|
||||
throw new MtCuteArgumentError('sticker inline result cannot contain a URL')
|
||||
|
||||
let mime: string
|
||||
if (obj.type === 'video') mime = 'video/mp4'
|
||||
else if (obj.type === 'audio')
|
||||
mime = obj.mime ?? 'audio/mpeg'
|
||||
else if (obj.type === 'gif') mime = obj.mime ?? 'image/jpeg'
|
||||
else if (obj.type === 'voice') mime = 'audio/ogg'
|
||||
else if (obj.type === 'file') {
|
||||
if (!obj.mime)
|
||||
throw new MtCuteArgumentError(
|
||||
'MIME type must be specified for file inline result'
|
||||
)
|
||||
|
||||
mime = obj.mime
|
||||
} else mime = 'image/jpeg'
|
||||
|
||||
const attributes: tl.TypeDocumentAttribute[] = []
|
||||
|
||||
if (
|
||||
(obj.type === 'video' ||
|
||||
obj.type === 'gif' ||
|
||||
obj.type === 'photo') &&
|
||||
obj.width &&
|
||||
obj.height
|
||||
) {
|
||||
if (obj.type !== 'photo' && obj.duration) {
|
||||
attributes.push({
|
||||
_: 'documentAttributeVideo',
|
||||
w: obj.width,
|
||||
h: obj.height,
|
||||
duration: obj.duration,
|
||||
})
|
||||
} else {
|
||||
attributes.push({
|
||||
_: 'documentAttributeImageSize',
|
||||
w: obj.width,
|
||||
h: obj.height,
|
||||
})
|
||||
}
|
||||
} else if (obj.type === 'audio' || obj.type === 'voice') {
|
||||
attributes.push({
|
||||
_: 'documentAttributeAudio',
|
||||
voice: obj.type === 'voice',
|
||||
duration: obj.duration ?? 0,
|
||||
title: obj.type === 'audio' ? obj.title : '',
|
||||
performer:
|
||||
obj.type === 'audio' ? obj.performer : '',
|
||||
})
|
||||
}
|
||||
|
||||
attributes.push({
|
||||
_: 'documentAttributeFilename',
|
||||
fileName: extractFileName(obj.media),
|
||||
})
|
||||
|
||||
media = {
|
||||
_: 'inputWebDocument',
|
||||
url: obj.media,
|
||||
mimeType: mime,
|
||||
size: 0,
|
||||
attributes,
|
||||
}
|
||||
} else if (obj.type === 'photo') {
|
||||
media = fileIdToInputPhoto(obj.media)
|
||||
} else {
|
||||
media = fileIdToInputDocument(obj.media)
|
||||
}
|
||||
} else {
|
||||
media = obj.media
|
||||
}
|
||||
}
|
||||
|
||||
let title: string | undefined = undefined
|
||||
let description: string | undefined = undefined
|
||||
|
||||
// incredible hacks by durov team.
|
||||
// i honestly don't understand why didn't they just
|
||||
// make a bunch of types, as they normally do,
|
||||
// but whatever.
|
||||
// ref: https://github.com/tdlib/td/blob/master/td/telegram/InlineQueriesManager.cpp
|
||||
if (obj.type === 'contact') {
|
||||
title = obj.lastName?.length ? `${obj.firstName} ${obj.lastName}` : obj.firstName
|
||||
} else if (obj.type !== 'sticker') {
|
||||
title = obj.title
|
||||
}
|
||||
|
||||
if (obj.type === 'audio') {
|
||||
description = obj.performer
|
||||
} else if (obj.type === 'geo') {
|
||||
description = `${obj.latitude} ${obj.longitude}`
|
||||
} else if (obj.type === 'venue') {
|
||||
description = obj.address
|
||||
} else if (obj.type === 'contact') {
|
||||
description = obj.phone
|
||||
} else if (obj.type !== 'gif' && obj.type !== 'voice' && obj.type !== 'sticker') {
|
||||
description = obj.description
|
||||
}
|
||||
|
||||
if (!media || media._ === 'inputWebDocument') {
|
||||
return {
|
||||
_: 'inputBotInlineResult',
|
||||
id: obj.id,
|
||||
type: obj.type,
|
||||
title,
|
||||
description,
|
||||
content: media,
|
||||
thumb: normalizeThumb(obj, media?.url),
|
||||
sendMessage,
|
||||
}
|
||||
}
|
||||
|
||||
if (media._ === 'inputPhoto') {
|
||||
return {
|
||||
_: 'inputBotInlineResultPhoto',
|
||||
id: obj.id,
|
||||
type: obj.type,
|
||||
photo: media,
|
||||
sendMessage,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputBotInlineResultDocument',
|
||||
id: obj.id,
|
||||
type: obj.type,
|
||||
title,
|
||||
description,
|
||||
document: media,
|
||||
sendMessage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ export class FileLocation {
|
|||
*
|
||||
* Shorthand for `client.downloadAsStream({ location: this })`
|
||||
*
|
||||
* @see TelegramClient.downloadAsIterable
|
||||
* @link TelegramClient.downloadAsIterable
|
||||
*/
|
||||
downloadIterable(): AsyncIterableIterator<Buffer> {
|
||||
return this.client.downloadAsIterable({ location: this })
|
||||
|
@ -96,7 +96,7 @@ export class FileLocation {
|
|||
*
|
||||
* Shorthand for `client.downloadAsStream({ location: this })`
|
||||
*
|
||||
* @see TelegramClient.downloadAsStream
|
||||
* @link TelegramClient.downloadAsStream
|
||||
*/
|
||||
downloadStream(): Readable {
|
||||
return this.client.downloadAsStream({ location: this })
|
||||
|
@ -107,7 +107,7 @@ export class FileLocation {
|
|||
*
|
||||
* Shorthand for `client.downloadAsBuffer({ location: this })`
|
||||
*
|
||||
* @see TelegramClient.downloadAsBuffer
|
||||
* @link TelegramClient.downloadAsBuffer
|
||||
*/
|
||||
downloadBuffer(): Promise<Buffer> {
|
||||
return this.client.downloadAsBuffer({ location: this })
|
||||
|
@ -120,7 +120,7 @@ export class FileLocation {
|
|||
* Shorthand for `client.downloadToFile(filename, { location: this })`
|
||||
*
|
||||
* @param filename Local file name
|
||||
* @see TelegramClient.downloadToFile
|
||||
* @link TelegramClient.downloadToFile
|
||||
*/
|
||||
downloadToFile(filename: string): Promise<void> {
|
||||
return this.client.downloadToFile(filename, { location: this })
|
||||
|
|
|
@ -240,7 +240,7 @@ export interface InputMediaVideo extends BaseInputMedia {
|
|||
* applicable if `file` is {@link UploadFileLike},
|
||||
* otherwise they are ignored.
|
||||
*
|
||||
* @see InputMedia
|
||||
* @link InputMedia
|
||||
*/
|
||||
export type InputMediaLike =
|
||||
| InputMediaAudio
|
||||
|
|
|
@ -931,7 +931,7 @@ export class Message {
|
|||
/**
|
||||
* Edit this message's text and/or reply markup
|
||||
*
|
||||
* @see TelegramClient.editMessage
|
||||
* @link TelegramClient.editMessage
|
||||
*/
|
||||
edit(
|
||||
params: Parameters<TelegramClient['editMessage']>[2]
|
||||
|
@ -947,7 +947,7 @@ export class Message {
|
|||
*
|
||||
* @param text New message text
|
||||
* @param params Additional parameters
|
||||
* @see TelegramClient.editMessage
|
||||
* @link TelegramClient.editMessage
|
||||
*/
|
||||
editText(
|
||||
text: string,
|
||||
|
|
Loading…
Reference in a new issue