From 42c5d29167b71bb9c0cce62e3bf1ad495108510b Mon Sep 17 00:00:00 2001 From: teidesu <86301490+teidesu@users.noreply.github.com> Date: Wed, 13 Jul 2022 05:09:58 +0300 Subject: [PATCH] fix(client): automatically derive `gallery` for inline result --- .../src/methods/bots/answer-inline-query.ts | 11 +- .../types/bots/input/input-inline-result.ts | 543 +++++++++--------- 2 files changed, 290 insertions(+), 264 deletions(-) diff --git a/packages/client/src/methods/bots/answer-inline-query.ts b/packages/client/src/methods/bots/answer-inline-query.ts index 694ac636..bf8ffcb3 100644 --- a/packages/client/src/methods/bots/answer-inline-query.ts +++ b/packages/client/src/methods/bots/answer-inline-query.ts @@ -28,7 +28,10 @@ export async function answerInlineQuery( * Whether the results should be displayed as a gallery instead * of a vertical list. Only applicable to some media types. * - * Defaults to `true` + * In some cases changing this may lead to the results not being + * displayed by the client. + * + * Default is derived automatically based on result types */ gallery?: boolean @@ -94,16 +97,14 @@ export async function answerInlineQuery( ): Promise { if (!params) params = {} - const tlResults = await Promise.all( - results.map((it) => BotInline._convertToTl(this, it, params!.parseMode)) - ) + const [gallery, tlResults] = await BotInline._convertToTl(this, results, params!.parseMode) await this.call({ _: 'messages.setInlineBotResults', queryId, results: tlResults, cacheTime: params.cacheTime ?? 300, - gallery: params.gallery ?? true, + gallery: params.gallery ?? gallery, private: params.private, nextOffset: params.nextOffset, switchPm: params.switchPm diff --git a/packages/client/src/types/bots/input/input-inline-result.ts b/packages/client/src/types/bots/input/input-inline-result.ts index a67b1ebd..7c986fec 100644 --- a/packages/client/src/types/bots/input/input-inline-result.ts +++ b/packages/client/src/types/bots/input/input-inline-result.ts @@ -714,9 +714,9 @@ export namespace BotInline { /** @internal */ export async function _convertToTl( client: TelegramClient, - obj: InputInlineResult, + results: InputInlineResult[], parseMode?: string | null - ): Promise { + ): Promise<[boolean, tl.TypeInputBotInlineResult[]]> { const normalizeThumb = ( obj: InputInlineResult, fallback?: string @@ -748,306 +748,331 @@ export namespace BotInline { } } - if (obj.type === 'article') { - let sendMessage: tl.TypeInputBotInlineMessage - if (obj.message) { - sendMessage = await BotInlineMessage._convertToTl( - client, - obj.message, - parseMode - ) - } else { - let message = obj.title - const entities: tl.TypeMessageEntity[] = [ - { - _: 'messageEntityBold', - offset: 0, - length: message.length, - }, - ] + const items: tl.TypeInputBotInlineResult[] = [] - if (obj.url) { - entities.push({ - _: 'messageEntityTextUrl', - url: obj.url, - offset: 0, - length: message.length, - }) - } + let isGallery = false + let forceVertical = false - if (obj.description) { - message += '\n' + obj.description - } + for (const obj of results) { + switch (obj.type) { + case 'article': { + forceVertical = true - sendMessage = { - _: 'inputBotInlineMessageText', - message, - entities, - } - } + let sendMessage: tl.TypeInputBotInlineMessage + if (obj.message) { + sendMessage = await BotInlineMessage._convertToTl( + client, + obj.message, + parseMode + ) + } else { + let message = obj.title + const entities: tl.TypeMessageEntity[] = [ + { + _: 'messageEntityBold', + offset: 0, + length: message.length, + }, + ] - return { - _: 'inputBotInlineResult', - id: obj.id, - type: obj.type, - title: obj.title, - description: obj.description, - url: obj.hideUrl ? undefined : obj.url, - content: - obj.url && obj.hideUrl - ? { - _: 'inputWebDocument', - url: obj.url, - mimeType: 'text/html', - size: 0, - attributes: [], - } - : undefined, - thumb: - typeof obj.thumb === 'string' - ? normalizeThumb(obj) - : obj.thumb, - sendMessage, - } - } + if (obj.url) { + entities.push({ + _: 'messageEntityTextUrl', + url: obj.url, + offset: 0, + length: message.length, + }) + } - if (obj.type === 'game') { - let sendMessage: tl.TypeInputBotInlineMessage - if (obj.message) { - sendMessage = await BotInlineMessage._convertToTl( - client, - obj.message, - parseMode - ) - if (sendMessage._ !== 'inputBotInlineMessageGame') { - throw new MtArgumentError( - 'game inline result must contain a game inline message' - ) - } - } else { - sendMessage = { - _: 'inputBotInlineMessageGame', - } - } + if (obj.description) { + message += '\n' + obj.description + } - return { - _: 'inputBotInlineResultGame', - id: obj.id, - shortName: obj.shortName, - sendMessage, - } - } + sendMessage = { + _: 'inputBotInlineMessageText', + message, + entities, + } + } - let sendMessage: tl.TypeInputBotInlineMessage - if (obj.message) { - sendMessage = await BotInlineMessage._convertToTl( - client, - obj.message, - parseMode - ) - } else { - if (obj.type === 'venue') { - if (obj.latitude && obj.longitude) { - sendMessage = { - _: 'inputBotInlineMessageMediaVenue', + items.push({ + _: 'inputBotInlineResult', + id: obj.id, + type: obj.type, title: obj.title, - address: obj.address, + description: obj.description, + url: obj.hideUrl ? undefined : obj.url, + content: + obj.url && obj.hideUrl + ? { + _: 'inputWebDocument', + url: obj.url, + mimeType: 'text/html', + size: 0, + attributes: [], + } + : undefined, + thumb: + typeof obj.thumb === 'string' + ? normalizeThumb(obj) + : obj.thumb, + sendMessage, + }) + continue + } + case 'game': { + let sendMessage: tl.TypeInputBotInlineMessage + if (obj.message) { + sendMessage = await BotInlineMessage._convertToTl( + client, + obj.message, + parseMode + ) + if (sendMessage._ !== 'inputBotInlineMessageGame') { + throw new MtArgumentError( + 'game inline result must contain a game inline message' + ) + } + } else { + sendMessage = { + _: 'inputBotInlineMessageGame', + } + } + + items.push({ + _: 'inputBotInlineResultGame', + id: obj.id, + shortName: obj.shortName, + sendMessage, + }) + continue + } + case 'gif': + case 'photo': + case 'sticker': + isGallery = true + break + case 'audio': + case 'contact': + case 'voice': + forceVertical = true + } + + let sendMessage: tl.TypeInputBotInlineMessage + if (obj.message) { + sendMessage = await BotInlineMessage._convertToTl( + client, + obj.message, + parseMode + ) + } else { + if (obj.type === 'venue') { + if (obj.latitude && obj.longitude) { + sendMessage = { + _: 'inputBotInlineMessageMediaVenue', + title: obj.title, + address: obj.address, + geoPoint: { + _: 'inputGeoPoint', + lat: obj.latitude, + long: obj.longitude, + }, + provider: '', + venueId: '', + venueType: '', + } + } else { + throw new MtArgumentError( + 'message or location (lat&lon) bust be supplied for venue inline result' + ) + } + } else 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, }, - provider: '', - venueId: '', - venueType: '', + } + } else if (obj.type === 'contact') { + sendMessage = { + _: 'inputBotInlineMessageMediaContact', + phoneNumber: obj.phone, + firstName: obj.firstName, + lastName: obj.lastName ?? '', + vcard: '', } } else { - throw new MtArgumentError( - 'message or location (lat&lon) bust be supplied for venue inline result' - ) - } - } else 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: '', + 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 MtArgumentError( - '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 ?? 'video/mp4' - else if (obj.type === 'voice') mime = 'audio/ogg' - else if (obj.type === 'file') { - if (!obj.mime) + 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 MtArgumentError( - 'MIME type must be specified for file inline result' + 'sticker inline result cannot contain a URL' ) - mime = obj.mime - } else mime = 'image/jpeg' + 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 ?? 'video/mp4' + else if (obj.type === 'voice') mime = 'audio/ogg' + else if (obj.type === 'file') { + if (!obj.mime) + throw new MtArgumentError( + 'MIME type must be specified for file inline result' + ) - const attributes: tl.TypeDocumentAttribute[] = [] + mime = obj.mime + } else mime = 'image/jpeg' - if ( - (obj.type === 'video' || - obj.type === 'gif' || - obj.type === 'photo') && - obj.width && - obj.height - ) { - if (obj.type !== 'photo' && obj.duration) { + 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({ - _: 'documentAttributeVideo', - w: obj.width, - h: obj.height, - duration: obj.duration, - }) - } else { - attributes.push({ - _: 'documentAttributeImageSize', - w: obj.width, - h: obj.height, + _: 'documentAttributeAudio', + voice: obj.type === 'voice', + duration: obj.duration ?? 0, + title: obj.type === 'audio' ? obj.title : '', + performer: + obj.type === 'audio' ? obj.performer : '', }) } - } 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 : '', + _: 'documentAttributeFilename', + fileName: extractFileName(obj.media), }) - } - attributes.push({ - _: 'documentAttributeFilename', - fileName: extractFileName(obj.media), - }) - - media = { - _: 'inputWebDocument', - url: obj.media, - mimeType: mime, - size: 0, - attributes, + 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 if (obj.type === 'photo') { - media = fileIdToInputPhoto(obj.media) } else { - media = fileIdToInputDocument(obj.media) + media = obj.media } - } else { - media = obj.media } - } - let title: string | undefined = undefined - let description: string | undefined = undefined + 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 - } + // 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 !== 'voice' && obj.type !== 'sticker') { - description = obj.description - } + 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 !== 'voice' && obj.type !== 'sticker') { + description = obj.description + } - if (!media || media._ === 'inputWebDocument') { - return { - _: 'inputBotInlineResult', + if (!media || media._ === 'inputWebDocument') { + items.push({ + _: 'inputBotInlineResult', + id: obj.id, + type: obj.type, + title, + description, + content: media, + thumb: normalizeThumb(obj, media?.url), + sendMessage, + }) + continue + } + + if (media._ === 'inputPhoto') { + items.push({ + _: 'inputBotInlineResultPhoto', + id: obj.id, + type: obj.type, + photo: media, + sendMessage, + }) + continue + } + + items.push({ + _: 'inputBotInlineResultDocument', id: obj.id, type: obj.type, title, description, - content: media, - thumb: normalizeThumb(obj, media?.url), + document: media, 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, - } + return [isGallery && !forceVertical, items] } }