feat(client): support invoices with extended media
This commit is contained in:
parent
1935413aee
commit
e75ac9fa5d
6 changed files with 170 additions and 17 deletions
|
@ -132,6 +132,9 @@ export async function _normalizeInputMedia(
|
|||
data: JSON.stringify(media.providerData),
|
||||
},
|
||||
startParam: media.startParam,
|
||||
extendedMedia: media.extendedMedia
|
||||
? await this._normalizeInputMedia(media.extendedMedia, params)
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -435,6 +435,11 @@ export interface InputMediaInvoice extends CaptionMixin {
|
|||
* Can be a URL, or a TL object with input web document
|
||||
*/
|
||||
photo?: string | tl.TypeInputWebDocument
|
||||
|
||||
/**
|
||||
* Extended media (i.e. media that will be available once the invoice is paid)
|
||||
*/
|
||||
extendedMedia?: InputMediaLike
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,7 +3,63 @@ import { tl } from '@mtcute/tl'
|
|||
import { TelegramClient } from '../../client'
|
||||
import { makeInspectable } from '../utils'
|
||||
import { WebDocument } from '../files/web-document'
|
||||
import { MtArgumentError } from '../errors'
|
||||
import { MtArgumentError, MtTypeAssertionError } from '../errors'
|
||||
import { _messageMediaFromTl, MessageMedia } from '../messages'
|
||||
import { Thumbnail } from './thumbnail'
|
||||
|
||||
/**
|
||||
* Information about invoice's extended media.
|
||||
* - `none`: there is no extended media in this invoice
|
||||
* - `preview`: there is only a preview of this invoice's media ({@link Invoice.extendedMediaPreview})
|
||||
* - `full`: there is a full version of this invoice's media available ({@link Invoice.extendedMedia})
|
||||
*/
|
||||
export type InvoiceExtendedMediaState = 'none' | 'preview' | 'full'
|
||||
|
||||
export class InvoiceExtendedMediaPreview {
|
||||
constructor(
|
||||
public readonly client: TelegramClient,
|
||||
public readonly raw: tl.RawMessageExtendedMediaPreview
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Width of the preview, in pixels (if available, else 0)
|
||||
*/
|
||||
get width(): number {
|
||||
return this.raw.w ?? 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Height of the preview, in pixels (if available, else 0)
|
||||
*/
|
||||
get height(): number {
|
||||
return this.raw.h ?? 0
|
||||
}
|
||||
|
||||
private _thumbnail?: Thumbnail
|
||||
get thumbnail(): Thumbnail | null {
|
||||
if (!this.raw.thumb) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!this._thumbnail) {
|
||||
this._thumbnail = new Thumbnail(
|
||||
this.client,
|
||||
this.raw,
|
||||
this.raw.thumb
|
||||
)
|
||||
}
|
||||
|
||||
return this._thumbnail
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a video, the duration of the video,
|
||||
* in seconds (if available, else 0)
|
||||
*/
|
||||
get videoDuration(): number {
|
||||
return this.raw.videoDuration ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An invoice
|
||||
|
@ -92,6 +148,58 @@ export class Invoice {
|
|||
return this.raw.startParam
|
||||
}
|
||||
|
||||
/**
|
||||
* If this invoice has extended media
|
||||
*/
|
||||
get extendedMediaState(): InvoiceExtendedMediaState {
|
||||
if (!this.raw.extendedMedia) return 'none'
|
||||
if (this.raw.extendedMedia._ === 'messageExtendedMediaPreview')
|
||||
return 'preview'
|
||||
return 'full'
|
||||
}
|
||||
|
||||
private _extendedMediaPreview?: InvoiceExtendedMediaPreview
|
||||
/**
|
||||
* Get the invoice's extended media preview.
|
||||
* Only available if {@link extendedMediaState} is `preview`.
|
||||
* Otherwise, throws an error.
|
||||
*/
|
||||
get extendedMediaPreview(): InvoiceExtendedMediaPreview {
|
||||
if (this.raw.extendedMedia?._ !== 'messageExtendedMediaPreview')
|
||||
throw new MtArgumentError('No extended media preview available')
|
||||
|
||||
if (!this._extendedMediaPreview) {
|
||||
this._extendedMediaPreview = new InvoiceExtendedMediaPreview(
|
||||
this.client,
|
||||
this.raw.extendedMedia
|
||||
)
|
||||
}
|
||||
|
||||
return this._extendedMediaPreview
|
||||
}
|
||||
|
||||
private _extendedMedia?: MessageMedia
|
||||
/**
|
||||
* Get the invoice's extended media.
|
||||
* Only available if {@link extendedMediaState} is `full`.
|
||||
* Otherwise, throws an error.
|
||||
*/
|
||||
get extendedMedia(): MessageMedia {
|
||||
if (this.raw.extendedMedia?._ !== "messageExtendedMedia") {
|
||||
throw new MtArgumentError('No extended media available')
|
||||
}
|
||||
|
||||
if (!this._extendedMedia) {
|
||||
this._extendedMedia = _messageMediaFromTl(
|
||||
this.client,
|
||||
null,
|
||||
this.raw.extendedMedia.media
|
||||
)
|
||||
}
|
||||
|
||||
return this._extendedMedia
|
||||
}
|
||||
|
||||
/**
|
||||
* Input media TL object generated from this object,
|
||||
* to be used inside {@link InputMediaLike} and
|
||||
|
@ -108,3 +216,4 @@ export class Invoice {
|
|||
}
|
||||
|
||||
makeInspectable(Invoice, undefined, ['inputMedia'])
|
||||
makeInspectable(InvoiceExtendedMediaPreview)
|
||||
|
|
|
@ -54,11 +54,19 @@ export class Thumbnail extends FileLocation {
|
|||
readonly height: number
|
||||
|
||||
private _path?: string
|
||||
private _media: tl.RawPhoto | tl.RawDocument | tl.RawStickerSet
|
||||
private _media:
|
||||
| tl.RawPhoto
|
||||
| tl.RawDocument
|
||||
| tl.RawStickerSet
|
||||
| tl.RawMessageExtendedMediaPreview
|
||||
|
||||
constructor(
|
||||
client: TelegramClient,
|
||||
media: tl.RawPhoto | tl.RawDocument | tl.RawStickerSet,
|
||||
media:
|
||||
| tl.RawPhoto
|
||||
| tl.RawDocument
|
||||
| tl.RawStickerSet
|
||||
| tl.RawMessageExtendedMediaPreview,
|
||||
sz: tl.TypePhotoSize | tl.TypeVideoSize
|
||||
) {
|
||||
switch (sz._) {
|
||||
|
@ -99,6 +107,13 @@ export class Thumbnail extends FileLocation {
|
|||
},
|
||||
thumbVersion: media.thumbVersion!,
|
||||
}
|
||||
} else if (media._ === 'messageExtendedMediaPreview') {
|
||||
// according to tdlib and tdesktop sources, sz can only be photoStrippedSize
|
||||
throw new MtTypeAssertionError(
|
||||
'messageExtendedMediaPreview#thumb',
|
||||
'photoStrippedSize',
|
||||
sz._
|
||||
)
|
||||
} else {
|
||||
location = {
|
||||
_:
|
||||
|
@ -124,7 +139,11 @@ export class Thumbnail extends FileLocation {
|
|||
client,
|
||||
location,
|
||||
size,
|
||||
media._ === 'stickerSet' ? media.thumbDcId : media.dcId
|
||||
media._ === 'stickerSet'
|
||||
? media.thumbDcId
|
||||
: media._ === 'messageExtendedMediaPreview'
|
||||
? 0
|
||||
: media.dcId
|
||||
)
|
||||
this.raw = sz
|
||||
this.width = width
|
||||
|
@ -176,7 +195,8 @@ export class Thumbnail extends FileLocation {
|
|||
if (
|
||||
this.raw._ !== 'photoSize' &&
|
||||
this.raw._ !== 'photoSizeProgressive' &&
|
||||
this.raw._ !== 'videoSize'
|
||||
this.raw._ !== 'videoSize' ||
|
||||
this._media._ === 'messageExtendedMediaPreview' // just for type safety
|
||||
) {
|
||||
throw new MtArgumentError(
|
||||
`Cannot generate a file ID for "${this.raw.type}"`
|
||||
|
@ -238,7 +258,8 @@ export class Thumbnail extends FileLocation {
|
|||
if (
|
||||
this.raw._ !== 'photoSize' &&
|
||||
this.raw._ !== 'photoSizeProgressive' &&
|
||||
this.raw._ !== 'videoSize'
|
||||
this.raw._ !== 'videoSize' ||
|
||||
this._media._ === 'messageExtendedMediaPreview' // just for type safety
|
||||
) {
|
||||
throw new MtArgumentError(
|
||||
`Cannot generate a unique file ID for "${this.raw.type}"`
|
||||
|
|
|
@ -19,6 +19,9 @@ import {
|
|||
} from '../media'
|
||||
import { parseDocument } from '../media/document-utils'
|
||||
import { Message } from './message'
|
||||
import { TelegramClient } from '../../client'
|
||||
import { PeersIndex } from '../peers'
|
||||
import { MtTypeAssertionError } from '../errors'
|
||||
|
||||
/** A media inside of a {@link Message} */
|
||||
export type MessageMedia =
|
||||
|
@ -38,41 +41,53 @@ export type MessageMedia =
|
|||
| Poll
|
||||
| Invoice
|
||||
| null
|
||||
|
||||
// todo: successful_payment, connected_website
|
||||
|
||||
/** @internal */
|
||||
export function _messageMediaFromTl(
|
||||
this: Message,
|
||||
client: TelegramClient,
|
||||
peers: PeersIndex | null,
|
||||
m: tl.TypeMessageMedia
|
||||
): MessageMedia {
|
||||
switch (m._) {
|
||||
case 'messageMediaPhoto':
|
||||
if (!(m.photo?._ === 'photo')) return null
|
||||
return new Photo(this.client, m.photo)
|
||||
return new Photo(client, m.photo)
|
||||
case 'messageMediaDice':
|
||||
return new Dice(m)
|
||||
case 'messageMediaContact':
|
||||
return new Contact(m)
|
||||
case 'messageMediaDocument':
|
||||
if (!(m.document?._ === 'document')) return null
|
||||
return parseDocument(this.client, m.document) as MessageMedia
|
||||
return parseDocument(client, m.document) as MessageMedia
|
||||
case 'messageMediaGeo':
|
||||
if (!(m.geo._ === 'geoPoint')) return null
|
||||
return new Location(this.client, m.geo)
|
||||
return new Location(client, m.geo)
|
||||
case 'messageMediaGeoLive':
|
||||
if (!(m.geo._ === 'geoPoint')) return null
|
||||
return new LiveLocation(this.client, m)
|
||||
return new LiveLocation(client, m)
|
||||
case 'messageMediaGame':
|
||||
return new Game(this.client, m.game)
|
||||
return new Game(client, m.game)
|
||||
case 'messageMediaWebPage':
|
||||
if (!(m.webpage._ === 'webPage')) return null
|
||||
return new WebPage(this.client, m.webpage)
|
||||
return new WebPage(client, m.webpage)
|
||||
case 'messageMediaVenue':
|
||||
return new Venue(this.client, m)
|
||||
return new Venue(client, m)
|
||||
case 'messageMediaPoll':
|
||||
return new Poll(this.client, m.poll, this._peers, m.results)
|
||||
if (!peers) {
|
||||
// should only be possible in extended media
|
||||
// (and afaik polls can't be there)
|
||||
throw new MtTypeAssertionError(
|
||||
"can't create poll without peers index",
|
||||
'PeersIndex',
|
||||
'null'
|
||||
)
|
||||
}
|
||||
|
||||
return new Poll(client, m.poll, peers, m.results)
|
||||
case 'messageMediaInvoice':
|
||||
return new Invoice(this.client, m)
|
||||
return new Invoice(client, m)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -431,7 +431,7 @@ export class Message {
|
|||
) {
|
||||
this._media = null
|
||||
} else {
|
||||
this._media = _messageMediaFromTl.call(this, this.raw.media)
|
||||
this._media = _messageMediaFromTl(this.client, this._peers, this.raw.media)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue