From 6e2881b31b53f701954a809e0193e1ca4d6e9701 Mon Sep 17 00:00:00 2001 From: Leandro Toledo Date: Mon, 17 Aug 2015 11:34:42 -0300 Subject: [PATCH] Adding support for Voice object and sendVoice method #39 --- telegram/__init__.py | 4 ++- telegram/audio.py | 10 ++++++ telegram/bot.py | 73 ++++++++++++++++++++++++++++++++++++++++-- telegram/inputfile.py | 5 ++- telegram/message.py | 11 +++++++ telegram/voice.py | 49 ++++++++++++++++++++++++++++ tests/telegram.mp3 | Bin 0 -> 28232 bytes tests/test_bot.py | 48 +++++++++++++++++++-------- 8 files changed, 182 insertions(+), 18 deletions(-) create mode 100644 telegram/voice.py create mode 100644 tests/telegram.mp3 diff --git a/telegram/__init__.py b/telegram/__init__.py index 899b63183..f6b7c7be6 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -27,6 +27,7 @@ from .update import Update from .groupchat import GroupChat from .photosize import PhotoSize from .audio import Audio +from .voice import Voice from .document import Document from .sticker import Sticker from .video import Video @@ -48,4 +49,5 @@ __all__ = ['Bot', 'Emoji', 'TelegramError', 'InputFile', 'ReplyMarkup', 'ForceReply', 'ReplyKeyboardHide', 'ReplyKeyboardMarkup', 'UserProfilePhotos', 'ChatAction', 'Location', 'Contact', 'Video', 'Sticker', 'Document', 'Audio', 'PhotoSize', 'GroupChat', - 'Update', 'Message', 'User', 'TelegramObject', 'NullHandler'] + 'Update', 'Message', 'User', 'TelegramObject', 'NullHandler', + 'Voice'] diff --git a/telegram/audio.py b/telegram/audio.py index 53b527626..5fff1d2e7 100644 --- a/telegram/audio.py +++ b/telegram/audio.py @@ -24,10 +24,14 @@ class Audio(TelegramObject): def __init__(self, file_id, duration, + performer=None, + title=None, mime_type=None, file_size=None): self.file_id = file_id self.duration = duration + self.performer = performer + self.title = title self.mime_type = mime_type self.file_size = file_size @@ -35,12 +39,18 @@ class Audio(TelegramObject): def de_json(data): return Audio(file_id=data.get('file_id', None), duration=data.get('duration', None), + performer=data.get('performer', None), + title=data.get('title', None), mime_type=data.get('mime_type', None), file_size=data.get('file_size', None)) def to_dict(self): data = {'file_id': self.file_id, 'duration': self.duration} + if self.performer: + data['performer'] = self.performer + if self.title: + data['title'] = self.title if self.mime_type: data['mime_type'] = self.mime_type if self.file_size: diff --git a/telegram/bot.py b/telegram/bot.py index 4d5b86d3b..a1335c1c0 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -262,12 +262,21 @@ class Bot(TelegramObject): def sendAudio(self, chat_id, audio, + duration=None, + performer=None, + title=None, reply_to_message_id=None, reply_markup=None): """Use this method to send audio files, if you want Telegram clients to - display the file as a playable voice message. For this to work, your - audio must be in an .ogg file encoded with OPUS (other formats may be - sent as telegram.Document). + display them in the music player. Your audio must be in an .mp3 format. + On success, the sent Message is returned. Bots can currently send audio + files of up to 50 MB in size, this limit may be changed in the future. + + For backward compatibility, when both fields title and description are + empty and mime-type of the sent file is not "audio/mpeg", file is sent + as playable voice message. In this case, your audio must be in an .ogg + file encoded with OPUS. This will be removed in the future. You need to + use sendVoice method instead. Args: chat_id: @@ -276,6 +285,12 @@ class Bot(TelegramObject): Audio file to send. You can either pass a file_id as String to resend an audio that is already on the Telegram servers, or upload a new audio file using multipart/form-data. + duration: + Duration of sent audio in seconds. [Optional] + performer: + Performer of sent audio. [Optional] + title: + Title of sent audio. [Optional] reply_to_message_id: If the message is a reply, ID of the original message. [Optional] reply_markup: @@ -292,6 +307,13 @@ class Bot(TelegramObject): data = {'chat_id': chat_id, 'audio': audio} + if duration: + data['duration'] = duration + if performer: + data['performer'] = performer + if title: + data['title'] = title + return url, data @log @@ -409,6 +431,51 @@ class Bot(TelegramObject): return url, data + @log + @message + def sendVoice(self, + chat_id, + voice, + duration=None, + reply_to_message_id=None, + reply_markup=None): + """Use this method to send audio files, if you want Telegram clients to + display the file as a playable voice message. For this to work, your + audio must be in an .ogg file encoded with OPUS (other formats may be + sent as Audio or Document). On success, the sent Message is returned. + Bots can currently send audio files of up to 50 MB in size, this limit + may be changed in the future. + + Args: + chat_id: + Unique identifier for the message recipient - User or GroupChat id. + voice: + Audio file to send. You can either pass a file_id as String to + resend an audio that is already on the Telegram servers, or upload + a new audio file using multipart/form-data. + duration: + Duration of sent audio in seconds. [Optional] + reply_to_message_id: + If the message is a reply, ID of the original message. [Optional] + reply_markup: + Additional interface options. A JSON-serialized object for a + custom reply keyboard, instructions to hide keyboard or to force a + reply from the user. [Optional] + + Returns: + A telegram.Message instance representing the message posted. + """ + + url = '%s/sendVoice' % self.base_url + + data = {'chat_id': chat_id, + 'voice': voice} + + if duration: + data['duration'] = duration + + return url, data + @log @message def sendLocation(self, diff --git a/telegram/inputfile.py b/telegram/inputfile.py index 7fee1d882..acf1119ac 100644 --- a/telegram/inputfile.py +++ b/telegram/inputfile.py @@ -54,6 +54,9 @@ class InputFile(object): if 'video' in data: self.input_name = 'video' self.input_file = data.pop('video') + if 'voice' in data: + self.input_name = 'voice' + self.input_file = data.pop('voice') if isinstance(self.input_file, file): self.input_file_content = self.input_file.read() @@ -145,7 +148,7 @@ class InputFile(object): bool """ if data: - file_types = ['audio', 'document', 'photo', 'video'] + file_types = ['audio', 'document', 'photo', 'video', 'voice'] file_type = [i for i in list(data.keys()) if i in file_types] if file_type: diff --git a/telegram/message.py b/telegram/message.py index adb27b5e1..fb8e480ae 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -37,6 +37,7 @@ class Message(TelegramObject): photo=None, sticker=None, video=None, + voice=None, caption=None, contact=None, location=None, @@ -59,6 +60,7 @@ class Message(TelegramObject): self.photo = photo self.sticker = sticker self.video = video + self.voice = voice self.caption = caption self.contact = contact self.location = location @@ -142,6 +144,12 @@ class Message(TelegramObject): else: video = None + if 'voice' in data: + from telegram import Voice + voice = Voice.de_json(data['voice']) + else: + voice = None + if 'contact' in data: from telegram import Contact contact = Contact.de_json(data['contact']) @@ -179,6 +187,7 @@ class Message(TelegramObject): photo=photo, sticker=sticker, video=video, + voice=voice, caption=data.get('caption', ''), contact=contact, location=location, @@ -222,6 +231,8 @@ class Message(TelegramObject): data['sticker'] = self.sticker.to_dict() if self.video: data['video'] = self.video.to_dict() + if self.voice: + data['voice'] = self.voice.to_dict() if self.caption: data['caption'] = self.caption if self.contact: diff --git a/telegram/voice.py b/telegram/voice.py new file mode 100644 index 000000000..a628b04e6 --- /dev/null +++ b/telegram/voice.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015 Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. + + +from telegram import TelegramObject + + +class Voice(TelegramObject): + def __init__(self, + file_id, + duration=None, + mime_type=None, + file_size=None): + self.file_id = file_id + self.duration = duration + self.mime_type = mime_type + self.file_size = file_size + + @staticmethod + def de_json(data): + return Voice(file_id=data.get('file_id', None), + duration=data.get('duration', None), + mime_type=data.get('mime_type', None), + file_size=data.get('file_size', None)) + + def to_dict(self): + data = {'file_id': self.file_id} + if self.duration: + data['duration'] = self.duration + if self.mime_type: + data['mime_type'] = self.mime_type + if self.file_size: + data['file_size'] = self.file_size + return data diff --git a/tests/telegram.mp3 b/tests/telegram.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..2c9ea84d13fb612ddcda490026d8c3629de4114b GIT binary patch literal 28232 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 literal 0 HcmV?d00001 diff --git a/tests/test_bot.py b/tests/test_bot.py index a51b2a215..b44808c68 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -89,7 +89,7 @@ class BotTest(unittest.TestCase): def testResendPhoto(self): '''Test the telegram.Bot sendPhoto method''' print('Testing sendPhoto - Resend') - message = self._bot.sendPhoto(photo=str('AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI'), + message = self._bot.sendPhoto(photo='AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual('AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI', message.photo[0].file_id) @@ -97,7 +97,7 @@ class BotTest(unittest.TestCase): def testSendJPGURLPhoto(self): '''Test the telegram.Bot sendPhoto method''' print('Testing testSendJPGURLPhoto - URL') - message = self._bot.sendPhoto(photo=str('http://dummyimage.com/600x400/000/fff.jpg&text=telegram'), + message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.jpg&text=telegram', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual(822, message.photo[0].file_size) @@ -105,7 +105,7 @@ class BotTest(unittest.TestCase): def testSendPNGURLPhoto(self): '''Test the telegram.Bot sendPhoto method''' print('Testing testSendPNGURLPhoto - URL') - message = self._bot.sendPhoto(photo=str('http://dummyimage.com/600x400/000/fff.png&text=telegram'), + message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.png&text=telegram', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual(684, message.photo[0].file_size) @@ -113,7 +113,7 @@ class BotTest(unittest.TestCase): def testSendGIFURLPhoto(self): '''Test the telegram.Bot sendPhoto method''' print('Testing testSendGIFURLPhoto - URL') - message = self._bot.sendPhoto(photo=str('http://dummyimage.com/600x400/000/fff.gif&text=telegram'), + message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.gif&text=telegram', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual(684, message.photo[0].file_size) @@ -121,18 +121,40 @@ class BotTest(unittest.TestCase): def testSendAudio(self): '''Test the telegram.Bot sendAudio method''' print('Testing sendAudio - File') - message = self._bot.sendAudio(audio=open('tests/telegram.ogg', 'rb'), - chat_id=12173560) + message = self._bot.sendAudio(audio=open('tests/telegram.mp3', 'rb'), + chat_id=12173560, + performer='Leandro Toledo', + title='Teste') self.assertTrue(self.is_json(message.to_json())) - self.assertEqual(9199, message.audio.file_size) + self.assertEqual(28232, message.audio.file_size) + self.assertEqual('Leandro Toledo', message.audio.performer) + self.assertEqual('Teste', message.audio.title) def testResendAudio(self): '''Test the telegram.Bot sendAudio method''' print('Testing sendAudio - Resend') - message = self._bot.sendAudio(audio=str('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC'), + message = self._bot.sendAudio(audio='BQADAQADwwcAAjU8LQdBRsl3_qD2TAI', + chat_id=12173560, + performer='Leandro Toledo', # Bug #39 + title='Teste') # Bug #39 + self.assertTrue(self.is_json(message.to_json())) + self.assertEqual('BQADAQADwwcAAjU8LQdBRsl3_qD2TAI', message.audio.file_id) + + def testSendVoice(self): + '''Test the telegram.Bot sendVoice method''' + print('Testing sendVoice - File') + message = self._bot.sendVoice(voice=open('tests/telegram.ogg', 'rb'), chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) - self.assertEqual('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC', message.audio.file_id) + self.assertEqual(9199, message.voice.file_size) + + def testResendVoice(self): + '''Test the telegram.Bot sendVoice method''' + print('Testing sendVoice - Resend') + message = self._bot.sendVoice(voice='AwADAQADIQEAAvjAuQABSAXg_GhkhZcC', + chat_id=12173560) + self.assertTrue(self.is_json(message.to_json())) + self.assertEqual('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC', message.voice.file_id) def testSendDocument(self): '''Test the telegram.Bot sendDocument method''' @@ -145,7 +167,7 @@ class BotTest(unittest.TestCase): def testSendGIFURLDocument(self): '''Test the telegram.Bot sendDocument method''' print('Testing sendDocument - File') - message = self._bot.sendPhoto(photo=str('http://dummyimage.com/600x400/000/fff.gif&text=telegram'), + message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.gif&text=telegram', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual(684, message.photo[0].file_size) @@ -153,7 +175,7 @@ class BotTest(unittest.TestCase): def testResendDocument(self): '''Test the telegram.Bot sendDocument method''' print('Testing sendDocument - Resend') - message = self._bot.sendDocument(document=str('BQADAQADHAADNTwtBxZxUGKyxYbYAg'), + message = self._bot.sendDocument(document='BQADAQADHAADNTwtBxZxUGKyxYbYAg', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual('BQADAQADHAADNTwtBxZxUGKyxYbYAg', message.document.file_id) @@ -171,7 +193,7 @@ class BotTest(unittest.TestCase): def testResendVideo(self): '''Test the telegram.Bot sendVideo method''' print('Testing sendVideo - Resend') - message = self._bot.sendVideo(video=str('BAADAQADIgEAAvjAuQABOuTB937fPTgC'), + message = self._bot.sendVideo(video='BAADAQADIgEAAvjAuQABOuTB937fPTgC', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual(4, message.video.duration) @@ -179,7 +201,7 @@ class BotTest(unittest.TestCase): def testResendSticker(self): '''Test the telegram.Bot sendSticker method''' print('Testing sendSticker - Resend') - message = self._bot.sendSticker(sticker=str('BQADAQADHAADyIsGAAFZfq1bphjqlgI'), + message = self._bot.sendSticker(sticker='BQADAQADHAADyIsGAAFZfq1bphjqlgI', chat_id=12173560) self.assertTrue(self.is_json(message.to_json())) self.assertEqual(39518, message.sticker.file_size)