Read public channel texts using Telegram API - python-3.x

I would like to create a small script that will fetch Telegram texts from a public channel (I am not the channel's admin).
I've found another question asked here:
Read the messages of the public channels from Telegram
I've tried using Telethon as said in the answer, but it didn't work:
from telethon.tl.functions.contacts import ResolveUsernameRequest
import telethon
client = telethon.TelegramClient("session.txt", api_id=XYZ, api_hash='XYZ')
client.connect()
response = client.invoke(ResolveUsernameRequest("test"))
print(response.channel_id)
print(response.access_hash)
Throwing this error:
C:/Users/mypc/PycharmProjects/untitled/aa.py:5: RuntimeWarning: coroutine 'TelegramBaseClient.connect' was never awaited
client.connect()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Traceback (most recent call last):
File "C:/Users/mypc/PycharmProjects/untitled/aa.py", line 6, in <module>
response = client.invoke(ResolveUsernameRequest("test"))
AttributeError: 'TelegramClient' object has no attribute 'invoke'
I've tried reading the API documentation, but I didn't fully understand how those calls work:
https://core.telegram.org/method/channels.exportMessageLink
https://core.telegram.org/method/channels.joinChannel
https://core.telegram.org/method/channels.getMessages
I'd be grateful if someone could explain to me how those work.

That answer is very old. If we check Telethon's Quick-Start we have enough code to do what you need:
from telethon import TelegramClient
# Remember to use your own values from my.telegram.org!
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('anon', api_id, api_hash)
async def main():
# You can print the message history of any chat:
async for message in client.iter_messages('USERNAME OF THE CHANNEL'):
print(message.sender.username, message.text)
with client:
client.loop.run_until_complete(main())

Well like it says, TelegramClient has no invoke method. Have you tried client(ResolveUsernameRequest("test"))?

Related

How do i await cogs in discord.py

I was trying to create a discord bot in python that will play music from YouTube. But when i run this script, it shows the bot is online but if i enter a command then it says command not found. gives me this warning everytime i run the script.
/bin/python3 "/home/r1d0m/Python/Discord Music Bot/main.py"
/home/r1d0m/Python/Discord Music Bot/main.py:15: RuntimeWarning: coroutine 'BotBase.add_cog' was never awaited
bot.add_cog(help_cog(bot))
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/home/r1d0m/Python/Discord Music Bot/main.py:16: RuntimeWarning: coroutine 'BotBase.add_cog' was never awaited
bot.add_cog(music_cog(bot))
And this is what i coded in main.py
import discord
from discord.ext import commands
from help_cog import help_cog
from music_cog import music_cog
intents = discord.Intents.all()
intents.message_content = True
bot = commands.Bot(command_prefix="/", intents = intents)
bot.remove_command("help")
bot.add_cog(help_cog(bot))
bot.add_cog(music_cog(bot))
with open('/home/r1d0m/Python/Discord Music Bot/token.txt') as redk:
contents = redk.read()
bot.run(contents)
I don't know what to do. please help.
I even tried to add this,
await bot.add_cog(help_cog(bot))
But it gives me error.
Try reading up on async-await for python. This is a good starting point.
Async IO in Python
await should always reside inside an async function.
eg snippet:
import discord
from discord.ext import commands
from help_cog import help_cog
from music_cog import music_cog
async def main():
...
await bot.add_cog(help_cog(bot))
await bot.add_cog(music_cog(bot))
with open('/home/r1d0m/Python/Discord Music Bot/token.txt') as redk:
contents = redk.read()
...
if __name__ == "__main__":
import asyncio
asyncio.run(main())

discord.py temporary voices

I am making my bot for discord, I want to do this, when a user clicks on a certain voice channel, a new voice channel is created for him, which is deleted upon exit. Here is the code:
import discord
from discord.ext import commands
from discord.utils import get
import asyncio
TOKEN = 'xxxx'
bot = commands.Bot(command_prefix='!')
#bot.event
async def on_voice_state_update(member, before, after):
if after.channel != None:
if after.channel.id == 700246237244555338:
for guild in bot.guilds:
maincategory = discord.utils.get(
guild.categories, id=700246237244555336)
channel2 = guild.create_voice_channel(name=f'канал {member.display_name}', category=maincategory)
await channel2.set_permissions(member, connect=True, mute_members=True, manage_channels=True)
await member.move_to(channel2)
def check(x, y, z):
return len(channel2.members) == 0
await bot.wait_for('voice_state_update', check=check)
await channel2.delete()
# RUN
bot.run(TOKEN)
But i have error...
Ignoring exception in on_voice_state_update
Traceback (most recent call last):
File "C:\Users\asus\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\client.py", line 333, in _run_event
await coro(*args, **kwargs)
File "jett.py", line 190, in on_voice_state_update
await member.move_to(channel2)
File "C:\Users\asus\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\member.py", line 626, in move_to
await self.edit(voice_channel=channel, reason=reason)
File "C:\Users\asus\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\member.py", line 592, in edit
payload['channel_id'] = vc and vc.id
AttributeError: 'coroutine' object has no attribute 'id'
C:\Users\asus\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\client.py:340: RuntimeWarning: coroutine 'Guild.create_voice_channel' was never awaited
pass
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Can you help me with this problem or just send me working code for temporary voices
RuntimeWarning: Enable tracemalloc to get the object allocation traceback usually means that you forgot to add an await keyword to an async function. The async function in question is likely create_voice_channel, as the documentation says it is an async function.
To fix this, you'll want to add the await keyword before the function call, similar to this:
channel2 = await guild.create_voice_channel(name=f'канал {member.display_name}', category=maincategory)

How to correctly await zmq response from within an async route

I am attempting to wait for a ZMQ message response from within a route but am getting the following error.
RuntimeError: Task got bad yield: <zmq.eventloop.future._TornadoFuture object at 0x7f74f4143c88>
The following code worked with ApiStar on an earlier version of our API coded against that framework but we have made a decision to move to Starlette now. The code below is included in a async def function.
import zmq
from zmq.eventloop.future import Context
import threading
zmq_context = zmq.eventloop.future.Context()
mysocket = zmq_context.socket(zmq.SUB)
mysocket.connect(f"tcp://{DB_HOST}:{DEFAULT_ZMQ_PORT}")
topicstring = 'niOSGOV6eAyUKOOVdXm0CA=='
topicfilter=bytes(topicstring, 'utf-8').decode()
mysocket.setsockopt_string(zmq.SUBSCRIBE, topicfilter)
all_responses = await mysocket.recv_multipart(flags=0, copy=True, track=False)
Thank you for any assistance!

How to send a message with discord.py from outside the event loop (i.e. from python-telegram-bot thread)?

I want to use make a bot that communicates between discord and telegram by using the libraries python-telegram-bot and discord.py (version 1.0.0). However the problem is that discord.py uses async functions and python-telegram-bot threading. With the code below, everything works fine for messages being posted in discord (the bot sends them correctly to telegram), however the other way around does not work (bot gets messages from telegram and sends it to discord). I previously had issues with syntax/runtime errors as I tried to run the discords channel.send function in a sync function (thus either returning only a generator object or complaining that I cannot use await in a sync function). However, at the same time the python-telegram-bot's MessageHandler needs a sync function so when giving him a async function Python complains that "await" was never called for the async function.
I now tried to use the async_to_sync method from asgiref library to run my async broadcastMsg from the MessageHandler, however the code still does not send the message to discord! It seems to call the function correctly but only until line print('I get to here'). No error is displayed and no message is poping up in discord. I guess it has something to do with the fact that I have to register the function as a task in the discord.py event loop, however registering is only working when it happens before botDiscord.run(TOKENDISCORD) has been executed which of course has to happen before.
So to boil my problem down to one question:
How am I able to interact with the discord.py event loop from another thread (which is from the telegram MessageHandler). Or if this is not possible: How can I send a message with discord.py without being within the discord.py event loop?
Thank you for your help
import asyncio
from asgiref.sync import async_to_sync
from telegram import Message as TMessage
from telegram.ext import (Updater,Filters,MessageHandler)
from discord.ext import commands
import discord
TChannelID = 'someTelegramChannelID'
DChannel = 'someDiscordChannelObject'
#%% define functions / commands
prefix = "?"
botDiscord = commands.Bot(command_prefix=prefix)
discordChannels = {}
async def broadcastMsg(medium,channel,message):
'''
Function to broadcast a message to all linked channels.
'''
if isinstance(message,TMessage):
fromMedium = 'Telegram'
author = message.from_user.username
channel = message.chat.title
content = message.text
elif isinstance(message,discord.Message):
fromMedium = 'Discord'
author = message.author
channel = message.channel.name
content = message.content
# check where message comes from
textToSend = '%s wrote on %s %s:\n%s'%(author,fromMedium,channel,content)
# go through channels and send the message
if 'telegram' in medium:
# transform channel to telegram chatID and send
updaterTelegram.bot.send_message(channel,textToSend)
elif 'discord' in medium:
print('I get to here')
await channel.send(textToSend)
print("I do not get there")
#botDiscord.event
async def on_message(message):
await broadcastMsg('telegram',TChannelID,message)
def on_TMessage(bot,update):
# check if this chat is already known, else save it
# get channels to send to and send message
async_to_sync(broadcastMsg)('discord',DChannel,update.message)
#%% initialize telegram and discord bot and run them
messageHandler = MessageHandler(Filters.text, on_TMessage)
updaterTelegram = Updater(token = TOKENTELEGRAM, request_kwargs={'read_timeout': 10, 'connect_timeout': 10})
updaterTelegram.dispatcher.add_handler(messageHandler)
updaterTelegram.start_polling()
botDiscord.run(TOKENDISCORD)
How can I send a message with discord.py without being within the discord.py event loop?
To safely schedule a coroutine from outside the event loop thread, use asyncio.run_coroutine_threadsafe:
_loop = asyncio.get_event_loop()
def on_TMessage(bot, update):
asyncio.run_coroutine_threadsafe(
broadcastMsg('discord', DChannel, update.message), _loop)
you can try split them to 2 separates *.py files.
t2d.py #telegram to discor
import subprocess
from telethon import TelegramClient, events, sync
api_id = '...'
api_hash = '...'
with TelegramClient('name', api_id, api_hash) as client:
#client.on(events.NewMessage()) #inside .NewMessage() you can put specific channel like: chats="test_channel"
async def handler(event):
print('test_channel raw text: ', event.raw_text) #this row is not necessary
msg = event.raw_text
subprocess.call(["python", "s2d.py", msg])
client.run_until_disconnected()
s2d.py #send to discord
import discord, sys
my_secret = '...'
clientdiscord = discord.Client()
#clientdiscord.event
async def on_ready():
#print('We have logged in as {0.user}'.format(clientdiscord)) #this row is not necessary
channel = clientdiscord.get_channel(123456789) # num of channel where you want to write message
msg = sys.argv[1] #grab message
msg = 's2d: ' + msg #only for test, you can delete this row
await channel.send(msg)
quit() # very important quit this bot
clientdiscord.run(my_secret)
It will be a little bit slower (subprocess will make delay), but very easy solution

Tornado unexpected exception in Future <Future cancelled> after timeout

I have set up a dask cluster. I can access a web dashboard, but when I'm trying to connect to the scheduler:
from dask.distributed import Client
client = Client('192.168.0.10:8786')
I get the following error:
tornado.application - ERROR - Exception in Future <Future cancelled> after timeout
Traceback (most recent call last):
File "/home/user/venv/lib/python3.5/site-packages/tornado/gen.py", line 970, in error_callback
future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 285, in result
raise CancelledError
concurrent.futures._base.CancelledError
Also, when I'm trying to execute some tasks on the cluster, all tasks are computed correctly and the result is fetched but then the above error occurs at the end.
Do you have any ideas how to fix it? I think it's a client problem, but where. Thank you very much.
You are running sync function in async tornado
Try this one:
from dask.distributed import Client
from tornado.ioloop import IOLoop
async def f():
client = await Client(address='192.168.0.10:8786', asynchronous=True)
future = client.submit(DO SOMETHING HERE)
result = await future
await client.close()
return result
IOLoop().run_sync(f)

Resources