1#!/usr/bin/env python
2#
3# A library that provides a Python interface to the Telegram Bot API
4# Copyright (C) 2015-2020
5# Leandro Toledo de Souza <devs@python-telegram-bot.org>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU Lesser Public License for more details.
16#
17# You should have received a copy of the GNU Lesser Public License
18# along with this program.  If not, see [http://www.gnu.org/licenses/].
19"""Base class for Telegram InputMedia Objects."""
20
21from typing import Union, List, Tuple
22
23from telegram import (
24    Animation,
25    Audio,
26    Document,
27    InputFile,
28    PhotoSize,
29    TelegramObject,
30    Video,
31    MessageEntity,
32)
33from telegram.utils.helpers import DEFAULT_NONE, DefaultValue, parse_file_input
34from telegram.utils.types import FileInput, JSONDict
35
36
37class InputMedia(TelegramObject):
38    """Base class for Telegram InputMedia Objects.
39
40    See :class:`telegram.InputMediaAnimation`, :class:`telegram.InputMediaAudio`,
41    :class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto` and
42    :class:`telegram.InputMediaVideo` for detailed use.
43
44    """
45
46    caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...], None] = None
47
48    def to_dict(self) -> JSONDict:
49        data = super().to_dict()
50
51        if self.caption_entities:
52            data['caption_entities'] = [
53                ce.to_dict() for ce in self.caption_entities  # pylint: disable=E1133
54            ]
55
56        return data
57
58
59class InputMediaAnimation(InputMedia):
60    """Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
61
62    Attributes:
63        type (:obj:`str`): ``animation``.
64        media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
65        caption (:obj:`str`): Optional. Caption of the document to be sent.
66        parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
67        caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
68            entities that appear in the caption.
69        thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
70        width (:obj:`int`): Optional. Animation width.
71        height (:obj:`int`): Optional. Animation height.
72        duration (:obj:`int`): Optional. Animation duration.
73
74
75    Args:
76        media (:obj:`str` | `filelike object` | :class:`pathlib.Path` | \
77            :class:`telegram.Animation`): File to send. Pass a
78            file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
79            URL for Telegram to get a file from the Internet. Lastly you can pass an existing
80            :class:`telegram.Animation` object to send.
81        thumb (`filelike object` | :class:`pathlib.Path`, optional): Thumbnail of the file sent;
82            can be ignored if
83            thumbnail generation for the file is supported server-side. The thumbnail should be
84            in JPEG format and less than 200 kB in size. A thumbnail's width and height should
85            not exceed 320. Ignored if the file is not uploaded using multipart/form-data.
86            Thumbnails can't be reused and can be only uploaded as a new file.
87        caption (:obj:`str`, optional): Caption of the animation to be sent, 0-1024 characters
88            after entities parsing.
89        parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
90            bold, italic, fixed-width text or inline URLs in the media caption. See the constants
91            in :class:`telegram.ParseMode` for the available modes.
92        caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
93            entities that appear in the caption, which can be specified instead of parse_mode.
94        width (:obj:`int`, optional): Animation width.
95        height (:obj:`int`, optional): Animation height.
96        duration (:obj:`int`, optional): Animation duration.
97
98    Note:
99        When using a :class:`telegram.Animation` for the :attr:`media` attribute. It will take the
100        width, height and duration from that video, unless otherwise specified with the optional
101        arguments.
102    """
103
104    def __init__(
105        self,
106        media: Union[FileInput, Animation],
107        thumb: FileInput = None,
108        caption: str = None,
109        parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
110        width: int = None,
111        height: int = None,
112        duration: int = None,
113        caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
114    ):
115        self.type = 'animation'
116
117        if isinstance(media, Animation):
118            self.media: Union[str, InputFile] = media.file_id
119            self.width = media.width
120            self.height = media.height
121            self.duration = media.duration
122        else:
123            self.media = parse_file_input(media, attach=True)
124
125        if thumb:
126            self.thumb = parse_file_input(thumb, attach=True)
127
128        if caption:
129            self.caption = caption
130        self.parse_mode = parse_mode
131        self.caption_entities = caption_entities
132        if width:
133            self.width = width
134        if height:
135            self.height = height
136        if duration:
137            self.duration = duration
138
139
140class InputMediaPhoto(InputMedia):
141    """Represents a photo to be sent.
142
143    Attributes:
144        type (:obj:`str`): ``photo``.
145        media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
146        caption (:obj:`str`): Optional. Caption of the document to be sent.
147        parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
148        caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
149            entities that appear in the caption.
150
151    Args:
152        media (:obj:`str` | `filelike object` | :class:`pathlib.Path` | \
153            :class:`telegram.PhotoSize`): File to send. Pass a
154            file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
155            URL for Telegram to get a file from the Internet. Lastly you can pass an existing
156            :class:`telegram.PhotoSize` object to send.
157        caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-1024 characters after
158            entities parsing.
159        parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
160            bold, italic, fixed-width text or inline URLs in the media caption. See the constants
161            in :class:`telegram.ParseMode` for the available modes.
162        caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
163            entities that appear in the caption, which can be specified instead of parse_mode.
164    """
165
166    def __init__(
167        self,
168        media: Union[FileInput, PhotoSize],
169        caption: str = None,
170        parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
171        caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
172    ):
173        self.type = 'photo'
174        self.media = parse_file_input(media, PhotoSize, attach=True)
175
176        if caption:
177            self.caption = caption
178        self.parse_mode = parse_mode
179        self.caption_entities = caption_entities
180
181
182class InputMediaVideo(InputMedia):
183    """Represents a video to be sent.
184
185    Attributes:
186        type (:obj:`str`): ``video``.
187        media (:obj:`str` | :class:`telegram.InputFile`): Video file to send.
188        caption (:obj:`str`): Optional. Caption of the document to be sent.
189        parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
190        caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
191            entities that appear in the caption.
192        width (:obj:`int`): Optional. Video width.
193        height (:obj:`int`): Optional. Video height.
194        duration (:obj:`int`): Optional. Video duration.
195        supports_streaming (:obj:`bool`): Optional. Pass :obj:`True`, if the uploaded video is
196            suitable for streaming.
197        thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
198
199    Args:
200        media (:obj:`str` | `filelike object` | :class:`pathlib.Path` | :class:`telegram.Video`):
201            File to send. Pass a
202            file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
203            URL for Telegram to get a file from the Internet. Lastly you can pass an existing
204            :class:`telegram.Video` object to send.
205        caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters after
206            entities parsing.
207        parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
208            bold, italic, fixed-width text or inline URLs in the media caption. See the constants
209            in :class:`telegram.ParseMode` for the available modes.
210        caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
211            entities that appear in the caption, which can be specified instead of parse_mode.
212        width (:obj:`int`, optional): Video width.
213        height (:obj:`int`, optional): Video height.
214        duration (:obj:`int`, optional): Video duration.
215        supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is
216            suitable for streaming.
217        thumb (`filelike object` | :class:`pathlib.Path`, optional): Thumbnail of the file sent;
218            can be ignored if
219            thumbnail generation for the file is supported server-side. The thumbnail should be
220            in JPEG format and less than 200 kB in size. A thumbnail's width and height should
221            not exceed 320. Ignored if the file is not uploaded using multipart/form-data.
222            Thumbnails can't be reused and can be only uploaded as a new file.
223
224    Note:
225        *  When using a :class:`telegram.Video` for the :attr:`media` attribute. It will take the
226           width, height and duration from that video, unless otherwise specified with the optional
227           arguments.
228        *  ``thumb`` will be ignored for small video files, for which Telegram can easily
229           generate thumb nails. However, this behaviour is undocumented and might be changed
230           by Telegram.
231    """
232
233    def __init__(
234        self,
235        media: Union[FileInput, Video],
236        caption: str = None,
237        width: int = None,
238        height: int = None,
239        duration: int = None,
240        supports_streaming: bool = None,
241        parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
242        thumb: FileInput = None,
243        caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
244    ):
245        self.type = 'video'
246
247        if isinstance(media, Video):
248            self.media: Union[str, InputFile] = media.file_id
249            self.width = media.width
250            self.height = media.height
251            self.duration = media.duration
252        else:
253            self.media = parse_file_input(media, attach=True)
254
255        if thumb:
256            self.thumb = parse_file_input(thumb, attach=True)
257
258        if caption:
259            self.caption = caption
260        self.parse_mode = parse_mode
261        self.caption_entities = caption_entities
262        if width:
263            self.width = width
264        if height:
265            self.height = height
266        if duration:
267            self.duration = duration
268        if supports_streaming:
269            self.supports_streaming = supports_streaming
270
271
272class InputMediaAudio(InputMedia):
273    """Represents an audio file to be treated as music to be sent.
274
275    Attributes:
276        type (:obj:`str`): ``audio``.
277        media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
278        caption (:obj:`str`): Optional. Caption of the document to be sent.
279        parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
280        caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
281            entities that appear in the caption.
282        duration (:obj:`int`): Duration of the audio in seconds.
283        performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio
284            tags.
285        title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags.
286        thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
287
288    Args:
289        media (:obj:`str` | `filelike object` | :class:`pathlib.Path` | :class:`telegram.Audio`):
290            File to send. Pass a
291            file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
292            URL for Telegram to get a file from the Internet. Lastly you can pass an existing
293            :class:`telegram.Audio` object to send.
294        caption (:obj:`str`, optional): Caption of the audio to be sent, 0-1024 characters after
295            entities parsing.
296        parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
297            bold, italic, fixed-width text or inline URLs in the media caption. See the constants
298            in :class:`telegram.ParseMode` for the available modes.
299        caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
300            entities that appear in the caption, which can be specified instead of parse_mode.
301        duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
302        performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio
303            tags.
304        title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags.
305        thumb (`filelike object` | :class:`pathlib.Path`, optional): Thumbnail of the file sent;
306            can be ignored if
307            thumbnail generation for the file is supported server-side. The thumbnail should be
308            in JPEG format and less than 200 kB in size. A thumbnail's width and height should
309            not exceed 320. Ignored if the file is not uploaded using multipart/form-data.
310            Thumbnails can't be reused and can be only uploaded as a new file.
311
312    Note:
313        When using a :class:`telegram.Audio` for the :attr:`media` attribute. It will take the
314        duration, performer and title from that video, unless otherwise specified with the
315        optional arguments.
316    """
317
318    def __init__(
319        self,
320        media: Union[FileInput, Audio],
321        thumb: FileInput = None,
322        caption: str = None,
323        parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
324        duration: int = None,
325        performer: str = None,
326        title: str = None,
327        caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
328    ):
329        self.type = 'audio'
330
331        if isinstance(media, Audio):
332            self.media: Union[str, InputFile] = media.file_id
333            self.duration = media.duration
334            self.performer = media.performer
335            self.title = media.title
336        else:
337            self.media = parse_file_input(media, attach=True)
338
339        if thumb:
340            self.thumb = parse_file_input(thumb, attach=True)
341
342        if caption:
343            self.caption = caption
344        self.parse_mode = parse_mode
345        self.caption_entities = caption_entities
346        if duration:
347            self.duration = duration
348        if performer:
349            self.performer = performer
350        if title:
351            self.title = title
352
353
354class InputMediaDocument(InputMedia):
355    """Represents a general file to be sent.
356
357    Attributes:
358        type (:obj:`str`): ``document``.
359        media (:obj:`str` | :class:`telegram.InputFile`): File to send.
360        caption (:obj:`str`): Optional. Caption of the document to be sent.
361        parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
362        caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
363            entities that appear in the caption.
364        thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
365        disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side
366            content type detection for files uploaded using multipart/form-data. Always true, if
367            the document is sent as part of an album.
368
369    Args:
370        media (:obj:`str` | `filelike object` | :class:`pathlib.Path` | \
371            :class:`telegram.Document`): File to send. Pass a
372            file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP
373            URL for Telegram to get a file from the Internet. Lastly you can pass an existing
374            :class:`telegram.Document` object to send.
375        caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters after
376            entities parsing.
377        parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
378            bold, italic, fixed-width text or inline URLs in the media caption. See the constants
379            in :class:`telegram.ParseMode` for the available modes.
380        caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
381            entities that appear in the caption, which can be specified instead of parse_mode.
382        thumb (`filelike object` | :class:`pathlib.Path`, optional): Thumbnail of the file sent;
383            can be ignored if
384            thumbnail generation for the file is supported server-side. The thumbnail should be
385            in JPEG format and less than 200 kB in size. A thumbnail's width and height should
386            not exceed 320. Ignored if the file is not uploaded using multipart/form-data.
387            Thumbnails can't be reused and can be only uploaded as a new file.
388        disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side
389            content type detection for files uploaded using multipart/form-data. Always true, if
390            the document is sent as part of an album.
391    """
392
393    def __init__(
394        self,
395        media: Union[FileInput, Document],
396        thumb: FileInput = None,
397        caption: str = None,
398        parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
399        disable_content_type_detection: bool = None,
400        caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
401    ):
402        self.type = 'document'
403        self.media = parse_file_input(media, Document, attach=True)
404
405        if thumb:
406            self.thumb = parse_file_input(thumb, attach=True)
407
408        if caption:
409            self.caption = caption
410        self.parse_mode = parse_mode
411        self.caption_entities = caption_entities
412        self.disable_content_type_detection = disable_content_type_detection
413