From cd774bef178155d3b056263b027bf4a802d75477 Mon Sep 17 00:00:00 2001 From: Wictor Nogueira <57378387+wictornogueira@users.noreply.github.com> Date: Sat, 31 Jul 2021 10:36:11 -0300 Subject: [PATCH] feat: Add MessageMedia.fromUrl method (#769) --- index.d.ts | 10 +++++++ package.json | 1 + src/structures/MessageMedia.js | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/index.d.ts b/index.d.ts index a30fc76..b38135d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,5 +1,6 @@ import { EventEmitter } from 'events' +import { RequestInit } from 'node-fetch' import puppeteer = require('puppeteer') declare namespace WAWebJS { @@ -664,6 +665,12 @@ declare namespace WAWebJS { stickerCategories?: string[] } + export interface MediaFromURLOptions { + client?: Client + unsafeMime?: boolean + reqOptions?: RequestInit + } + /** Media attached to a message */ export class MessageMedia { /** MIME type of the attachment */ @@ -682,6 +689,9 @@ declare namespace WAWebJS { /** Creates a MessageMedia instance from a local file path */ static fromFilePath: (filePath: string) => MessageMedia + + /** Creates a MessageMedia instance from a URL */ + static fromUrl: (url: string, options?: MediaFromURLOptions) => Promise } export type MessageContent = string | MessageMedia | Location | Contact | Contact[] diff --git a/package.json b/package.json index f9df280..9b6eb1d 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "sharp": "^0.28.3" }, "devDependencies": { + "@types/node-fetch": "^2.5.11", "chai": "^4.3.4", "dotenv": "^10.0.0", "eslint": "^7.27.0", diff --git a/src/structures/MessageMedia.js b/src/structures/MessageMedia.js index 3d9a25b..4174b06 100644 --- a/src/structures/MessageMedia.js +++ b/src/structures/MessageMedia.js @@ -3,6 +3,8 @@ const fs = require('fs'); const path = require('path'); const mime = require('mime'); +const fetch = require('node-fetch'); +const { URL } = require('url'); /** * Media attached to a message @@ -43,6 +45,56 @@ class MessageMedia { return new MessageMedia(mimetype, b64data, filename); } + + /** + * Creates a MessageMedia instance from a URL + * @param {string} url + * @param {Object} [options] + * @param {number} [options.unsafeMime=false] + * @param {object} [options.client] + * @param {object} [options.reqOptions] + * @param {number} [options.reqOptions.size=0] + * @returns {Promise} + */ + static async fromUrl(url, options = {}) { + let mimetype; + + if (!options.unsafeMime) { + const pUrl = new URL(url); + mimetype = mime.getType(pUrl.pathname); + + if (!mimetype) + throw new Error('Unable to determine MIME type'); + } + + async function fetchData (url, options) { + const reqOptions = Object.assign({ headers: { accept: 'image/* video/* text/* audio/*' } }, options); + const response = await fetch(url, reqOptions); + const mime = response.headers.get('Content-Type'); + let data = ''; + + if (response.buffer) { + data = (await response.buffer()).toString('base64'); + } else { + const bArray = new Uint8Array(await response.arrayBuffer()); + bArray.forEach((b) => { + data += String.fromCharCode(b); + }); + data = btoa(data); + } + + return { data, mime }; + } + + const res = options.client + ? (await options.client.pupPage.evaluate(fetchData, url, options.reqOptions)) + : (await fetchData(url, options.reqOptions)); + + if (!mimetype) + mimetype = res.mime; + + return new MessageMedia(mimetype, res.data, null); + } } module.exports = MessageMedia; \ No newline at end of file