feat(client): support Story message media
This commit is contained in:
parent
893a15d111
commit
8b2debb0aa
9 changed files with 107 additions and 14 deletions
|
@ -30,7 +30,18 @@ export async function _normalizeInputMedia(
|
||||||
|
|
||||||
// thanks to @pacificescape for pointing out messages.uploadMedia method
|
// thanks to @pacificescape for pointing out messages.uploadMedia method
|
||||||
|
|
||||||
if (tl.isAnyInputMedia(media)) return media
|
if (tl.isAnyInputMedia(media)) {
|
||||||
|
// make sure the peers in the media are correctly resolved (i.e. mtcute.* ones are replaced with proper ones)
|
||||||
|
switch (media._) {
|
||||||
|
case 'inputMediaStory':
|
||||||
|
return {
|
||||||
|
...media,
|
||||||
|
peer: await resolvePeer(client, media.peer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return media
|
||||||
|
}
|
||||||
|
|
||||||
if (media.type === 'venue') {
|
if (media.type === 'venue') {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -9,6 +9,7 @@ export * from './location.js'
|
||||||
export * from './photo.js'
|
export * from './photo.js'
|
||||||
export * from './poll.js'
|
export * from './poll.js'
|
||||||
export * from './sticker.js'
|
export * from './sticker.js'
|
||||||
|
export * from './story.js'
|
||||||
export * from './thumbnail.js'
|
export * from './thumbnail.js'
|
||||||
export * from './venue.js'
|
export * from './venue.js'
|
||||||
export * from './video.js'
|
export * from './video.js'
|
||||||
|
|
61
packages/client/src/types/media/story.ts
Normal file
61
packages/client/src/types/media/story.ts
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import { tl } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { parsePeer, Peer } from '../peers/peer.js'
|
||||||
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
import { Story } from '../stories/story.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a "forwarded" story in a message,
|
||||||
|
* internally represented as a message media
|
||||||
|
*/
|
||||||
|
export class MediaStory {
|
||||||
|
readonly type = 'story' as const
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.RawMessageMediaStory,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this story was automatically forwarded to you
|
||||||
|
* because you were mentioned in it
|
||||||
|
*/
|
||||||
|
get isMention(): boolean {
|
||||||
|
return this.raw.viaMention!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peer who has posted this story
|
||||||
|
*/
|
||||||
|
get peer(): Peer {
|
||||||
|
return parsePeer(this.raw.peer, this._peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the story
|
||||||
|
*/
|
||||||
|
get storyId(): number {
|
||||||
|
return this.raw.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contents of the story. May not be available, in which case the story
|
||||||
|
* should be fetched using {@link getStoriesById}
|
||||||
|
*/
|
||||||
|
get story(): Story | null {
|
||||||
|
if (this.raw.story?._ !== 'storyItem') return null
|
||||||
|
|
||||||
|
return new Story(this.raw.story, this._peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
get inputMedia(): tl.TypeInputMedia {
|
||||||
|
return {
|
||||||
|
_: 'inputMediaStory',
|
||||||
|
peer: this.peer.inputPeer,
|
||||||
|
id: this.raw.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(MediaStory, undefined, ['inputMedia'])
|
|
@ -50,7 +50,7 @@ export class WebPage {
|
||||||
* Officially documented are:
|
* Officially documented are:
|
||||||
* `article, photo, audio, video, document, profile, app`,
|
* `article, photo, audio, video, document, profile, app`,
|
||||||
* but also these are encountered:
|
* but also these are encountered:
|
||||||
* `telegram_user, telegram_bot, telegram_channel, telegram_megagroup`:
|
* `telegram_user, telegram_bot, telegram_channel, telegram_megagroup, telegram_story`:
|
||||||
*
|
*
|
||||||
* - `telegram_*` ones seem to be used for `t.me` links.
|
* - `telegram_*` ones seem to be used for `t.me` links.
|
||||||
* - `article` seems to be used for almost all custom pages with `og:*` tags
|
* - `article` seems to be used for almost all custom pages with `og:*` tags
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { LiveLocation, Location } from '../media/location.js'
|
||||||
import { Photo } from '../media/photo.js'
|
import { Photo } from '../media/photo.js'
|
||||||
import { Poll } from '../media/poll.js'
|
import { Poll } from '../media/poll.js'
|
||||||
import { Sticker } from '../media/sticker.js'
|
import { Sticker } from '../media/sticker.js'
|
||||||
|
import { MediaStory } from '../media/story.js'
|
||||||
import { Venue } from '../media/venue.js'
|
import { Venue } from '../media/venue.js'
|
||||||
import { Video } from '../media/video.js'
|
import { Video } from '../media/video.js'
|
||||||
import { Voice } from '../media/voice.js'
|
import { Voice } from '../media/voice.js'
|
||||||
|
@ -34,6 +35,7 @@ export type MessageMedia =
|
||||||
| Venue
|
| Venue
|
||||||
| Poll
|
| Poll
|
||||||
| Invoice
|
| Invoice
|
||||||
|
| MediaStory
|
||||||
| null
|
| null
|
||||||
export type MessageMediaType = Exclude<MessageMedia, null>['type']
|
export type MessageMediaType = Exclude<MessageMedia, null>['type']
|
||||||
|
|
||||||
|
@ -84,6 +86,15 @@ export function _messageMediaFromTl(peers: PeersIndex | null, m: tl.TypeMessageM
|
||||||
|
|
||||||
return new Invoice(m, extended)
|
return new Invoice(m, extended)
|
||||||
}
|
}
|
||||||
|
case 'messageMediaStory': {
|
||||||
|
if (!peers) {
|
||||||
|
// should only be possible in extended media
|
||||||
|
// (and afaik stories can't be there)
|
||||||
|
throw new MtTypeAssertionError("can't create story without peers index", 'PeersIndex', 'null')
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MediaStory(m, peers)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { assertTypeIs } from '@mtcute/core/utils.js'
|
||||||
|
|
||||||
import { makeInspectable } from '../../../utils/index.js'
|
import { makeInspectable } from '../../../utils/index.js'
|
||||||
import { memoizeGetters } from '../../../utils/memoize.js'
|
import { memoizeGetters } from '../../../utils/memoize.js'
|
||||||
import { Location } from '../../media/index.js'
|
import { Location } from '../../media/location.js'
|
||||||
import { StoryInteractiveArea } from './base.js'
|
import { StoryInteractiveArea } from './base.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { assertTypeIs } from '@mtcute/core/utils.js'
|
||||||
|
|
||||||
import { makeInspectable } from '../../../utils/index.js'
|
import { makeInspectable } from '../../../utils/index.js'
|
||||||
import { memoizeGetters } from '../../../utils/memoize.js'
|
import { memoizeGetters } from '../../../utils/memoize.js'
|
||||||
import { Location, VenueSource } from '../../media/index.js'
|
import { Location } from '../../media/location.js'
|
||||||
|
import { VenueSource } from '../../media/venue.js'
|
||||||
import { StoryInteractiveArea } from './base.js'
|
import { StoryInteractiveArea } from './base.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,8 @@ import { tl } from '@mtcute/core'
|
||||||
|
|
||||||
import { makeInspectable } from '../../utils/index.js'
|
import { makeInspectable } from '../../utils/index.js'
|
||||||
import { memoizeGetters } from '../../utils/memoize.js'
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
import { PeersIndex, User } from '../peers/index.js'
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
import { User } from '../peers/user.js'
|
||||||
import { ReactionCount } from '../reactions/reaction-count.js'
|
import { ReactionCount } from '../reactions/reaction-count.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,8 +2,10 @@ import { MtUnsupportedError, tl } from '@mtcute/core'
|
||||||
|
|
||||||
import { makeInspectable } from '../../utils/index.js'
|
import { makeInspectable } from '../../utils/index.js'
|
||||||
import { memoizeGetters } from '../../utils/memoize.js'
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
import { Photo, Video } from '../media/index.js'
|
import { parseDocument } from '../media/document-utils.js'
|
||||||
import { _messageMediaFromTl, MessageEntity } from '../messages/index.js'
|
import { Photo } from '../media/photo.js'
|
||||||
|
import { Video } from '../media/video.js'
|
||||||
|
import { MessageEntity } from '../messages/message-entity.js'
|
||||||
import { PeersIndex } from '../peers/index.js'
|
import { PeersIndex } from '../peers/index.js'
|
||||||
import { ReactionEmoji, toReactionEmoji } from '../reactions/index.js'
|
import { ReactionEmoji, toReactionEmoji } from '../reactions/index.js'
|
||||||
import { _storyInteractiveElementFromTl, StoryInteractiveElement } from './interactive/index.js'
|
import { _storyInteractiveElementFromTl, StoryInteractiveElement } from './interactive/index.js'
|
||||||
|
@ -114,17 +116,22 @@ export class Story {
|
||||||
* Currently, can only be {@link Photo} or {@link Video}.
|
* Currently, can only be {@link Photo} or {@link Video}.
|
||||||
*/
|
*/
|
||||||
get media(): StoryMedia {
|
get media(): StoryMedia {
|
||||||
const media = _messageMediaFromTl(this._peers, this.raw.media)
|
switch (this.raw.media._) {
|
||||||
|
case 'messageMediaPhoto':
|
||||||
|
if (this.raw.media.photo?._ !== 'photo') throw new MtUnsupportedError('Unsupported story media type')
|
||||||
|
|
||||||
switch (media?.type) {
|
return new Photo(this.raw.media.photo, this.raw.media)
|
||||||
case 'photo':
|
case 'messageMediaDocument': {
|
||||||
case 'video':
|
if (this.raw.media.document?._ !== 'document') { throw new MtUnsupportedError('Unsupported story media type') }
|
||||||
return media
|
|
||||||
default:
|
const doc = parseDocument(this.raw.media.document, this.raw.media)
|
||||||
throw new MtUnsupportedError('Unsupported story media type')
|
if (doc.type === 'video') return doc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new MtUnsupportedError('Unsupported story media type')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interactive elements of the story
|
* Interactive elements of the story
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue