const fs = require('fs'); const nurl = require('url'); const path = require('path'); const stream = require('stream'); const request = require('request'); const ANSWER_METHODS = { addArticle: 'article', addPhoto: 'photo', addVideo: 'video', addGif: 'gif', addVideoGif: 'mpeg4_gif', addSticker: 'sticker', addVoice: 'voice', addDocument: 'document', addLocation: 'location', addVenue: 'venue', addGame: 'game', cachedPhoto: 'photo', cachedGif: 'gif', cachedVideoGif: 'mpeg4_gif', cachedSticker: 'sticker', cachedDocument: 'document', cachedVideo: 'video', cachedVoice: 'voice', cachedAudio: 'audio' }; const DEFAULT_FILE_EXTENSIONS = { photo: 'jpg', audio: 'mp3', document: 'doc', sticker: 'webp', voice: 'm4a', video: 'mp4' }; const REGEXP_URL = /^https?:\/\/|www\./; // Methods const methods = { keyboard(keyboard, opt = {}) { const markup = keyboard !== undefined ? {keyboard} : {}; if (opt.resize === true) markup['resize_keyboard'] = true; if (opt.once === true) markup['one_time_keyboard'] = true; if (opt.remove === true) markup['remove_keyboard'] = true; if (opt.selective) markup['selective'] = opt.selective; return markup; }, button(type, text) { if (!text && type) return {text: type}; type = `request_${type}`; return {text, [type]: true}; }, inlineKeyboard(inline_keyboard) { return {inline_keyboard}; }, inlineQueryKeyboard(inline_keyboard) { return {inline_keyboard: inline_keyboard}; }, inlineButton(text, opt = {}) { const markup = {text}; if (opt.url) markup.url = opt.url; if (opt.inline !== undefined) markup.switch_inline_query = opt.inline; if (opt.inlineCurrent !== undefined) markup.switch_inline_query_current_chat = opt.inlineCurrent; if (opt.callback) markup.callback_data = String(opt.callback); if (opt.game) markup.callback_game = String(opt.game); if (opt.pay === true) markup.pay = opt.pay; return markup; }, answerList(id, opt) { return new AnswerList(id, opt); }, getMe: {}, sendMessage: { arguments: ['chat_id', 'text'] }, forwardMessage: { arguments: ['chat_id', 'from_chat_id', 'message_id'] }, sendPhoto(chat_id, photo, opt) { return sendFile.call(this, 'photo', photo, opt, {chat_id}); }, sendAudio(chat_id, audio, opt = {}) { const form = {chat_id}; if (opt.title) form.title = opt.title; if (opt.performer) form.performer = opt.performer; if (Number.isInteger(opt.duration)) form.duration = opt.duration; return sendFile.call(this, 'audio', audio, opt, form); }, sendDocument(chat_id, doc, opt) { return sendFile.call(this, 'document', doc, opt, {chat_id}); }, sendAnimation(chat_id, animation, opt) { return sendFile.call(this, 'animation', animation, opt, {chat_id}); }, sendSticker(chat_id, sticker, opt) { return sendFile.call(this, 'sticker', sticker, opt, {chat_id}); }, sendVideo(chat_id, video, opt = {}) { const form = {chat_id}; if (Number.isInteger(opt.duration)) form.duration = opt.duration; if (Number.isInteger(opt.width)) form.width = opt.width; if (Number.isInteger(opt.height)) form.height = opt.height; if (opt.supportsStreaming) { form.supports_streaming = true; } return sendFile.call(this, 'video', video, opt, form); }, sendVideoNote: { arguments: ['chat_id', 'video_note'], options(form, opt = {}) { if (Number.isInteger(opt.duration)) form.duration = opt.duration; if (Number.isInteger(opt.length)) form.length = opt.length; return form; } }, sendVoice(chat_id, voice, opt = {}) { const form = {chat_id}; if (Number.isInteger(opt.duration)) form.duration = opt.duration; return sendFile.call(this, 'voice', voice, opt, form); }, sendLocation: { arguments(chat_id, position) { return { chat_id, latitude: position[0], longitude: position[1] }; }, options(form, opt = {}) { if (Number.isInteger(opt.livePeriod)) form.live_period = opt.livePeriod; return form; } }, editMessageLiveLocation: { arguments(opt = {}) { const form = {}; if (opt.latitude) form.latitude = opt.latitude; if (opt.longitude) form.longitude = opt.longitude; if (opt.chatId) form.chat_id = opt.chatId; if (opt.messageId) form.message_id = opt.messageId; if (opt.inlineMessageId) form.inline_message_id = opt.inlineMessageId; return form; } }, stopMessageLiveLocation: { arguments(opt = {}) { const form = {}; if (opt.chatId) form.chat_id = opt.chatId; if (opt.messageId) form.message_id = opt.messageId; if (opt.inlineMessageId) form.inline_message_id = opt.inlineMessageId; return form; } }, editMessageMedia: { arguments(media, opt = {}) { const form = {}; if (opt.chatId) form.chat_id = opt.chatId; if (opt.messageId) form.message_id = opt.messageId; if (opt.inlineMessageId) form.inline_message_id = opt.inlineMessageId; form.media = JSON.stringify(media); return form; } }, sendVenue: { arguments(chat_id, position, title, address) { return { chat_id, latitude: position[0], longitude: position[1], title, address }; }, options(form, opt = {}) { if (opt.foursquareId) form.foursquare_id = opt.foursquareId; if (opt.foursquareType) form.foursquare_type = opt.foursquareType; return form; } }, sendContact: { arguments: ['chat_id', 'phone_number', 'first_name', 'last_name'] }, sendChatAction: { short: 'sendAction', arguments: ['chat_id', 'action'] }, getUserProfilePhotos: { short: 'getUserPhoto', arguments: 'user_id', options(form, opt = {}) { if (opt.offset) form.offset = opt.offset; if (opt.limit) form.limit = opt.limit; return form; } }, getFile(file_id) { return this.request(`/getFile`, {file_id}).then(file => { const result = file.result; result.fileLink = this.fileLink + result.file_path; return result; }); }, sendGame: { arguments: ['chat_id', 'game_short_name'] }, setGameScore: { arguments: ['user_id', 'score'], options(form, opt = {}) { if (opt.force) form.force = opt.force; if (opt.chatId) form.chat_id = opt.chatId; if (opt.messageId) form.message_id = opt.messageId; if (opt.inlineMessageId) form.inline_message_id = opt.inlineMessageId; if (opt.disableEditMessage) form.disable_edit_message = opt.disableEditMessage; return form; } }, getGameHighScores: { arguments: ['user_id'], options(form, opt = {}) { if (opt.chatId) form.chat_id = opt.chatId; if (opt.messageId) form.message_id = opt.messageId; if (opt.inlineMessageId) form.inline_message_id = opt.inlineMessageId; return form; } }, sendInvoice: { arguments: ['chat_id'], options(form, opt = {}) { const photo = opt.photo || {}; const need = opt.need || {}; form.title = opt.title; form.description = opt.description; form.payload = opt.payload; form.provider_token = opt.providerToken; form.start_parameter = opt.startParameter; form.currency = opt.currency; form.send_phone_number_to_provider = opt.sendPhoneNumberToProvider; form.send_email_to_provider = opt.sendEmailToProvider; form.prices = JSON.stringify(opt.prices); form.provider_data = JSON.stringify(opt.providerData); if (photo.url) form.photo_url = photo.url; if (Number.isInteger(photo.size)) form.photo_size = photo.size; if (Number.isInteger(photo.width)) form.photo_width = photo.width; if (Number.isInteger(photo.height)) form.photo_height = photo.height; if (need.name === true) form.need_name = need.name; if (need.phoneNumber === true) form.need_phone_number = need.phoneNumber; if (need.email === true) form.need_email = need.email; if (need.shippingAddress === true) form.need_shipping_address = need.shippingAddress; if (opt.isFlexible === true) form.is_flexible = opt.isFlexible; return form; } }, sendMediaGroup: { arguments(chat_id, mediaList) { return { chat_id, media: JSON.stringify(mediaList) }; } }, getStickerSet: { arguments: ['name'] }, uploadStickerFile(user_id, sticker, opt) { return sendFile.call(this, 'png_sticker', sticker, opt, {user_id}, 'uploadStickerFile'); }, createNewStickerSet(user_id, name, title, sticker, emojis, opt = {}) { const form = {user_id, name, title, emojis}; if (opt.containsMasks) form.contains_masks = opt.containsMasks; if (opt.maskPosition) form.mask_position = opt.maskPosition; return sendFile.call(this, 'png_sticker', sticker, opt, form, 'createNewStickerSet'); }, setChatStickerSet: { arguments: ['chat_id', 'sticker_set_name'] }, deleteChatStickerSet: { arguments: ['chat_id'] }, addStickerToSet(user_id, name, sticker, emojis, opt = {}) { const form = {user_id, name, emojis}; if (opt.maskPosition) form.mask_position = opt.maskPosition; return sendFile.call(this, 'png_sticker', sticker, opt, form, 'addStickerToSet'); }, setStickerPositionInSet: { arguments: ['sticker', 'position'] }, deleteStickerFromSet: { arguments: ['sticker'] }, getChat: { arguments: ['chat_id'] }, leaveChat: { arguments: ['chat_id'] }, getChatAdministrators: { short: 'getAdmins', arguments: ['chat_id'] }, getChatMember: { short: 'getMember', arguments: ['chat_id', 'user_id'] }, getChatMembersCount: { short: 'countMembers', arguments: ['chat_id'] }, kickChatMember: { short: 'kick', arguments: ['chat_id', 'user_id'], options(form, opt) { if (opt.untilDate) form.until_date = opt.untilDate; return form; } }, unbanChatMember: { short: 'unban', arguments: ['chat_id', 'user_id'] }, restrictChatMember: { arguments: ['chat_id', 'user_id'], options(form, opt) { if (opt.untilDate) form.until_date = opt.untilDate; if (opt.canSendMessages) form.can_send_messages = opt.canSendMessages; if (opt.canSendMediaMessages) form.can_send_media_messages = opt.canSendMediaMessages; if (opt.canSendOtherMessages) form.can_send_other_messages = opt.canSendOtherMessages; if (opt.canAddWebPagePreviews) form.can_add_web_page_previews = opt.canAddWebPagePreviews; return form; } }, promoteChatMember: { arguments: ['chat_id', 'user_id'], options(form, opt) { if (opt.canChangeInfo) form.can_change_info = opt.canChangeInfo; if (opt.canPostMessages) form.can_post_messages = opt.canPostMessages; if (opt.canEditMessages) form.can_edit_messages = opt.canEditMessages; if (opt.canDeleteMessages) form.can_delete_messages = opt.canDeleteMessages; if (opt.canInviteUsers) form.can_invite_users = opt.canInviteUsers; if (opt.canRestrictMembers) form.can_restrict_members = opt.canRestrictMembers; if (opt.canPinMessages) form.can_pin_messages = opt.canPinMessages; if (opt.canPromoteMembers) form.can_promote_members = opt.canPromoteMembers; return form; } }, exportChatInviteLink: { arguments: ['chat_id'] }, setChatPhoto(chat_id, photo, opt) { return sendFile.call(this, 'photo', photo, opt, {chat_id}, 'setChatPhoto'); }, deleteChatPhoto: { arguments: ['chat_id'] }, setChatTitle: { arguments: ['chat_id', 'title'] }, setChatDescription: { arguments: ['chat_id', 'description'] }, pinChatMessage: { arguments: ['chat_id', 'message_id'] }, unpinChatMessage: { arguments: ['chat_id'] }, answerInlineQuery: { short: 'answerQuery', arguments(answers) { const data = { inline_query_id: answers.id, results: answers.results(), next_offset: answers.nextOffset, is_personal: answers.personal, cache_time: answers.cacheTime }; if (answers.pmText !== undefined) data.switch_pm_text = answers.pmText; if (answers.pmParameter !== undefined) data.switch_pm_parameter = answers.pmParameter; return data; } }, answerCallbackQuery: { short: 'answerCallback', arguments: ['callback_query_id'], options(form, opt) { if (opt.text) form.text = opt.text; if (opt.url) form.url = opt.url; if (opt.showAlert) form.show_alert = opt.showAlert; if (opt.cacheTime) form.cache_time = opt.cacheTime; return form; } }, answerShippingQuery: { arguments: ['shipping_query_id', 'ok'], options(form, opt) { if (opt.shippingOptions) form.shipping_options = opt.shippingOptions; if (opt.errorMessage) form.error_message = opt.errorMessage; return form; } }, answerPreCheckoutQuery: { arguments: ['pre_checkout_query_id', 'ok'], options(form, opt) { if (opt.errorMessage) form.error_message = opt.errorMessage; return form; } }, deleteMessage: { arguments: ['chat_id', 'message_id'] }, editMessageText: { short: 'editText', arguments: (obj, text) => editObject(obj, {text}) }, editMessageCaption: { short: 'editCaption', arguments: (obj, caption) => editObject(obj, {caption}) }, editMessageReplyMarkup: { short: 'editMarkup', arguments: (obj, reply_markup) => editObject(obj, {reply_markup}) }, setWebhook(url, certificate, allowedUpdates, maxConnections) { const form = {url}; if (Array.isArray(allowedUpdates)) { form.allowed_updates = allowedUpdates; } if (Number.isInteger(maxConnections)) { form.max_connections = maxConnections; } if (certificate) { form.certificate = { value: fs.readFileSync(certificate), options: { filename: 'cert.pem' } }; return this.request('/setWebhook', null, form); } return this.request('/setWebhook', form); }, getWebhookInfo: {}, deleteWebhook: {}, sendDice: { arguments: ['chat_id', 'emoji'] } }; // Functions function editObject(obj, form) { if (obj.chatId && obj.messageId) { form.chat_id = obj.chatId; form.message_id = obj.messageId; } else if (obj.inlineMsgId) { form.inline_message_id = obj.inlineMsgId; } return form; } function sendFile(type, file, opt = {}, methodForm = {}, methodUrl) { const form = this.properties(methodForm, opt); const defaultName = `file.${DEFAULT_FILE_EXTENSIONS[type]}`; const url = methodUrl ? methodUrl : 'send' + type.charAt(0).toUpperCase() + type.slice(1); // Send bot action event this.event(url, [].slice.call(arguments).splice(0, 1)); // Set file caption if (opt.caption) form.caption = opt.caption; if (file instanceof stream.Stream) { // File stream object if (!opt.fileName) { opt.fileName = nurl.parse(path.basename(file.path)).pathname; } form[type] = { value: file, options: {filename: opt.fileName} }; } else if (Buffer.isBuffer(file)) { // File buffer if (!opt.fileName) opt.fileName = defaultName; form[type] = { value: file, options: {filename: opt.fileName} }; } else if (REGEXP_URL.test(file)) { // File url if (!opt.fileName) { opt.fileName = path.basename(nurl.parse(file).pathname) || defaultName; } if (opt.serverDownload === true) { // Download by our server form[type] = { value: request.get(file), options: {filename: opt.fileName} }; } else { // Download by Telegram server form[type] = file; } } else if (fs.existsSync(file)) { // File location if (!opt.fileName) opt.fileName = path.basename(file); form[type] = { value: fs.createReadStream(file), options: {filename: opt.fileName} }; } else { // File as 'file_id' form[type] = file; } return this.request(`/${url}`, null, form).then((response) => response.result); } /* Answer List */ class AnswerList { constructor(id, opt = {}) { this.id = id; this.cacheTime = Number(opt.cacheTime) || 300; this.nextOffset = opt.nextOffset === undefined ? null : opt.nextOffset; this.personal = opt.personal === undefined ? false : opt.personal; this.pmText = opt.pmText; this.pmParameter = opt.pmParameter; this.list = []; } add(type, set = {}) { set.type = type; this.list.push(set); return set; } results() { return JSON.stringify(this.list); } } // Add answer methods { for (let prop in ANSWER_METHODS) { AnswerList.prototype[prop] = (name => { return function (set) { return this.add(name, set); }; })(ANSWER_METHODS[prop]); } } // Export methods module.exports = methods;