diff --git a/src/Defaults/index.ts b/src/Defaults/index.ts index 7898c4a6..b05a9c23 100644 --- a/src/Defaults/index.ts +++ b/src/Defaults/index.ts @@ -157,6 +157,15 @@ export const MEDIA_PATH_MAP: { [T in MediaType]?: string } = { 'thumbnail-sticker-pack': '/mms/thumbnail-sticker-pack' } +export const NEWSLETTER_MEDIA_PATH_MAP: { [T in MediaType]?: string } = { + image: '/newsletter/newsletter-image', + video: '/newsletter/newsletter-video', + document: '/newsletter/newsletter-document', + audio: '/newsletter/newsletter-audio', + sticker: '/newsletter/newsletter-image', + 'thumbnail-link': '/newsletter/newsletter-image' +} + export const MEDIA_HKDF_KEY_MAPPING = { audio: 'Audio', document: 'Document', diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts index 2fe9ae8e..8ed7b10f 100644 --- a/src/Socket/messages-send.ts +++ b/src/Socket/messages-send.ts @@ -1051,7 +1051,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { const bytes = encodeNewsletterMessage(patched as proto.IMessage) binaryNodeContent.push({ tag: 'plaintext', - attrs: {}, + attrs: mediaType ? { mediatype: mediaType } : {}, content: bytes }) const stanza: BinaryNode = { diff --git a/src/Types/Message.ts b/src/Types/Message.ts index 12b43aad..1597e349 100644 --- a/src/Types/Message.ts +++ b/src/Types/Message.ts @@ -990,8 +990,16 @@ export type MessageGenerationOptionsFromContent = MiscMessageGenerationOptions & export type WAMediaUploadFunction = ( encFilePath: string, - opts: { fileEncSha256B64: string; mediaType: MediaType; timeoutMs?: number } -) => Promise<{ mediaUrl: string; directPath: string; meta_hmac?: string; ts?: number; fbid?: number }> + opts: { fileEncSha256B64: string; mediaType: MediaType; timeoutMs?: number; newsletter?: boolean } +) => Promise<{ + mediaUrl: string + directPath: string + meta_hmac?: string + ts?: number + fbid?: number + thumbnailDirectPath?: string + thumbnailSha256?: string +}> export type MediaGenerationOptions = { logger?: ILogger diff --git a/src/Utils/messages-media.ts b/src/Utils/messages-media.ts index 5d232796..fc2b24fa 100644 --- a/src/Utils/messages-media.ts +++ b/src/Utils/messages-media.ts @@ -10,7 +10,13 @@ import { join } from 'path' import { Readable, Transform } from 'stream' import { URL } from 'url' import { proto } from '../../WAProto/index.js' -import { DEFAULT_ORIGIN, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP, type MediaType } from '../Defaults' +import { + DEFAULT_ORIGIN, + MEDIA_HKDF_KEY_MAPPING, + MEDIA_PATH_MAP, + type MediaType, + NEWSLETTER_MEDIA_PATH_MAP +} from '../Defaults' import type { BaileysEventMap, DownloadableMessage, @@ -681,6 +687,10 @@ type MediaUploadResult = { meta_hmac?: string ts?: number fbid?: number + thumbnail_info?: { + thumbnail_sha256?: string + thumbnail_direct_path?: string + } } export type UploadParams = { @@ -825,11 +835,21 @@ export const getWAUploadToServer = ( { customUploadHosts, fetchAgent, logger, options }: SocketConfig, refreshMediaConn: (force: boolean) => Promise ): WAMediaUploadFunction => { - return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => { + return async (filePath, { mediaType, fileEncSha256B64, timeoutMs, newsletter }) => { // send a query JSON to obtain the url & auth token to upload our media let uploadInfo = await refreshMediaConn(false) - let urls: { mediaUrl: string; directPath: string; meta_hmac?: string; ts?: number; fbid?: number } | undefined + let urls: + | { + mediaUrl: string + directPath: string + meta_hmac?: string + ts?: number + fbid?: number + thumbnailDirectPath?: string + thumbnailSha256?: string + } + | undefined const hosts = [...customUploadHosts, ...uploadInfo.hosts] fileEncSha256B64 = encodeBase64EncodedStringForUpload(fileEncSha256B64) @@ -851,7 +871,11 @@ export const getWAUploadToServer = ( logger.debug(`uploading to "${hostname}"`) const auth = encodeURIComponent(uploadInfo.auth) - const url = `https://${hostname}${MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}` + const mediaPath = (newsletter ? NEWSLETTER_MEDIA_PATH_MAP[mediaType] : undefined) || MEDIA_PATH_MAP[mediaType] + let url = `https://${hostname}${mediaPath}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}` + if (newsletter) { + url += '&server_thumb_gen=1' + } let result: MediaUploadResult | undefined try { @@ -872,7 +896,9 @@ export const getWAUploadToServer = ( directPath: result.direct_path!, meta_hmac: result.meta_hmac, fbid: result.fbid, - ts: result.ts + ts: result.ts, + thumbnailDirectPath: result.thumbnail_info?.thumbnail_direct_path, + thumbnailSha256: result.thumbnail_info?.thumbnail_sha256 } break } else { diff --git a/src/Utils/messages.ts b/src/Utils/messages.ts index 782682db..8138ef48 100644 --- a/src/Utils/messages.ts +++ b/src/Utils/messages.ts @@ -196,10 +196,11 @@ export const prepareWAMessageMedia = async ( ) const fileSha256B64 = fileSha256.toString('base64') - const { mediaUrl, directPath } = await options.upload(filePath, { + const { directPath, thumbnailDirectPath, thumbnailSha256 } = await options.upload(filePath, { fileEncSha256B64: fileSha256B64, mediaType: mediaType, - timeoutMs: options.mediaUploadTimeoutMs + timeoutMs: options.mediaUploadTimeoutMs, + newsletter: true }) await fs.unlink(filePath) @@ -207,10 +208,12 @@ export const prepareWAMessageMedia = async ( const obj = WAProto.Message.fromObject({ // todo: add more support here [`${mediaType}Message`]: (MessageTypeProto as any)[mediaType].fromObject({ - url: mediaUrl, + // url intentionally omitted — newsletters use directPath only directPath, fileSha256, fileLength, + thumbnailDirectPath, + thumbnailSha256: thumbnailSha256 ? Buffer.from(thumbnailSha256, 'base64') : undefined, ...uploadData, media: undefined })