Telethon is not sending video as round even if video_note = True - bots

I tried it with different videos and it won't work. :/
In the docs they clearly say I should do:
await client.send_file(entity = "chat", file="C:\\Users\fold\to\video.mp4", video_note = True)
But it won't work. :/

entity should be the phone number or userid of the recipient.

To make a long story short.
The code explanes itself.
And, of course, your video must be of the appropriate format.
from telethon import TelegramClient, sync, events
api_id = xxx
api_hash = 'xxx'
client = TelegramClient('session', api_id, api_hash)
# send any message to your bot
#client.on(events.NewMessage())
async def my_event_handler(event):
# the telethon bot can be subscribed to your channel
if event.message.peer_id.to_dict()['_'] == 'PeerChannel':
actual_id = event.message.peer_id.to_dict()['channel_id']
if event.message.peer_id.to_dict()['_'] == 'PeerUser':
actual_id = event.message.peer_id.to_dict()['user_id']
await client.send_message(actual_id, message = 'Here we go')
file_path = 'C:/Users/fold/to/video.mp4' # make sure the path exists
await client.send_file(actual_id, file=file_path, video_note=True)
client.start()
client.run_until_disconnected()

Related

Print the list of members in a voice channel

i'm coding a discord bot and I need a function that kick all members in my channel. I wrote this code:
#client.command()
async def separaci(ctx):
canale = ctx.message.author.voice.channel
utenti = canale.members #This return an empty list
for utente in utenti:
await utente.edit(voice_channel = None)
I don't know why canale.members return an empty list. Can you help me? Thanks you :)
Try this:
#client.command()
async def separaci(ctx):
if ctx.author.voice: # if the author is connected to a voice channel
canale = ctx.message.author.voice.channel
utenti = canale.members #This return an empty list
for utente in utenti:
await utente.edit(voice_channel = None)
await ctx.send("Kicked all the members from the voice channel!")
else:
await ctx.send("You need to be in a voice channel!")
return
NOTE:
You need to be in a voice channel while using this command.
Make sure the bot has the permission to disconnect the members present in the voice channel.
Make sure you have the members intent enabled in your developer portal.
You have to enable member intents, also make sure to enable them in the developer portal
intents = discord.Intents.default()
intents.members = True
client = commands.Bot(command_prefix='', intents=intents)
#client.command()
async def separaci(ctx):
channel = ctx.author.voice.channel
members = channel.members
A Primer Gateway to Intents

Discord.py grabbing twitch URL without an API

I have a discord bot.
What I want it to do is when the bot detects a user is streaming, print the URL of their stream into chat.
I'm having a problem trying to find out how to get the user's twitch channel url...
this is what I have
#client.event
async def on_member_update(before, after):
aname = after.display_name
aactivity = after.activity.type
mactivity = str(after.activities)
role = after.guild.get_role(736271867836498031)
channel = client.get_channel(736269005651836985)
memberinfo = after.activities.streaming.url
print(memberinfo)
if "Streaming name" in mactivity:
await after.add_roles(role)
await channel.send('{} has started streaming!'.format(after.display_name))
print(aname + " is streaming!")
else:
await after.remove_roles(role)
streamchannel = discord.Profile
await channel.send('{} is not streaming!'.format(after.display_name))
print(aname + " is not streaming.")
print('member updated status')
Is there something I'm missing? I don't know how at all to either find the URL of the streamer, or get it from their connect accounts.
Member objects have a Activity attribute. You can check if before.activity or after.activity is an instance of the Streaming class.
If so, the user either stopped or started streaming and we can send a message in channel:
from discord import Streaming
from discord.utils import get
#client.event
async def on_member_update(before, after):
if not before.activity.type == after.activity.type:
return
role = get(after.guild.roles, id=736271867836498031)
channel = get(after.guild.channels, id=736269005651836985)
if isinstance(after.activity, Streaming):
await after.add_roles(role)
await channel.send(f"{before.mention} is streaming on {activity.platform}: {activity.name}.\nJoin here: {activity.url}")
elif isinstance(before.activity, Streaming):
await after.remove_roles(role)
await channel.send(f'{after.mention} is no longer streaming!')
else:
return
Reference: discord.py documentation

Discord.py welcome message for multiple servers

I am making a discord bot that I plan on being in multiple servers. Each server will have a different welcome channel name and all that. I made the welcome message and I tried making the bot post the message in a channel called "welcome" which would solve this problem but didn't work. I thought about making a database that saves the channel id that the server owner sends to the bot under the server name/ID. The bot when triggered would match the server ID to one in the database then grab the channel id linked to the server id. But that would be a lot of coding in SQL or PostgreSQL which I would have to learn how to get the bot to save the sever id and channel id to the database, How to get the bot to match the server id's then grab the channel id and posting it the message to the server. There is no documentation on discord py bots and making welcome messages for different servers. I was wondering if there is a better way to do it and how would I do it?
What I have so far in relation to the welcome message.
import discord
import logging
import asyncio
import random
import time
import tweepy, discord
from discord.ext import commands
from discord.ext.commands import bot
#File Imports
from config import *
client = commands.Bot(command_prefix='sec.')
# logger = logging.getLogger('discord')
# logger.setLevel(logging.DEBUG)
# handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
# handler.setFormatter(logging.Formatter('%(name)s: %(message)s'))
# logger.addHandler(handler)
#client.event
async def on_ready():
print('Logged in as %s' % client.user.name)
while True:
presence = random.choice(['sec.help', 'Defending Servers'])
activity = discord.Game(name=(presence))
await client.change_presence(status=discord.Status.online, activity=activity)
await asyncio.sleep(7)
client.remove_command('help')
#client.event
async def on_member_join(member):
# Adds role to user
# role = discord.utils.get(member.server.roles, name='Member')
# await client.add_roles(member, role)
# Random embed color
range = [255,0,0]
rand = random.shuffle(range)
# Welcomes User
embed = discord.Embed(title="{}'s info".format(member.name), description="Welcome too {}".format(member.guild.name))
embed.add_field(name="Name", value=member.name, inline=True)
embed.add_field(name="ID", value=member.id, inline=True)
embed.add_field(name="Status", value=member.status, inline=True)
embed.add_field(name="Roles", value=member.top_role)
embed.add_field(name="Joined", value=member.joined_at)
embed.add_field(name="Created", value=member.created_at)
embed.set_thumbnail(url=member.avatar_url)
inlul = client.get_channel(CHANNEL_ID)
await inlul.send(inlul, embed=embed)
If you find any documentation on this I would love to read it. All I could find are for bots that are basic and has you enter a channel id.
If the bot is on a much smaller scale, say just a few servers, then I'd say using a json file to save a dictionary wouldn't be a bad idea.
You can save the Id of the top text channel as a default when the server joins the server and let them change what channel to use with commands, this can be done with the on_guild_join event
import json
#sets value in json to guild id upon the bot joining the guild
#client.event
async def on_guild_join(guild):
#loads json file to dictionary
with open("filename.json", "r") as f:
guildInfo = json.load(f)
guildInfo[guild.id] = guild.text_channels[0] #sets key to guilds id and value to top textchannel
#writes dictionary to json file
with open("filename.json", "w") as f:
json.dump(guildInfo, f)
#allows server members to set channel for welcome messages to send to
#client.command()
async def welcomeMessage(ctx):
with open("filename.json", "r") as f:
guildInfo = json.load(f)
guildInfo[ctx.message.guild.id] = ctx.message.channel.id #sets channel to send message to as the channel the command was sent to
with open("filename.json", "w") as f:
json.dump(guildInfo, f)
then just use
with open("filename.json", "r"):
guildInfo = json.load(f)
channnel = guildInfo[ctx.message.guild.id]
to get the channel to send the message to and
channel.send(embed=embed)
to send the message
before running it ensure to have an empty json file in the same directory and add {} to the file.

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

Send messages to telegram group without user input

I'm trying to build a bot which automatically sends a message whenever there is an update in the latest news using python. Following is what I did.
companies = {
"name_1": {
"rss": "name_1 rss link",
"link": "name_1 link"
}
}
import feedparser as fp
import time, telebot
token = <TOKEN>
bot = telebot.TeleBot(token)
LIMIT = 1
while True:
def get_news():
count = 1
news = []
for company, value in companies.items():
count = 1
if 'rss' in value:
d = fp.parse(value['rss'])
for entry in d.entries:
if hasattr(entry, 'published'):
if count > LIMIT:
break
news.append(entry.link)
count = count + 1
return (news)
val = get_news()
time.sleep(10)
val2 = get_news()
try:
if val[0]!=val2[0]:
bot.send_message(chat_id= "Hardcoded chat_id", text=val2[0])
except Exception:
pass
How can I update my code so that the bot publishes the latest news to all the groups to which it is added?
I got the chat_id using:
bot.get_updates()[-1].message.chat.id
Any suggestions on how to automate this?
Using the python-telegram-bot api, you can send a message like this
bot.send_message(id, text='Message')
you need the "bot" and "id"
I keep these in a dictionary called "mybots" which I fill/update when people interact with the bot for the first time / or on later communication with the bot. It's possible to pickle this dictionary to keep it persistant.
mybots = {}
def start(bot, update):
"""Send a message when the command /start is issued."""
mybots[update.message.chat_id] = bot
update.message.reply_text('Hello{}!'.format(
update.effective_chat.first_name))
def send_later():
for id, bot in mybots.items():
bot.send_message(id, text='Beep!')
In short, you can use sendMessage() to send message to a specific group or user.
bot.sendMessage(chat_id=chat_id, text=msg)
the complete code,
import telegram
#token that can be generated talking with #BotFather on telegram
my_token = ''
def send(msg, chat_id, token=my_token):
"""
Send a message to a telegram user or group specified on chatId
chat_id must be a number!
"""
bot = telegram.Bot(token=token)
bot.sendMessage(chat_id=chat_id, text=msg)

Resources