mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-11-22 15:17:00 +01:00
Merge branch 'videonote' into beta
# Conflicts: # telegram/__init__.py # telegram/message.py
This commit is contained in:
commit
48fa3d975b
7 changed files with 370 additions and 4 deletions
|
@ -94,6 +94,7 @@ from .precheckoutquery import PreCheckoutQuery
|
|||
from .shippingquery import ShippingQuery
|
||||
from .webhookinfo import WebhookInfo
|
||||
from .gamehighscore import GameHighScore
|
||||
from .videonote import VideoNote
|
||||
from .update import Update
|
||||
from .bot import Bot
|
||||
from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOOK_PORTS,
|
||||
|
@ -123,6 +124,6 @@ __all__ = [
|
|||
'Video', 'Voice', 'MAX_MESSAGE_LENGTH', 'MAX_CAPTION_LENGTH', 'SUPPORTED_WEBHOOK_PORTS',
|
||||
'MAX_FILESIZE_DOWNLOAD', 'MAX_FILESIZE_UPLOAD', 'MAX_MESSAGES_PER_SECOND_PER_CHAT',
|
||||
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
|
||||
'Game', 'GameHighScore', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
|
||||
'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
|
||||
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery'
|
||||
]
|
||||
|
|
|
@ -671,6 +671,66 @@ class Bot(TelegramObject):
|
|||
timeout=timeout,
|
||||
**kwargs)
|
||||
|
||||
@log
|
||||
def send_video_note(self,
|
||||
chat_id,
|
||||
video_note,
|
||||
duration=None,
|
||||
length=None,
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
**kwargs):
|
||||
"""As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute
|
||||
long. Use this method to send video messages
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the message recipient - Chat id.
|
||||
voice: Video note to send. Pass a file_id as String to send a video note that exists
|
||||
on the Telegram servers (recommended) or upload a new video. Sending video notes
|
||||
by a URL is currently unsupported
|
||||
duration (Optional[int]): Duration of sent audio in seconds.
|
||||
length (Optional[int]): Video width and height
|
||||
disable_notification (Optional[bool]): Sends the message silently. iOS users will not
|
||||
receive a notification, Android users will receive a notification with no sound.
|
||||
reply_to_message_id (Optional[int]): If the message is a reply, ID of the original
|
||||
message.
|
||||
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
|
||||
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
|
||||
to remove reply keyboard or to force a reply from the user.
|
||||
timeout (Optional[int|float]): Send file timeout (default: 20 seconds).
|
||||
**kwargs (dict): Arbitrary keyword arguments.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/sendVideoNote'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'video_note': video_note}
|
||||
|
||||
if duration:
|
||||
data['duration'] = duration
|
||||
if length:
|
||||
data['length'] = length
|
||||
|
||||
return self._message_wrapper(
|
||||
url,
|
||||
data,
|
||||
chat_id=chat_id,
|
||||
video_note=video_note,
|
||||
duration=duration,
|
||||
length=length,
|
||||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
timeout=timeout,
|
||||
**kwargs)
|
||||
|
||||
@log
|
||||
@message
|
||||
def send_location(self,
|
||||
|
@ -1963,6 +2023,7 @@ class Bot(TelegramObject):
|
|||
sendSticker = send_sticker
|
||||
sendVideo = send_video
|
||||
sendVoice = send_voice
|
||||
sendVideoNote = send_video_note
|
||||
sendLocation = send_location
|
||||
sendVenue = send_venue
|
||||
sendContact = send_contact
|
||||
|
|
|
@ -31,3 +31,5 @@ class ChatAction(object):
|
|||
UPLOAD_AUDIO = 'upload_audio'
|
||||
UPLOAD_DOCUMENT = 'upload_document'
|
||||
FIND_LOCATION = 'find_location'
|
||||
RECORD_VIDEO_NOTE = 'record_video_note'
|
||||
UPLOAD_VIDEO_NOTE = 'upload_video_note'
|
||||
|
|
|
@ -35,7 +35,8 @@ from telegram import TelegramError
|
|||
|
||||
DEFAULT_MIME_TYPE = 'application/octet-stream'
|
||||
USER_AGENT = 'Python Telegram Bot (https://github.com/python-telegram-bot/python-telegram-bot)'
|
||||
FILE_TYPES = ('audio', 'document', 'photo', 'sticker', 'video', 'voice', 'certificate')
|
||||
FILE_TYPES = ('audio', 'document', 'photo', 'sticker', 'video', 'voice', 'certificate',
|
||||
'video_note')
|
||||
|
||||
|
||||
class InputFile(object):
|
||||
|
@ -66,6 +67,9 @@ class InputFile(object):
|
|||
elif 'certificate' in data:
|
||||
self.input_name = 'certificate'
|
||||
self.input_file = data.pop('certificate')
|
||||
elif 'video_note' in data:
|
||||
self.input_name = 'video_note'
|
||||
self.input_file = data.pop('video_note')
|
||||
else:
|
||||
raise TelegramError('Unknown inputfile type')
|
||||
|
||||
|
@ -117,7 +121,7 @@ class InputFile(object):
|
|||
form_boundary, 'Content-Disposition: form-data; name="%s"' % name, '', str(value)
|
||||
])
|
||||
|
||||
# Add input_file to upload
|
||||
# Add input_file to upload
|
||||
form.extend([
|
||||
form_boundary, 'Content-Disposition: form-data; name="%s"; filename="%s"' %
|
||||
(self.input_name,
|
||||
|
|
|
@ -23,7 +23,8 @@ from datetime import datetime
|
|||
from time import mktime
|
||||
|
||||
from telegram import (Audio, Contact, Document, Chat, Location, PhotoSize, Sticker, TelegramObject,
|
||||
User, Video, Voice, Venue, MessageEntity, Game, Invoice, SuccessfulPayment)
|
||||
User, Video, Voice, Venue, MessageEntity, Game, Invoice, SuccessfulPayment,
|
||||
VideoNote)
|
||||
from telegram.utils.helpers import escape_html, escape_markdown
|
||||
|
||||
|
||||
|
@ -62,6 +63,8 @@ class Message(TelegramObject):
|
|||
sticker (:class:`telegram.Sticker`): Message is a sticker, information about the sticker
|
||||
video (:class:`telegram.Video`): Message is a video, information about the video
|
||||
voice (:class:`telegram.Voice`): Message is a voice message, information about the file
|
||||
video_note (:class:`telegram.VideoNote`): Message is a video note, information about the
|
||||
video message
|
||||
caption (str): Caption for the document, photo or video, 0-200 characters
|
||||
contact (:class:`telegram.Contact`): Message is a shared contact, information about the
|
||||
contact
|
||||
|
@ -123,6 +126,7 @@ class Message(TelegramObject):
|
|||
sticker=None,
|
||||
video=None,
|
||||
voice=None,
|
||||
video_note=None,
|
||||
caption=None,
|
||||
contact=None,
|
||||
location=None,
|
||||
|
@ -163,6 +167,7 @@ class Message(TelegramObject):
|
|||
self.sticker = sticker
|
||||
self.video = video
|
||||
self.voice = voice
|
||||
self.video_note = video_note
|
||||
self.caption = caption
|
||||
self.contact = contact
|
||||
self.location = location
|
||||
|
@ -222,6 +227,7 @@ class Message(TelegramObject):
|
|||
data['sticker'] = Sticker.de_json(data.get('sticker'), bot)
|
||||
data['video'] = Video.de_json(data.get('video'), bot)
|
||||
data['voice'] = Voice.de_json(data.get('voice'), bot)
|
||||
data['video_note'] = VideoNote.de_json(data.get('video_note'), bot)
|
||||
data['contact'] = Contact.de_json(data.get('contact'), bot)
|
||||
data['location'] = Location.de_json(data.get('location'), bot)
|
||||
data['venue'] = Venue.de_json(data.get('venue'), bot)
|
||||
|
@ -412,6 +418,23 @@ class Message(TelegramObject):
|
|||
self._quote(kwargs)
|
||||
return self.bot.sendVideo(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_video_note(self, *args, **kwargs):
|
||||
"""
|
||||
Shortcut for ``bot.send_video_note(update.message.chat_id, *args, **kwargs)``
|
||||
|
||||
Keyword Args:
|
||||
quote (Optional[bool]): If set to ``True``, the video is sent as an actual reply to
|
||||
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
|
||||
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||
|
||||
"""
|
||||
|
||||
self._quote(kwargs)
|
||||
return self.bot.send_video_note(self.chat_id, *args, **kwargs)
|
||||
|
||||
def reply_voice(self, *args, **kwargs):
|
||||
"""
|
||||
Shortcut for ``bot.sendVoice(update.message.chat_id, *args, **kwargs)``
|
||||
|
|
63
telegram/videonote.py
Normal file
63
telegram/videonote.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2017
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# 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/].
|
||||
"""This module contains an object that represents a Telegram VideoNote."""
|
||||
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
|
||||
|
||||
class VideoNote(TelegramObject):
|
||||
"""This object represents a Telegram VideoNote.
|
||||
|
||||
Attributes:
|
||||
file_id (str): Unique identifier for this file
|
||||
length (int): Video width and height as defined by sender
|
||||
duration (int): Duration of the video in seconds as defined by sender
|
||||
thumb (Optional[:class:`telegram.PhotoSize`]): Video thumbnail
|
||||
file_size (Optional[int]): File size
|
||||
"""
|
||||
|
||||
def __init__(self, file_id, length, duration, thumb=None, file_size=None, **kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.length = int(length)
|
||||
self.duration = int(duration)
|
||||
# Optionals
|
||||
self.thumb = thumb
|
||||
self.file_size = file_size
|
||||
|
||||
self._id_attrs = (self.file_id,)
|
||||
|
||||
@staticmethod
|
||||
def de_json(data, bot):
|
||||
"""
|
||||
Args:
|
||||
data (dict):
|
||||
bot (telegram.Bot):
|
||||
|
||||
Returns:
|
||||
telegram.VideoNote:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data = super(VideoNote, VideoNote).de_json(data, bot)
|
||||
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
|
||||
|
||||
return VideoNote(**data)
|
212
tests/test_videonote.py
Normal file
212
tests/test_videonote.py
Normal file
|
@ -0,0 +1,212 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2017
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents Tests for Telegram VideoNote"""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
import os
|
||||
|
||||
from flaky import flaky
|
||||
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest, timeout
|
||||
|
||||
|
||||
class VideoNoteTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram VideoNote."""
|
||||
|
||||
def setUp(self):
|
||||
self.videonote_file = open('tests/data/telegram.mp4', 'rb')
|
||||
self.videonote_file_id = 'DQADAQADBwAD5VIIRYemhHpbPmIQAg'
|
||||
self.duration = 5
|
||||
self.length = 1 # No bloody clue what this does, see note in first test
|
||||
self.thumb = telegram.PhotoSize.de_json({
|
||||
'file_id': 'AAQBABOMsecvAAQqqoY1Pee_MqcyAAIC',
|
||||
'width': 51,
|
||||
'file_size': 645,
|
||||
'height': 90
|
||||
}, self._bot)
|
||||
self.file_size = 326534
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.videonote_file_id,
|
||||
'duration': self.duration,
|
||||
'length': self.length,
|
||||
'thumb': self.thumb.to_dict(),
|
||||
'file_size': self.file_size
|
||||
}
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_error_send_videonote_required_args_only(self):
|
||||
# This is where it gets weird....
|
||||
# According to telegram length is Video width and height.. but how that works with one
|
||||
# parameter I couldn't tell you
|
||||
# It would also seem that it is in fact a required parameter, so the original test below
|
||||
# fails. Therefore I decided I check for the error instead - that way we'll also know
|
||||
# when telegram fixes their shit
|
||||
with self.assertRaisesRegexp(telegram.error.BadRequest, r'Wrong video note length'):
|
||||
message = self._bot.sendVideoNote(self._chat_id, self.videonote_file, timeout=10)
|
||||
|
||||
# videonote = message.videonote
|
||||
#
|
||||
# self.assertTrue(isinstance(videonote.file_id, str))
|
||||
# self.assertNotEqual(videonote.file_id, None)
|
||||
# self.assertEqual(videonote.duration, self.duration)
|
||||
# self.assertEqual(videonote.length, self.length)
|
||||
# self.assertEqual(videonote.thumb, self.thumb)
|
||||
# self.assertEqual(videonote.file_size, self.file_size)
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_send_videonote_actual_required_args_only(self):
|
||||
# See above test... if you pass any number that's > 0 and < some high number, it seems
|
||||
# to work
|
||||
message = self._bot.sendVideoNote(
|
||||
self._chat_id, self.videonote_file, length=self.length, timeout=10)
|
||||
|
||||
videonote = message.video_note
|
||||
|
||||
self.assertTrue(isinstance(videonote.file_id, str))
|
||||
self.assertNotEqual(videonote.file_id, None)
|
||||
self.assertEqual(videonote.duration, self.duration)
|
||||
# self.assertEqual(videonote.length, self.length)
|
||||
self.assertEqual(videonote.thumb, self.thumb)
|
||||
self.assertEqual(videonote.file_size, self.file_size)
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_send_videonote_all_args(self):
|
||||
message = self._bot.sendVideoNote(
|
||||
self._chat_id,
|
||||
self.videonote_file,
|
||||
timeout=10,
|
||||
duration=self.duration,
|
||||
length=self.length)
|
||||
|
||||
videonote = message.video_note
|
||||
|
||||
self.assertTrue(isinstance(videonote.file_id, str))
|
||||
self.assertNotEqual(videonote.file_id, None)
|
||||
# self.assertEqual(videonote.length, self.length)
|
||||
self.assertEqual(videonote.duration, self.duration)
|
||||
self.assertEqual(videonote.thumb, self.thumb)
|
||||
self.assertEqual(videonote.file_size, self.file_size)
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_send_videonote_resend(self):
|
||||
message = self._bot.sendVideoNote(
|
||||
chat_id=self._chat_id,
|
||||
video_note=self.videonote_file_id,
|
||||
timeout=10,
|
||||
duration=self.duration,
|
||||
length=self.length)
|
||||
|
||||
videonote = message.video_note
|
||||
|
||||
self.assertEqual(videonote.file_id, self.videonote_file_id)
|
||||
# self.assertEqual(videonote.length, self.length)
|
||||
self.assertEqual(videonote.duration, self.duration)
|
||||
self.assertEqual(videonote.thumb, self.thumb)
|
||||
self.assertEqual(videonote.file_size, self.file_size)
|
||||
|
||||
def test_videonote_de_json(self):
|
||||
videonote = telegram.VideoNote.de_json(self.json_dict, self._bot)
|
||||
|
||||
self.assertEqual(videonote.file_id, self.videonote_file_id)
|
||||
# self.assertEqual(videonote.duration, self.duration)
|
||||
self.assertEqual(videonote.thumb, self.thumb)
|
||||
self.assertEqual(videonote.length, self.length)
|
||||
self.assertEqual(videonote.file_size, self.file_size)
|
||||
|
||||
def test_videonote_to_json(self):
|
||||
videonote = telegram.VideoNote.de_json(self.json_dict, self._bot)
|
||||
|
||||
self.assertTrue(self.is_json(videonote.to_json()))
|
||||
|
||||
def test_videonote_to_dict(self):
|
||||
videonote = telegram.VideoNote.de_json(self.json_dict, self._bot)
|
||||
|
||||
self.assertTrue(self.is_dict(videonote.to_dict()))
|
||||
self.assertEqual(videonote['file_id'], self.videonote_file_id)
|
||||
self.assertEqual(videonote['duration'], self.duration)
|
||||
self.assertEqual(videonote['length'], self.length)
|
||||
self.assertEqual(videonote['file_size'], self.file_size)
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_error_send_videonote_empty_file(self):
|
||||
json_dict = self.json_dict
|
||||
|
||||
del (json_dict['file_id'])
|
||||
json_dict['video_note'] = open(os.devnull, 'rb')
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendVideoNote(chat_id=self._chat_id,
|
||||
timeout=10,
|
||||
**json_dict))
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_error_send_videonote_empty_file_id(self):
|
||||
json_dict = self.json_dict
|
||||
|
||||
del (json_dict['file_id'])
|
||||
json_dict['video_note'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendVideoNote(chat_id=self._chat_id,
|
||||
timeout=10,
|
||||
**json_dict))
|
||||
|
||||
@flaky(3, 1)
|
||||
@timeout(10)
|
||||
def test_reply_videonote(self):
|
||||
"""Test for Message.reply_videonote"""
|
||||
message = self._bot.sendMessage(self._chat_id, '.')
|
||||
# Length is needed... see first test
|
||||
message = message.reply_video_note(self.videonote_file, length=self.length)
|
||||
|
||||
self.assertNotEqual(message.video_note.file_id, None)
|
||||
|
||||
def test_equality(self):
|
||||
a = telegram.VideoNote(self.videonote_file_id, self.length, self.duration)
|
||||
b = telegram.VideoNote(self.videonote_file_id, self.length, self.duration)
|
||||
c = telegram.VideoNote(self.videonote_file_id, 0, 0, 0)
|
||||
d = telegram.VideoNote("", self.length, self.duration)
|
||||
e = telegram.Voice(self.videonote_file_id, self.duration)
|
||||
|
||||
self.assertEqual(a, b)
|
||||
self.assertEqual(hash(a), hash(b))
|
||||
self.assertIsNot(a, b)
|
||||
|
||||
self.assertEqual(a, c)
|
||||
self.assertEqual(hash(a), hash(c))
|
||||
|
||||
self.assertNotEqual(a, d)
|
||||
self.assertNotEqual(hash(a), hash(d))
|
||||
|
||||
self.assertNotEqual(a, e)
|
||||
self.assertNotEqual(hash(a), hash(e))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in a new issue