@@ -405,6 +405,79 @@ class TelegramBot extends EventEmitter {
405
405
} , null ] ;
406
406
}
407
407
408
+
409
+ /**
410
+ * Format multiple files to be uploaded; handles file paths, streams, and buffers
411
+ * @param {String } type
412
+ * @param {Array } files Array of file data objects
413
+ * @param {Object } fileOptions File options
414
+ * @param {String } [fileOptions.filename] File name
415
+ * @param {String } [fileOptions.contentType] Content type (i.e. MIME)
416
+ * @return {Object } formatted
417
+ * @return {Object } formatted.formData Form data object with all files
418
+ * @return {Array } formatted.fileIds Array of fileIds for non-file data
419
+ * @throws Error if Buffer file type is not supported.
420
+ * @see https://npmjs.com/package/file-type
421
+ * @private
422
+ */
423
+ _formatSendMultipleData ( type , files , fileOptions = { } ) {
424
+ const formData = { } ;
425
+ const fileIds = { } ;
426
+
427
+ files . forEach ( ( file , index ) => {
428
+ let filedata = file . media || file . data ;
429
+ let filename = file . filename || fileOptions . filename ;
430
+ let contentType = file . contentType || fileOptions . contentType ;
431
+
432
+ if ( filedata instanceof stream . Stream ) {
433
+ if ( ! filename && filedata . path ) {
434
+ const url = URL . parse ( path . basename ( filedata . path . toString ( ) ) , true ) ;
435
+ if ( url . pathname ) {
436
+ filename = qs . unescape ( url . pathname ) ;
437
+ }
438
+ }
439
+ } else if ( Buffer . isBuffer ( filedata ) ) {
440
+ filename = `filename_${ index } ` ;
441
+
442
+ if ( ! contentType ) {
443
+ const filetype = fileType ( filedata ) ;
444
+
445
+ if ( filetype ) {
446
+ contentType = filetype . mime ;
447
+ const ext = filetype . ext ;
448
+
449
+ if ( ext ) {
450
+ filename = `${ filename } .${ ext } ` ;
451
+ }
452
+ } else {
453
+ throw new errors . FatalError ( 'Unsupported Buffer file-type' ) ;
454
+ }
455
+ }
456
+ } else if ( fs . existsSync ( filedata ) ) {
457
+ filedata = fs . createReadStream ( filedata ) ;
458
+
459
+ if ( ! filename ) {
460
+ filename = path . basename ( filedata . path ) ;
461
+ }
462
+ } else {
463
+ fileIds [ index ] = filedata ;
464
+ return ;
465
+ }
466
+
467
+ filename = filename || `filename_${ index } ` ;
468
+ contentType = contentType || 'application/octet-stream' ;
469
+
470
+ formData [ `${ type } _${ index } ` ] = {
471
+ value : filedata ,
472
+ options : {
473
+ filename,
474
+ contentType,
475
+ } ,
476
+ } ;
477
+ } ) ;
478
+
479
+ return { formData, fileIds } ;
480
+ }
408
481
/**
409
482
* Start polling.
410
483
* Rejects returned promise if a WebHook is being used by this instance.
@@ -1247,6 +1320,48 @@ class TelegramBot extends EventEmitter {
1247
1320
return this . _request ( 'sendVideoNote' , opts ) ;
1248
1321
}
1249
1322
1323
+ /**
1324
+ * Use this method to send paid media.
1325
+ * @param {Number|String } chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
1326
+ * @param {Number } starCount The number of Telegram Stars that must be paid to buy access to the media; 1-10000
1327
+ * @param {String|stream.Stream|Buffer } media A file path or Stream.
1328
+ * @param {Object } [options] Additional Telegram query options
1329
+ * @return {Promise } On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned
1330
+ * @see https://core.telegram.org/bots/api#sendpaidmedia
1331
+ */
1332
+ sendPaidMedia ( chatId , starCount , media , options = { } ) {
1333
+ const opts = {
1334
+ qs : options
1335
+ } ;
1336
+
1337
+ opts . qs . chat_id = chatId ;
1338
+ opts . qs . star_count = starCount ;
1339
+
1340
+ try {
1341
+ const inputPaidMedia = [ ] ;
1342
+ opts . formData = { } ;
1343
+
1344
+ const { formData, fileIds } = this . _formatSendMultipleData ( 'media' , media ) ;
1345
+
1346
+ opts . formData = formData ;
1347
+
1348
+ inputPaidMedia . push ( ...media . map ( ( item , index ) => {
1349
+ if ( fileIds [ index ] ) {
1350
+ item . media = fileIds [ index ] ;
1351
+ } else {
1352
+ item . media = `attach://media_${ index } ` ;
1353
+ }
1354
+ return item ;
1355
+ } ) ) ;
1356
+
1357
+ opts . qs . media = stringify ( inputPaidMedia ) ;
1358
+ } catch ( ex ) {
1359
+ return Promise . reject ( ex ) ;
1360
+ }
1361
+
1362
+ return this . _request ( 'sendPaidMedia' , opts ) ;
1363
+ }
1364
+
1250
1365
/**
1251
1366
* Use this method to send a group of photos or videos as an album.
1252
1367
*
0 commit comments