diff --git a/readthedocs/extra/examples/chats-and-channels.rst b/readthedocs/extra/examples/chats-and-channels.rst index 95fa1b1e..f38519c6 100644 --- a/readthedocs/extra/examples/chats-and-channels.rst +++ b/readthedocs/extra/examples/chats-and-channels.rst @@ -56,11 +56,12 @@ Adding someone else to such chat or channel ******************************************* If you don't want to add yourself, maybe because you're already in, -you can always add someone else with the `AddChatUserRequest`__, -which use is very straightforward: +you can always add someone else with the `AddChatUserRequest`__, which +use is very straightforward, or `InviteToChannelRequest`__ for channels: .. code-block:: python + # For normal chats from telethon.tl.functions.messages import AddChatUserRequest client(AddChatUserRequest( @@ -69,6 +70,15 @@ which use is very straightforward: fwd_limit=10 # Allow the user to see the 10 last messages )) + # For channels + from telethon.tl.functions.channels import InviteToChannelRequest + + client(InviteToChannelRequest( + channel, + [users_to_add] + )) + + Checking a link without joining ******************************* @@ -84,6 +94,7 @@ __ https://lonamiwebs.github.io/Telethon/methods/channels/join_channel.html __ https://lonamiwebs.github.io/Telethon/methods/channels/index.html __ https://lonamiwebs.github.io/Telethon/methods/messages/import_chat_invite.html __ https://lonamiwebs.github.io/Telethon/methods/messages/add_chat_user.html +__ https://lonamiwebs.github.io/Telethon/methods/channels/invite_to_channel.html __ https://lonamiwebs.github.io/Telethon/methods/messages/check_chat_invite.html @@ -225,6 +236,12 @@ use `GetMessagesViewsRequest`__, setting ``increment=True``: increment=True )) + +Note that you can only do this **once or twice a day** per account, +running this in a loop will obviously not increase the views forever +unless you wait a day between each iteration. If you run it any sooner +than that, the views simply won't be increased. + __ https://github.com/LonamiWebs/Telethon/issues/233 __ https://github.com/LonamiWebs/Telethon/issues/305 __ https://github.com/LonamiWebs/Telethon/issues/409 diff --git a/readthedocs/telethon.tl.custom.rst b/readthedocs/telethon.tl.custom.rst index a1290869..7f59596c 100644 --- a/readthedocs/telethon.tl.custom.rst +++ b/readthedocs/telethon.tl.custom.rst @@ -10,3 +10,12 @@ telethon\.tl\.custom\.draft module :undoc-members: :show-inheritance: + + +telethon\.tl\.custom\.dialog module +----------------------------------- + +.. automodule:: telethon.tl.custom.dialog + :members: + :undoc-members: + :show-inheritance: diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index b8133d44..361366d3 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -102,7 +102,8 @@ class TelegramClient(TelegramBareClient): Initializes the Telegram client with the specified API ID and Hash. Args: - session (:obj:`str` | :obj:`Session` | :obj:`None`): + session (:obj:`str` | :obj:`telethon.sessions.abstract.Session`, \ + :obj:`None`): The file name of the session file to be used if a string is given (it may be a full path), or the Session instance to be used otherwise. If it's ``None``, the session will not be saved, @@ -394,7 +395,7 @@ class TelegramClient(TelegramBareClient): Returns: The signed in user, or the information about - :meth:`.send_code_request()`. + :meth:`send_code_request`. """ if self.is_user_authorized(): self._check_events_pending_resolve() @@ -550,7 +551,7 @@ class TelegramClient(TelegramBareClient): A _Box instance to pass the total parameter by reference. Yields: - Instances of ``telethon.tl.custom.Dialog``. + Instances of :obj:`telethon.tl.custom.dialog.Dialog`. """ limit = float('inf') if limit is None else int(limit) if limit == 0: @@ -606,7 +607,7 @@ class TelegramClient(TelegramBareClient): def get_dialogs(self, *args, **kwargs): """ Same as :meth:`iter_dialogs`, but returns a list instead - with an additional .total attribute on the list. + with an additional ``.total`` attribute on the list. """ total_box = _Box(0) kwargs['_total_box'] = total_box @@ -618,9 +619,10 @@ class TelegramClient(TelegramBareClient): """ Iterator over all open draft messages. - The yielded items are custom ``Draft`` objects that are easier to use. - You can call ``draft.set_message('text')`` to change the message, - or delete it through :meth:`draft.delete()`. + Instances of :obj:`telethon.tl.custom.draft.Draft` are yielded. + You can call :obj:`telethon.tl.custom.draft.Draft.set_message` + to change the message or :obj:`telethon.tl.custom.draft.Draft.delete` + among other things. """ for update in self(GetAllDraftsRequest()).updates: yield Draft._from_update(self, update) @@ -674,7 +676,7 @@ class TelegramClient(TelegramBareClient): def _parse_message_text(self, message, parse_mode): """ - Returns a (parsed message, entities) tuple depending on parse_mode. + Returns a (parsed message, entities) tuple depending on ``parse_mode``. """ if not parse_mode: return message, [] @@ -741,7 +743,7 @@ class TelegramClient(TelegramBareClient): Has no effect when sending a file. Returns: - the sent message + the sent message. """ if file is not None: return self.send_file( @@ -1001,7 +1003,6 @@ class TelegramClient(TelegramBareClient): second is the default for this limit (or above). You may need an higher limit, so you're free to set the ``batch_size`` that you think may be good. - """ entity = self.get_input_entity(entity) limit = float('inf') if limit is None else int(limit) @@ -1079,7 +1080,7 @@ class TelegramClient(TelegramBareClient): def get_messages(self, *args, **kwargs): """ Same as :meth:`iter_messages`, but returns a list instead - with an additional .total attribute on the list. + with an additional ``.total`` attribute on the list. """ total_box = _Box(0) kwargs['_total_box'] = total_box @@ -1308,7 +1309,7 @@ class TelegramClient(TelegramBareClient): def get_participants(self, *args, **kwargs): """ Same as :meth:`iter_participants`, but returns a list instead - with an additional .total attribute on the list. + with an additional ``.total`` attribute on the list. """ total_box = _Box(0) kwargs['_total_box'] = total_box @@ -1918,7 +1919,7 @@ class TelegramClient(TelegramBareClient): return file def _download_document(self, document, file, date, progress_callback): - """Specialized version of .download_media() for documents""" + """Specialized version of .download_media() for documents.""" if isinstance(document, MessageMediaDocument): document = document.document if not isinstance(document, Document): @@ -1965,7 +1966,7 @@ class TelegramClient(TelegramBareClient): @staticmethod def _download_contact(mm_contact, file): """Specialized version of .download_media() for contacts. - Will make use of the vCard 4.0 format + Will make use of the vCard 4.0 format. """ first_name = mm_contact.first_name last_name = mm_contact.last_name diff --git a/telethon/tl/custom/dialog.py b/telethon/tl/custom/dialog.py index 366a19bf..a2b1a966 100644 --- a/telethon/tl/custom/dialog.py +++ b/telethon/tl/custom/dialog.py @@ -7,7 +7,47 @@ class Dialog: Custom class that encapsulates a dialog (an open "conversation" with someone, a group or a channel) providing an abstraction to easily access the input version/normal entity/message etc. The library will - return instances of this class when calling `client.get_dialogs()`. + return instances of this class when calling :meth:`.get_dialogs()`. + + Args: + dialog (:obj:`Dialog`): + The original ``Dialog`` instance. + + pinned (:obj:`bool`): + Whether this dialog is pinned to the top or not. + + message (:obj:`Message`): + The last message sent on this dialog. Note that this member + will not be updated when new messages arrive, it's only set + on creation of the instance. + + date (:obj:`datetime`): + The date of the last message sent on this dialog. + + entity (:obj:`entity`): + The entity that belongs to this dialog (user, chat or channel). + + input_entity (:obj:`InputPeer`): + Input version of the entity. + + id (:obj:`int`): + The marked ID of the entity, which is guaranteed to be unique. + + name (:obj:`str`): + Display name for this dialog. For chats and channels this is + their title, and for users it's "First-Name Last-Name". + + unread_count (:obj:`int`): + How many messages are currently unread in this dialog. Note that + this value won't update when new messages arrive. + + unread_mentions_count (:obj:`int`): + How many mentions are currently unread in this dialog. Note that + this value won't update when new messages arrive. + + draft (:obj:`telethon.tl.custom.draft.Draft`): + The draft object in this dialog. It will not be ``None``, + so you can call ``draft.set_message(...)``. """ def __init__(self, client, dialog, entities, messages): # Both entities and messages being dicts {ID: item} @@ -19,6 +59,7 @@ class Dialog: self.entity = entities[utils.get_peer_id(dialog.peer)] self.input_entity = utils.get_input_peer(self.entity) + self.id = utils.get_peer_id(self.input_entity) self.name = utils.get_display_name(self.entity) self.unread_count = dialog.unread_count @@ -29,6 +70,6 @@ class Dialog: def send_message(self, *args, **kwargs): """ Sends a message to this dialog. This is just a wrapper around - client.send_message(dialog.input_entity, *args, **kwargs). + ``client.send_message(dialog.input_entity, *args, **kwargs)``. """ return self._client.send_message(self.input_entity, *args, **kwargs) diff --git a/telethon/tl/custom/draft.py b/telethon/tl/custom/draft.py index 8f3aac60..fc40c1cf 100644 --- a/telethon/tl/custom/draft.py +++ b/telethon/tl/custom/draft.py @@ -1,3 +1,5 @@ +import datetime + from ..functions.messages import SaveDraftRequest from ..types import UpdateDraftMessage, DraftMessage from ...extensions import markdown @@ -7,7 +9,17 @@ class Draft: """ Custom class that encapsulates a draft on the Telegram servers, providing an abstraction to change the message conveniently. The library will return - instances of this class when calling ``client.get_drafts()``. + instances of this class when calling :meth:`get_drafts()`. + + Args: + date (:obj:`datetime`): + The date of the draft. + + link_preview (:obj:`bool`): + Whether the link preview is enabled or not. + + reply_to_msg_id (:obj:`int`): + The message ID that the draft will reply to. """ def __init__(self, client, peer, draft): self._client = client @@ -33,20 +45,41 @@ class Draft: @property def entity(self): + """ + The entity that belongs to this dialog (user, chat or channel). + """ return self._client.get_entity(self._peer) @property def input_entity(self): + """ + Input version of the entity. + """ return self._client.get_input_entity(self._peer) @property def text(self): + """ + The markdown text contained in the draft. It will be + empty if there is no text (and hence no draft is set). + """ return self._text @property def raw_text(self): + """ + The raw (text without formatting) contained in the draft. + It will be empty if there is no text (thus draft not set). + """ return self._raw_text + @property + def is_empty(self): + """ + Convenience bool to determine if the draft is empty or not. + """ + return not self._text + def set_message(self, text=None, reply_to=0, parse_mode='md', link_preview=None): """ @@ -88,10 +121,15 @@ class Draft: self._raw_text = raw_text self.link_preview = link_preview self.reply_to_msg_id = reply_to + self.date = datetime.datetime.now() return result def send(self, clear=True, parse_mode='md'): + """ + Sends the contents of this draft to the dialog. This is just a + wrapper around send_message(dialog.input_entity, *args, **kwargs). + """ self._client.send_message(self._peer, self.text, reply_to=self.reply_to_msg_id, link_preview=self.link_preview, @@ -100,7 +138,6 @@ class Draft: def delete(self): """ - Deletes this draft - :return bool: ``True`` on success + Deletes this draft, and returns ``True`` on success. """ return self.set_message(text='')