@@ -5,11 +5,12 @@ import {
55 type ChatType ,
66 type CitationConfig ,
77 type ContextMedia ,
8+ type MediaAttachment ,
89 type MentionAllContext ,
910 type MentionContext ,
1011 type MessageContext ,
1112} from '../context.js'
12- import type { MediaKind } from '../types.js'
13+ import type { MediaKind , SenderInfo } from '../types.js'
1314import { createDownloadFn , createStreamFn , type DownloadLogger } from './_media-download.js'
1415import {
1516 extractMentions ,
@@ -21,6 +22,8 @@ import {
2122
2223export interface DecodeContext {
2324 selfJid : string
25+ selfLid ?: string
26+ selfName ?: string
2427 logger ?: DownloadLogger
2528 channelId ?: string
2629 receiverId ?: string
@@ -444,10 +447,19 @@ const chatTypeOf = (content: WAMessage['message']): ChatType => {
444447 return 'text'
445448}
446449
450+ const sameAuthor = ( a : SenderInfo | undefined , b : SenderInfo ) : boolean => {
451+ if ( a == null ) return false
452+ const av = [ a . pn , a . lid , a . jid ] . filter ( ( v ) : v is string => typeof v === 'string' && v . length > 0 )
453+ const bv = [ b . pn , b . lid , b . jid ] . filter ( ( v ) : v is string => typeof v === 'string' && v . length > 0 )
454+ return av . some ( ( x ) => bv . includes ( x ) )
455+ }
456+
447457const decodeQuotedContext = async (
448458 contextInfo : WAContextInfo | null ,
449459 ctx : DecodeContext ,
450460 parentRemoteJid : string ,
461+ parentSender ?: SenderInfo ,
462+ parentRoomName ?: ( ) => Promise < string | null > ,
451463) : Promise < MessageContext | null > => {
452464 try {
453465 if ( contextInfo == null ) return null
@@ -459,31 +471,44 @@ const decodeQuotedContext = async (
459471 const original = await ctx . resolveQuoted ( stanzaId , parentRemoteJid )
460472 if ( original != null && original . message != null ) {
461473 const originalText = anyText ( original ) ?? ''
462- const fromStore = buildContext ( original , ctx , chatTypeOf ( original . message ) , originalText )
474+ const fromStore = buildContext ( original , ctx , chatTypeOf ( original . message ) , originalText , mediaOf ( original , ctx ) , parentRoomName )
463475 if ( fromStore !== null ) return fromStore
464476 }
465477 }
466478
467479 const quoted = extractQuoted ( contextInfo )
468480 if ( quoted === null ) return null
469481 if ( typeof quoted . key . id !== 'string' || quoted . key . id . length === 0 ) return null
470- const remoteJid = quoted . key . remoteJid
471- if ( typeof remoteJid !== 'string' || remoteJid . length === 0 ) return null
472- const participant = quoted . key . participant
473- if (
474- typeof participant === 'string' &&
475- ctx . selfJid . length > 0 &&
476- jidNormalizedUser ( participant ) === jidNormalizedUser ( ctx . selfJid )
477- ) {
482+
483+ if ( parentRemoteJid . length > 0 ) quoted . key . remoteJid = parentRemoteJid
484+ if ( typeof quoted . key . remoteJid !== 'string' || quoted . key . remoteJid . length === 0 ) return null
485+
486+ const author = quoted . key . participant
487+ const isSelf =
488+ typeof author === 'string' &&
489+ ( ( ctx . selfJid . length > 0 && normalizedEquals ( author , ctx . selfJid ) ) ||
490+ ( ctx . selfLid != null && normalizedEquals ( author , ctx . selfLid ) ) )
491+ const parentIsGroup = isGroupJid ( parentRemoteJid )
492+
493+ let pushName = quoted . sender ?. pushName
494+ if ( isSelf ) {
478495 quoted . key . fromMe = true
496+ if ( ctx . selfJid . length > 0 ) quoted . key . participant = ctx . selfJid
497+ if ( ctx . selfLid != null ) quoted . key . participantAlt = ctx . selfLid
498+ if ( pushName == null ) pushName = ctx . selfName
499+ } else if ( parentSender != null && ( ! parentIsGroup || sameAuthor ( quoted . sender , parentSender ) ) ) {
500+ if ( parentSender . pn != null ) quoted . key . participant = parentSender . pn
501+ if ( parentSender . lid != null ) quoted . key . participantAlt = parentSender . lid
502+ if ( pushName == null ) pushName = parentSender . pushName
479503 }
504+
480505 const qm = contextInfo . quotedMessage as WAMessage [ 'message' ]
481506 const reconstructed = Object . assign (
482507 { key : quoted . key , message : qm ?? null } ,
483- quoted . sender ?. pushName != null ? { pushName : quoted . sender . pushName } : { } ,
508+ pushName != null ? { pushName } : { } ,
484509 ) as WAMessage
485510 const text = anyText ( reconstructed ) ?? ''
486- return buildContext ( reconstructed , ctx , chatTypeOf ( qm ) , text )
511+ return buildContext ( reconstructed , ctx , chatTypeOf ( qm ) , text , mediaOf ( reconstructed , ctx ) , parentRoomName )
487512 } catch {
488513 return null
489514 }
@@ -495,6 +520,7 @@ const buildContext = (
495520 chatType : ChatType ,
496521 text : string ,
497522 media ?: ContextMedia ,
523+ roomNameOverride ?: ( ) => Promise < string | null > ,
498524) : MessageContext | null => {
499525 const key = msg . key
500526 if ( key == null ) return null
@@ -516,16 +542,16 @@ const buildContext = (
516542 const receiverId = ctx . receiverId ?? ''
517543 const prefixes = ctx . prefixes ?? [ ]
518544
519- const resolveRoomName = ( ) : Promise < string | null > =>
520- isGroup && ctx . resolveRoomName != null
521- ? ctx . resolveRoomName ( jid )
522- : Promise . resolve ( null )
545+ const resolveRoomName = roomNameOverride ?? ( ( ) : Promise < string | null > =>
546+ isGroup
547+ ? ( ctx . resolveRoomName != null ? ctx . resolveRoomName ( jid ) : Promise . resolve ( null ) )
548+ : Promise . resolve ( sender . pushName ?? null ) )
523549
524550 const resolveReceiverName : ( ) => Promise < string | null > =
525551 ctx . resolveReceiverName ?? ( ( ) => Promise . resolve ( null ) )
526552
527553 const resolveReplied = ( ) : Promise < MessageContext | null > =>
528- decodeQuotedContext ( contextInfo , ctx , jid )
554+ decodeQuotedContext ( contextInfo , ctx , jid , sender , resolveRoomName )
529555
530556 const replyTarget = jid . length > 0 ? jid : ( sender . pn ?? sender . jid )
531557 const reply = ( content : string , opts ?: TextOptions ) : Promise < WAMessageKey > => {
@@ -573,43 +599,67 @@ const buildContext = (
573599 )
574600}
575601
576- export const decodeText = ( msg : WAMessage , ctx : DecodeContext ) : MessageContext | null => {
577- const content = asRecord ( msg . message )
578- if ( content == null ) return null
579- const inner = unwrap ( content )
580- const body = bodyText ( inner )
581- const media = structuredMedia ( inner ) ?? undefined
582- if ( body === null && media === undefined ) return null
583- return buildContext ( msg , ctx , chatTypeOf ( msg . message ) , body ?? '' , media )
584- }
602+ const MEDIA_KINDS : readonly string [ ] = [ 'image' , 'video' , 'audio' , 'document' , 'sticker' ]
585603
586- const decodeMedia = < K extends MediaKind > (
587- kind : K ,
604+ const buildMediaAttachment = (
588605 msg : WAMessage ,
606+ kind : MediaKind ,
589607 ctx : DecodeContext ,
590- ) : MessageContext | null => {
608+ ) : MediaAttachment | null => {
591609 const node = mediaNodeOf ( msg , kind )
592610 if ( node === null ) return null
593- const caption = typeof node . caption === 'string' ? node . caption : ''
594- const chatType = kind as ChatType
595-
596611 const bufferFn = createDownloadFn ( msg , kind , ctx . logger )
597612 const streamFn = createStreamFn ( msg , kind , ctx . logger )
598- const media : ContextMedia = {
613+ return {
599614 type : kind ,
600615 mimetype : typeof node . mimetype === 'string' ? node . mimetype : null ,
601616 caption : typeof node . caption === 'string' ? node . caption : null ,
602617 fileName : typeof node . fileName === 'string' ? node . fileName : null ,
603618 fileSize : toNum ( node . fileLength ) ,
604619 ptt : node . ptt === true ,
605- buffer : async ( ) => {
606- const result = await bufferFn ( )
607- return result . buffer
608- } ,
620+ buffer : async ( ) => ( await bufferFn ( ) ) . buffer ,
609621 stream : streamFn ,
610622 }
623+ }
624+
625+ const mediaOf = ( msg : WAMessage , ctx : DecodeContext ) : ContextMedia | undefined => {
626+ const content = asRecord ( msg . message )
627+ if ( content == null ) return undefined
628+ const chatType = chatTypeOf ( msg . message )
629+ if ( MEDIA_KINDS . includes ( chatType ) ) {
630+ return buildMediaAttachment ( msg , chatType as MediaKind , ctx ) ?? undefined
631+ }
632+ return structuredMedia ( unwrap ( content ) ) ?? undefined
633+ }
634+
635+ export const decodeMessage = ( msg : WAMessage , ctx : DecodeContext ) : MessageContext | null => {
636+ const content = asRecord ( msg . message )
637+ if ( content == null ) return null
638+ const chatType = chatTypeOf ( msg . message )
639+ const media = mediaOf ( msg , ctx )
640+ const text = anyText ( msg ) ?? ''
641+ if ( text === '' && media === undefined ) return null
642+ return buildContext ( msg , ctx , chatType , text , media )
643+ }
644+
645+ export const decodeText = ( msg : WAMessage , ctx : DecodeContext ) : MessageContext | null => {
646+ const content = asRecord ( msg . message )
647+ if ( content == null ) return null
648+ const inner = unwrap ( content )
649+ const body = bodyText ( inner )
650+ const media = structuredMedia ( inner ) ?? undefined
651+ if ( body === null && media === undefined ) return null
652+ return buildContext ( msg , ctx , chatTypeOf ( msg . message ) , body ?? '' , media )
653+ }
611654
612- return buildContext ( msg , ctx , chatType , caption , media )
655+ const decodeMedia = < K extends MediaKind > (
656+ kind : K ,
657+ msg : WAMessage ,
658+ ctx : DecodeContext ,
659+ ) : MessageContext | null => {
660+ const media = buildMediaAttachment ( msg , kind , ctx )
661+ if ( media === null ) return null
662+ return buildContext ( msg , ctx , kind as ChatType , media . caption ?? '' , media )
613663}
614664
615665export const decodeImage = ( msg : WAMessage , ctx : DecodeContext ) : MessageContext | null =>
@@ -646,7 +696,7 @@ export const decodeMention = (msg: WAMessage, ctx: DecodeContext): MentionContex
646696 const content = asRecord ( msg . message )
647697 if ( content == null ) return null
648698 const text = anyText ( msg ) ?? ''
649- const media = structuredMedia ( unwrap ( content ) ) ?? undefined
699+ const media = mediaOf ( msg , ctx )
650700 const base = buildContext ( msg , ctx , chatTypeOf ( msg . message ) , text , media )
651701 if ( base === null ) return null
652702 return { ...base , mentionedJids, selfJid : ctx . selfJid }
@@ -662,7 +712,7 @@ export const decodeMentionAll = (msg: WAMessage, ctx: DecodeContext): MentionAll
662712 const content = asRecord ( msg . message )
663713 if ( content == null ) return null
664714 const text = anyText ( msg ) ?? ''
665- const media = structuredMedia ( unwrap ( content ) ) ?? undefined
715+ const media = mediaOf ( msg , ctx )
666716 const base = buildContext ( msg , ctx , chatTypeOf ( msg . message ) , text , media )
667717 if ( base === null ) return null
668718 return { ...base , isMentionAll : true , selfJid : ctx . selfJid }
0 commit comments