feat(client): support file ids in sendMedia, sendPhoto and sendChatPhoto methods

This commit is contained in:
teidesu 2021-04-30 20:51:50 +03:00
parent c0b72018fb
commit 3bb9a61ac7
5 changed files with 112 additions and 38 deletions

View file

@ -1603,12 +1603,15 @@ export interface TelegramClient extends BaseTelegramClient {
* Send a single media. * Send a single media.
* *
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"` * @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
* @param media Media contained in the message * @param media
* Media contained in the message. You can also pass TDLib
* and Bot API compatible File ID, which will be wrapped
* in {@link InputMedia.auto}
* @param params Additional sending parameters * @param params Additional sending parameters
*/ */
sendMedia( sendMedia(
chatId: InputPeerLike, chatId: InputPeerLike,
media: InputMediaLike, media: InputMediaLike | string,
params?: { params?: {
/** /**
* Message to reply to. Either a message object or message ID. * Message to reply to. Either a message object or message ID.

View file

@ -8,6 +8,7 @@ import {
} from '../../types' } from '../../types'
import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils' import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id'
/** /**
* Set a new chat photo or video. * Set a new chat photo or video.
@ -33,27 +34,37 @@ export async function setChatPhoto(
if (!(chat._ === 'inputPeerChat' || chat._ === 'inputPeerChannel')) if (!(chat._ === 'inputPeerChat' || chat._ === 'inputPeerChannel'))
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel') throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
let input: tl.TypeInputFile let photo: tl.TypeInputChatPhoto
if (typeof media === 'string' && media.match(/^https?:\/\//)) { if (tdFileId.isFileIdLike(media)) {
throw new MtCuteArgumentError("Chat photo can't be external") if (typeof media === 'string' && media.match(/^https?:\/\//))
} else if (typeof media === 'object' && tl.isAnyInputMedia(media)) { throw new MtCuteArgumentError("Chat photo can't be external")
throw new MtCuteArgumentError("Chat photo can't be InputMedia")
} else if (isUploadedFile(media)) { const input = fileIdToInputPhoto(media)
input = media.inputFile photo = {
} else if (typeof media === 'object' && tl.isAnyInputFile(media)) { _: 'inputChatPhoto',
input = media id: input
}
} else { } else {
const uploaded = await this.uploadFile({ let inputFile: tl.TypeInputFile
file: media, if (typeof media === 'object' && tl.isAnyInputMedia(media)) {
}) throw new MtCuteArgumentError("Chat photo can't be InputMedia")
input = uploaded.inputFile } else if (isUploadedFile(media)) {
} inputFile = media.inputFile
} else if (typeof media === 'object' && tl.isAnyInputFile(media)) {
inputFile = media
} else {
const uploaded = await this.uploadFile({
file: media,
})
inputFile = uploaded.inputFile
}
const photo: tl.RawInputChatUploadedPhoto = { photo = {
_: 'inputChatUploadedPhoto', _: 'inputChatUploadedPhoto',
[type === 'photo' ? 'file' : 'video']: input, [type === 'photo' ? 'file' : 'video']: inputFile,
videoStartTs: previewSec videoStartTs: previewSec
}
} }
let res let res

View file

@ -12,19 +12,28 @@ import { tl } from '@mtcute/tl'
import { extractFileName } from '../../utils/file-utils' import { extractFileName } from '../../utils/file-utils'
import { normalizeToInputPeer } from '../../utils/peer-utils' import { normalizeToInputPeer } from '../../utils/peer-utils'
import { normalizeDate, randomUlong } from '../../utils/misc-utils' import { normalizeDate, randomUlong } from '../../utils/misc-utils'
import {
fileIdToInputDocument,
fileIdToInputPhoto,
parseFileId,
tdFileId,
} from '@mtcute/file-id'
/** /**
* Send a single media. * Send a single media.
* *
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"` * @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
* @param media Media contained in the message * @param media
* Media contained in the message. You can also pass TDLib
* and Bot API compatible File ID, which will be wrapped
* in {@link InputMedia.auto}
* @param params Additional sending parameters * @param params Additional sending parameters
* @internal * @internal
*/ */
export async function sendMedia( export async function sendMedia(
this: TelegramClient, this: TelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
media: InputMediaLike, media: InputMediaLike | string,
params?: { params?: {
/** /**
* Message to reply to. Either a message object or message ID. * Message to reply to. Either a message object or message ID.
@ -76,6 +85,13 @@ export async function sendMedia(
): Promise<Message> { ): Promise<Message> {
if (!params) params = {} if (!params) params = {}
if (typeof media === 'string') {
media = {
type: 'auto',
file: media
}
}
if (media.type === 'photo') { if (media.type === 'photo') {
return this.sendPhoto(chatId, media.file, { return this.sendPhoto(chatId, media.file, {
caption: media.caption, caption: media.caption,
@ -91,13 +107,38 @@ export async function sendMedia(
let mime = 'application/octet-stream' let mime = 'application/octet-stream'
const input = media.file const input = media.file
if (typeof input === 'object' && tl.isAnyInputMedia(input)) { if (tdFileId.isFileIdLike(input)) {
inputMedia = input if (typeof input === 'string' && input.match(/^https?:\/\//)) {
} else if (typeof input === 'string' && input.match(/^https?:\/\//)) { inputMedia = {
inputMedia = { _: 'inputMediaDocumentExternal',
_: 'inputMediaDocumentExternal', url: input,
url: input, }
} else {
const parsed =
typeof input === 'string' ? parseFileId(input) : input
if (parsed.location._ === 'photo') {
inputMedia = {
_: 'inputMediaPhoto',
id: fileIdToInputPhoto(parsed),
}
} else if (parsed.location._ === 'web') {
inputMedia = {
_:
parsed.type === tdFileId.FileType.Photo
? 'inputMediaPhotoExternal'
: 'inputMediaDocumentExternal',
url: parsed.location.url,
}
} else {
inputMedia = {
_: 'inputMediaDocument',
id: fileIdToInputDocument(parsed),
}
}
} }
} else if (typeof input === 'object' && tl.isAnyInputMedia(input)) {
inputMedia = input
} else if (isUploadedFile(input)) { } else if (isUploadedFile(input)) {
inputFile = input.inputFile inputFile = input.inputFile
mime = input.mime mime = input.mime
@ -120,8 +161,8 @@ export async function sendMedia(
const t = media.thumb const t = media.thumb
if (typeof t === 'object' && tl.isAnyInputMedia(t)) { if (typeof t === 'object' && tl.isAnyInputMedia(t)) {
throw new MtCuteArgumentError("Thumbnail can't be InputMedia") throw new MtCuteArgumentError("Thumbnail can't be InputMedia")
} else if (typeof t === 'string' && t.match(/^https?:\/\//)) { } else if (tdFileId.isFileIdLike(t)) {
throw new MtCuteArgumentError("Thumbnail can't be external") throw new MtCuteArgumentError("Thumbnail can't be a URL or a File ID")
} else if (isUploadedFile(t)) { } else if (isUploadedFile(t)) {
thumb = t.inputFile thumb = t.inputFile
} else if (typeof t === 'object' && tl.isAnyInputFile(t)) { } else if (typeof t === 'object' && tl.isAnyInputFile(t)) {

View file

@ -10,6 +10,7 @@ import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { normalizeToInputPeer } from '../../utils/peer-utils' import { normalizeToInputPeer } from '../../utils/peer-utils'
import { normalizeDate, randomUlong } from '../../utils/misc-utils' import { normalizeDate, randomUlong } from '../../utils/misc-utils'
import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id'
/** /**
* Send a single photo * Send a single photo
@ -94,14 +95,23 @@ export async function sendPhoto(
if (!params) params = {} if (!params) params = {}
let media: tl.TypeInputMedia let media: tl.TypeInputMedia
if (typeof photo === 'object' && tl.isAnyInputMedia(photo)) {
media = photo if (tdFileId.isFileIdLike(photo)) {
} else if (typeof photo === 'string' && photo.match(/^https?:\/\//)) { if (typeof photo === 'string' && photo.match(/^https?:\/\//)) {
media = { media = {
_: 'inputMediaPhotoExternal', _: 'inputMediaPhotoExternal',
url: photo, url: photo,
ttlSeconds: params.ttlSeconds, ttlSeconds: params.ttlSeconds,
}
} else {
const input = fileIdToInputPhoto(photo)
media = {
_: 'inputMediaPhoto',
id: input
}
} }
} else if (typeof photo === 'object' && tl.isAnyInputMedia(photo)) {
media = photo
} else if (isUploadedFile(photo)) { } else if (isUploadedFile(photo)) {
media = { media = {
_: 'inputMediaUploadedPhoto', _: 'inputMediaUploadedPhoto',

View file

@ -35,7 +35,7 @@ export namespace tdFileId {
* Provided File ID cannot be converted to that TL object. * Provided File ID cannot be converted to that TL object.
*/ */
export class ConversionError extends FileIdError { export class ConversionError extends FileIdError {
constructor (to: string) { constructor(to: string) {
super(`Cannot convert given File ID to ${to}`) super(`Cannot convert given File ID to ${to}`)
} }
} }
@ -190,4 +190,13 @@ export namespace tdFileId {
*/ */
readonly location: TypeRemoteFileLocation readonly location: TypeRemoteFileLocation
} }
export function isFileIdLike(
obj: any
): obj is string | RawFullRemoteFileLocation {
return (
typeof obj === 'string' ||
(typeof obj === 'object' && obj._ === 'remoteFileLocation')
)
}
} }