How do I authorize with a Telethon QR code? - python

I'm trying to authorize in telethon via QR.
In the docs of telegram I found the method exportLoginToken, which allows you to create a token for qr code.
If I understand it correctly, the desktop telegram client uses this mechanics. You scan the qr from an authorized device and the session opens on the pc.
Telethon also has it. Example from the documentation:
with TelegramClient(name, api_id, api_hash) as client:
result = client(functions.auth.ExportLoginTokenRequest(
api_id=42,
api_hash='some string here',
except_ids=[42]
))
print(result.stringify())
If we don't have an active session, it will create one when we enter as telethon.
For this we need a number and a code. Or an active session and a connected client
The telethon docs say:
Note that you must be connected before invoking this, as with any other request.
So in order to create an authorization token on the new device I must already be authorized?
How do I get a token for the qr code on a device that has no active sessions?

When the documentation says that you must be connected, it means that you must call the method TelegramClient.connect which connects you to telegram.
So if you do this, it will work out:
import telethon
from telethon import TelegramClient
from qrcode import QRCode
from base64 import urlsafe_b64encode as base64url
qr = QRCode()
def gen_qr(token:str):
qr.clear()
qr.add_data(token)
qr.print_ascii()
def display_url_as_qr(url):
print(url) # do whatever to show url as a qr to the user
gen_qr(url)
async def main(client: telethon.TelegramClient):
if(not client.is_connected()):
await client.connect()
client.connect()
qr_login = await client.qr_login()
print(client.is_connected())
r = False
while not r:
display_url_as_qr(qr_login.url)
# Important! You need to wait for the login to complete!
try:
r = await qr_login.wait(10)
except:
await qr_login.recreate()
TELEGRAM_API_ID=
TELEGRAM_API_HASH=
client = TelegramClient("SessionName", TELEGRAM_API_ID, TELEGRAM_API_HASH)
client.loop.run_until_complete(main(client))

Related

How do I create invites with usage limit to a private channel on Telegram with Telethon?

I'm using Telethon to create a Telegram BOT and I needed to automate a task of generating a one time use invite
I tried searching about it but didn't find anything at their docs neither stackoverflow (i did find somethings about invites with this library but didn't understood how to handle my situation)
Anything that may help me with this is welcome!!
Thank you in advance!
From telethon.dev, You can mod the example like:
from telethon.sync import TelegramClient
from telethon import functions, types
session_file_name = "" # TODO: session file name without extension
api_id = "" # TODO: api id
api_hash = "" # TODO: api hash
channel_id = -1001109500936 # TODO: channel ID
with TelegramClient(session_file_name, api_id, api_hash) as client:
result = client(functions.messages.ExportChatInviteRequest(
peer=client.get_input_entity(channel_id),
legacy_revoke_permanent=True,
expire_date=None, # Set expiry date if needed like datetime.datetime(2018, 6, 25),
usage_limit=1 # Only one person can use your invite link
))
print(result.stringify())

Best practice in sending message in python telegram bot from a 3d party listener

I have a custom code that does its routine and I want to send a message to myself in Telegram if something goes wrong. In my case I use python-telegram-bot library along with apscheduler and its listeners, where certain events could be catched.
I came up with such working code, but my question is: is it possible to make it better, namely without using global variable? This was done to overcome the problem that listeners do not accept arguments needed for bot to send a message.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
from telegram.ext import Updater, CommandHandler
import copy
import my_custom_library
saved_update = None
def my_listener(event): # not related with bot
if event.exception:
if saved_update is not None:
alert(saved_update, 'Scheduler threw event.exception.') # should have bot related args
else:
record = event.retval # get returned value from my_custom_library.repetitive_function
try:
processed_record = my_custom_library.my_unsafe_business_logic(record) # something might go wrong here
my_custom_library.add_to_db(processed_record) # and here
except Exception as e:
if saved_update is not None:
alert(saved_update, e) # should have bot related args
def start(update, context):
global saved_update
saved_update = copy.deepcopy(update) # this is what I don't like
update.message.reply_text('You have subscribed for notifications.')
def alert(update, reason):
update.message.reply_text('Something went wrong: {}'.format(reason))
def main():
scheduler = BackgroundScheduler()
scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
scheduler.add_job(my_custom_library.repetitive_function, args=(my_args,), trigger='interval', minutes=1)
scheduler.start()
# bot
updater = Updater(TOKEN, use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler("start", callback=start))
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
The Telegram Bot API is fairly simple, you just ned to send an HTTP GET Request to this URL:
https://api.telegram.org/bot_token_/sendMessage?chat_id=123&text=Hello%20World!
Just create a bot with Botfather and send the Bot a message.
With the specified Token from Botfather and this URL:
https://api.telegram.org/bot_token_/getUpdates
You can get the messages which were sent to the Bot and the chat_id.
The simplest way would be to use the requests module and send the output of the updater to the first URL as the text parameter.
In my scripts I often use callbacks. It's a clean solution that provides separation between the two scripts. The send_message function can accept kwargs, so you can essentially create a dictionary, and update it when sending the message. The first part (channel ID) is something you know on the bot-side, and the second part (the text itself) is something you know one the third-party side.
In your third-party, provide a set_cb function that accepts a callback and a dictionary. Like so:
def set_cb(self, callback, params):
self.callback = callback
self.callback_params = params
In your bot script, set the callback before updater.idle()
# Start the Bot
updater = Updater("TOKEN")
updater.start_polling()
# Set the callback
r.set_cb(updater.bot.send_message, {"chat_id": 123456})
Then, in your third-party, once you want to send a message, simply add the message text call the following:
self.callback_params.update({"text": text})
self.callback(**self.callback_params) # converts the dict to kwargs

sending message to contacts in telethon python telegram

How can I see all my contacts and send them messages?
i use Telethon (API telegram python).
from telethon.tl.functions.contacts import ResolveUsernameRequest
from telethon.tl.types import InputChannelEmpty
from telethon import TelegramClient
from telethon.tl.types.messages import Messages
from telethon.tl.types.contacts import Contacts
api_id = 1****
api_hash = '5fbd2d************************'
client = TelegramClient('arta0', api_id, api_hash)
client.connect()
Just add this line to your code:
contacts = client.invoke(GetContactsRequest(""))
print(contacts)
And you should see the contacts in the result.
To send messages to contacts, you can use the send_message function defined in telegram_client.py and has an example in InteractiveTelegramClient.py.
for u in contacts.users:
client.send_message(InputPeerUser(u.id, u.access_hash), "hi")
If you need more details comment below and I will try to reply.
Sending empty string didn't worked for me:
contacts = client.invoke(GetContactsRequest(""))
*** struct.error: required argument is not an integer
So I think you should use '0' instead:
contacts = client.invoke(GetContactsRequest(0))
print(contacts)
I think in new update client.invoke() is not defined.
I used following code and it worked for me.
from telethon.tl.functions.contacts import GetContactsRequest
contacts = client(GetContactsRequest(0))

Telethon: delete a message

I am trying to delete a message using telegram API and Telethon.
Here is my code:
from telethon import InteractiveTelegramClient
from telethon.tl.types.input_peer_channel import InputPeerChannel
from telethon.tl.functions.messages.delete_messages import DeleteMessagesRequest
#...
total_count, messages, senders = client.get_message_history(
chat, limit=1)
msg = messages[0]
result = client.invoke(DeleteMessagesRequest([msg.id]))
But first of all nothing happens, and second, it doesn't look right, since msg.id is like 5 or 220 and it doesn't look like a unique number.
Here is the message:
msg: (message (ID: 0xc09bexxx) = (out=None, mentioned=None, media_unread=None, silent=None, post=True, id=5, from_id=None, to_id=(peerChannel (ID: 0xbdddexxx) = (channel_id=1234)), fwd_from=None, via_bot_id=None, reply_to_msg_id=None, date=2017-06-14 14:39:23, message=test33, media=None, reply_markup=None, entities=None, views=1, edit_date=None))
I also tried with the hex number 0xc09bexxx but that gives an exception.
So how can I delete a message in a channel?
So far I looked at this github issue to get started with the delete message. My guess is that maybe the following import is not the right one and I should import the version in the Channels package, which gets a channel id and a message id?
from telethon.tl.functions.messages.delete_messages import DeleteMessagesRequest
Using the other delete from channels package I was able to get the delete message working, but I am still curious to know how to get the delete from messages.delete_messages working.
from telethon.tl.functions.channels.delete_messages import DeleteMessagesRequest
channel = InputPeerChannel(channel_id, access_hash)
result = client.invoke(DeleteMessagesRequest(channel, [msg.id]))
and it will delete the message from the channel.
from telethon import TelegramClient
client = TelegramClient('cookie', '123', 'XXX')
id_group = -1001231231231
id_message = 3
await client.delete_messages(entity=id_group, message_ids=[id_message])
For example if u want to obtain all the msgs-ids in the channel and after of it delete all messages... this code works to me:
from telethon import TelegramClient
client = TelegramClient('cookiename', Apiid, 'api_hash')
id_group = -XXXX
async def getmsgs(client,id_group):
messagesid = []
async for message in client.iter_messages(id_group):
print(message.id)
messagesid.append(message.id)
return messagesid
async def delmsgs(client,id_group,list_msgs_id):
await client.delete_messages(entity=id_group, message_ids=list_msgs_id)
with client:
messages = client.loop.run_until_complete(getmsgs(client,id_group))
client.loop.run_until_complete(delmsgs(client,id_group,messages))

How can I download the chat history of a group in Telegram?

I would like to download the chat history (all messages) that were posted in a public group on Telegram. How can I do this with python?
I've found this method in the API https://core.telegram.org/method/messages.getHistory which I think looks like what I'm trying to do. But how do I actually call it? It seems there's no python examples for the MTproto protocol they use.
I also looked at the Bot API, but it doesn't seem to have a method to download messages.
You can use Telethon. Telegram API is fairly complicated and with the telethon, you can start using telegram API in a very short time without any pre-knowledge about the API.
pip install telethon
Then register your app (taken from telethon):
the link is: https://my.telegram.org/
Then to obtain message history of a group (assuming you have the group id):
chat_id = YOUR_CHAT_ID
api_id=YOUR_API_ID
api_hash = 'YOUR_API_HASH'
from telethon import TelegramClient
from telethon.tl.types.input_peer_chat import InputPeerChat
client = TelegramClient('session_id', api_id=api_id, api_hash=api_hash)
client.connect()
chat = InputPeerChat(chat_id)
total_count, messages, senders = client.get_message_history(
chat, limit=10)
for msg in reversed(messages):
# Format the message content
if getattr(msg, 'media', None):
content = '<{}> {}'.format( # The media may or may not have a caption
msg.media.__class__.__name__,
getattr(msg.media, 'caption', ''))
elif hasattr(msg, 'message'):
content = msg.message
elif hasattr(msg, 'action'):
content = str(msg.action)
else:
# Unknown message, simply print its class name
content = msg.__class__.__name__
text = '[{}:{}] (ID={}) {}: {} type: {}'.format(
msg.date.hour, msg.date.minute, msg.id, "no name",
content)
print (text)
The example is taken and simplified from telethon example.
With an update (August 2018) now Telegram Desktop application supports saving chat history very conveniently.
You can store it as json or html formatted.
To use this feature, make sure you have the latest version of Telegram Desktop installed on your computer, then click Settings > Export Telegram data.
https://telegram.org/blog/export-and-more
The currently accepted answer is for very old versions of Telethon. With Telethon 1.0, the code can and should be simplified to the following:
# chat can be:
# * int id (-12345)
# * str username (#chat)
# * str phone number (+12 3456)
# * Peer (types.PeerChat(12345))
# * InputPeer (types.InputPeerChat(12345))
# * Chat object (types.Chat)
# * ...and many more types
chat = ...
api_id = ...
api_hash = ...
from telethon.sync import TelegramClient
client = TelegramClient('session_id', api_id, api_hash)
with client:
# 10 is the limit on how many messages to fetch. Remove or change for more.
for msg in client.iter_messages(chat, 10):
print(msg.sender.first_name, ':', msg.text)
Applying any formatting is still possible but hasattr is no longer needed. if msg.media for example would be enough to check if the message has media.
A note, if you're using Jupyter, you need to use async directly:
from telethon import TelegramClient
client = TelegramClient('session_id', api_id, api_hash)
# Note `async with` and `async for`
async with client:
async for msg in client.iter_messages(chat, 10):
print(msg.sender.first_name, ':', msg.text)
Now, you can use TDesktop to export chats.
Here is the blog post about Aug 2018 update.
Original Answer:
Telegram MTProto is hard to use to newbies, so I recommend telegram-cli.
You can use third-party tg-export script, but still not easy to newbies too.
You can use the Telethon library. for this you need to register your app and connect your client code to it (look at this).
Then to obtain message history of a entry (such as channel, group or chat):
from telethon.sync import TelegramClient
from telethon.errors import SessionPasswordNeededError
client = TelegramClient(username, api_id, api_hash, proxy=("socks5", proxy_ip, proxy_port)) # if in your country telegram is banned, you can use the proxy, otherwise remove it.
client.start()
# for login
if not client.is_user_authorized():
client.send_code_request(phone)
try:
client.sign_in(phone, input('Enter the code: '))
except SessionPasswordNeededError:
client.sign_in(password=input('Password: '))
async for message in client.iter_messages(chat_id, wait_time=0):
messages.append(Message(message))
# write your code

Categories