mirror of
https://github.com/abdellahaski/Telegram-To-Discord-Bot.git
synced 2025-12-07 19:09:56 +00:00
First Commit
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -127,3 +127,6 @@ dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
*.session
|
||||
*.session-journal
|
||||
config.json5
|
||||
36
README.md
36
README.md
@@ -1,2 +1,34 @@
|
||||
# Telegram-To-Discord-Bot
|
||||
Telegram-To-Discord-Bot
|
||||
# Telegram-To-Discord
|
||||
Forward message from the specified Telegram channel to Discord Webhooks with all the media
|
||||
|
||||
### Requirements
|
||||
1. Python 3.6+
|
||||
2. Telegram APPID and HASH (can be created from here https://core.telegram.org/api/obtaining_api_id)
|
||||
3. Have a Telegram account with valid phone number
|
||||
4. Discord webhooks for the channels you to forward to
|
||||
|
||||
### Installing and Setup
|
||||
|
||||
1. Clone this repository `git clone https://github.com/abdellahaski/Telegram-To-Discord-Bot.git`.
|
||||
2. Open your choice of console (or Anaconda console) and navigate to cloned folder `cd Telegram-To-Discord-Bot.git`.
|
||||
3. Run Command: `pip3 install -r requirements.txt`.
|
||||
4. Rename `example.env` and `example.config.json5` to `.env` and `config.json5` respectively
|
||||
5. Fill out the .env and config.json5 files
|
||||
6. Run the bot by this command: `python3 main.py`
|
||||
|
||||
#### Filling `.env` file
|
||||
* Add your Telegram `api_id` and `api_hash` to the `.env` file | Read more [here](https://core.telegram.org/api/obtaining_api_id)
|
||||
* Specify an existing temporary directory to the `DLLOC` variable (e.g.: C:/tmp or /tmp)
|
||||
* Specify the text to append to each of the forwarded messages in the `TEXT_TO_PREPEND` variable (it can be a ping (`@everyone`, `@here`, or `@role`) and it can be a text or emojies like `:point_right:`)
|
||||
|
||||
|
||||
#### Filling `config.json5` file
|
||||
The ``config.json5` file contains a JSON array (list) of Telegram channel you want to forward messages from all along with specific configuration for each TG channel:
|
||||
|
||||
* `TGchannelID` : Telegram ID of the channel that you want to forward from (you can get it by forwarding any message from that channel to [@jsondumpbot](https://t.me/jsondumpbot)) don't forget to remove the first part (-100) from the ID
|
||||
* `senderAvatarUrl` : The avatar URL that will be shown on Discord sender profile (if it's empty it will be pulled automatically from the Telegram channel profile picture)
|
||||
* `senderName` : The sender name that will be shown on Discord sender profile (if it's empty it will default to the Telegram channel name)
|
||||
* `DiscordWebhooks` : Contains a list of the Discord webhooks that you want messages to be forwarded to
|
||||
```
|
||||
You can have as many TG channels as you want forwarding message to as many as Discord webhooks you want
|
||||
```
|
||||
|
||||
21
example.config.json5
Normal file
21
example.config.json5
Normal file
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"TGchannelID":"1594095970", //Telegram channel 1
|
||||
"senderAvatarUrl":"https://i.imgur.com/j8ixDXF.jpg", // Sender Avatar that will be visible on Discord (if it's not provided it will be pulled automatically from Telegram)
|
||||
"senderName":"", // Sender name that will be visible on Discord (if not provided it will defautl to the Telegram channel name)
|
||||
"discordWebhooks":
|
||||
[// Discord webhooks to forward to from this TG channel
|
||||
"https://discord.com/api/webhooks/123",
|
||||
"https://discord.com/api/webhooks/456"
|
||||
]
|
||||
},
|
||||
{
|
||||
"TGchannelID":"1786421862", //telegram channel 2
|
||||
"senderAvatarUrl":"https://i.imgur.com/8EpbciV.png",// Sender Avatar that will be visible on Discord (if it's not provided it will be pulled automatically from Telegram)
|
||||
"senderName":"",// Sender name that will be visible on Discord (if not provided it will defautl to the Telegram channel name)
|
||||
"discordWebhooks":
|
||||
[ // Discord webhooks to forward to from this TG channel
|
||||
"https://discord.com/api/webhooks/678"
|
||||
]
|
||||
}
|
||||
]
|
||||
7
example.env
Normal file
7
example.env
Normal file
@@ -0,0 +1,7 @@
|
||||
#APPID AND HASH https://core.telegram.org/api/obtaining_api_id
|
||||
APPID = "123"
|
||||
APIHASH = "bcdddexample123123" #
|
||||
APINAME = "Telegram To Discord" # Any string will do
|
||||
DLLOC = 'C:\tmp' # Temp storage for media, if able use a location in memory (unix)
|
||||
|
||||
TEXT_TO_PREPEND="@here \n" #Text to prepend to every message, it can be a ping (@everyone, @here, or @role) and it can be a text or emojies like ":point_right:"
|
||||
173
main.py
Normal file
173
main.py
Normal file
@@ -0,0 +1,173 @@
|
||||
from telethon import TelegramClient, events
|
||||
import aiohttp
|
||||
import nextcord
|
||||
import textwrap
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
import json5
|
||||
import random
|
||||
import validators
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
path = os.path.join(os.path.dirname(__file__), 'config.json5')
|
||||
with open(path) as fp:
|
||||
config = json5.load(fp)
|
||||
|
||||
#print(json5.dumps(config))
|
||||
appid = os.environ.get("APPID")
|
||||
apihash = os.environ.get("APIHASH")
|
||||
apiname = os.environ.get("APINAME")
|
||||
dlloc = os.environ.get("DLLOC")
|
||||
text_to_prepend=os.environ.get("TEXT_TO_PREPEND")
|
||||
|
||||
channels_avatars={}
|
||||
|
||||
#if input_channels_entities is not None:
|
||||
# input_channels_entities = list(map(int, input_channels_entities.split(',')))
|
||||
input_channels_entities=[]
|
||||
for channel in config:
|
||||
input_channels_entities.append(int(channel["TGchannelID"]))
|
||||
|
||||
|
||||
|
||||
async def imgurimg(mediafile): # Uploads image to imgur
|
||||
url = "https://api.imgur.com/3/upload"
|
||||
|
||||
payload = {
|
||||
'type': 'file'}
|
||||
files = [
|
||||
('image', open(mediafile, 'rb'))
|
||||
]
|
||||
headers = {
|
||||
'Authorization': str(random.randint(1,10000000000))
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data = payload, files = files)
|
||||
return(json.loads(response.text))
|
||||
|
||||
async def imgur(mediafile): # Uploads video to imgur
|
||||
url = "https://api.imgur.com/3/upload"
|
||||
|
||||
payload = {'album': 'ALBUMID',
|
||||
'type': 'file',
|
||||
'disable_audio': '0'}
|
||||
files = [
|
||||
('video', open(mediafile,'rb'))
|
||||
]
|
||||
headers = {
|
||||
'Authorization': str(random.randint(1,10000000000))
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data = payload, files = files)
|
||||
return(json.loads(response.text))
|
||||
|
||||
def start():
|
||||
client = TelegramClient(apiname,
|
||||
appid,
|
||||
apihash)
|
||||
client.start()
|
||||
print('Started')
|
||||
print('Listenning to the following Telegram Channels: '+str(input_channels_entities))
|
||||
|
||||
@client.on(events.NewMessage(chats=input_channels_entities))
|
||||
async def handler(event):
|
||||
channelID=str(event.chat.id)
|
||||
for channel in config:
|
||||
if str(channel["TGchannelID"]) == channelID:
|
||||
senderAvatarUrl=channel["senderAvatarUrl"]
|
||||
senderName=channel["senderName"]
|
||||
DiscordWebhooks=channel["discordWebhooks"]
|
||||
|
||||
if DiscordWebhooks is None:
|
||||
print('channel (id:'+channelID+') not configured correctly, please check the config.json5 file')
|
||||
return
|
||||
|
||||
if not senderName or senderName is None or senderName=='':
|
||||
senderName=event.chat.title
|
||||
|
||||
if(senderAvatarUrl is not None and validators.url(senderAvatarUrl)):
|
||||
channels_avatars[channelID]=senderAvatarUrl
|
||||
channelAvatarUrl=senderAvatarUrl
|
||||
else:
|
||||
#Checking if the channel avatar is already in the avatar list
|
||||
if(channelID in channels_avatars):
|
||||
channelAvatarUrl=channels_avatars[channelID]
|
||||
else: # if not we download it and upload it to imgur (since discord accept only avartar urls)
|
||||
channel = await client.get_entity(event.chat.id)
|
||||
channelAvatar = await client.download_profile_photo(channel,dlloc, download_big=False)
|
||||
channelAvatarUrl=await imgurimg(channelAvatar)
|
||||
os.remove(channelAvatar)
|
||||
channelAvatarUrl = channelAvatarUrl['data']['link']
|
||||
channels_avatars[channelID]=channelAvatarUrl # we store it on the channels avatars array so we can use it another time without reuploading to imgur
|
||||
|
||||
msg = event.message.message
|
||||
#Looking for href urls in the text message and appending them to the message
|
||||
try:
|
||||
for entity in event.message.entities:
|
||||
if ('MessageEntityTextUrl' in type(entity).__name__):
|
||||
msg +=f"\n\n{entity.url}"
|
||||
except:
|
||||
print("no url captured, forwording message")
|
||||
|
||||
if event.message.media is not None:
|
||||
|
||||
if('MessageMediaWebPage' in type(event.message.media).__name__):# directly send message if the media attached is a webpage embed
|
||||
for webhookUrl in DiscordWebhooks:
|
||||
await send_to_webhook(msg,senderName,channelAvatarUrl,webhookUrl)
|
||||
else:
|
||||
dur = event.message.file.duration # Get duration
|
||||
if dur is None:
|
||||
dur=1 # Set duration to 1 if media has no duration ex. photo
|
||||
# If duration is greater than 60 seconds or file size is greater than 200MB
|
||||
if dur>60 or event.message.file.size > 209715201: # Duration greater than 60s send link to media
|
||||
print('Media too long!')
|
||||
msg +=f"\n\nLink to Video: https://t.me/c/{event.chat.id}/{event.message.id}"
|
||||
for webhookUrl in DiscordWebhooks:
|
||||
await send_to_webhook(msg,senderName,channelAvatarUrl,webhookUrl)
|
||||
return
|
||||
else: # Duration less than 60s send media
|
||||
path = await event.message.download_media(dlloc)
|
||||
for webhookUrl in DiscordWebhooks:
|
||||
await pic(path,msg,senderName,channelAvatarUrl,webhookUrl)
|
||||
|
||||
os.remove(path)
|
||||
else: # No media text message
|
||||
for webhookUrl in DiscordWebhooks:
|
||||
await send_to_webhook(msg,senderName,channelAvatarUrl,webhookUrl)
|
||||
|
||||
client.run_until_disconnected()
|
||||
|
||||
async def pic(filem,message,username,channelAvatarUrl,webhookUrl): # Send media to webhook
|
||||
if(text_to_prepend is not None):
|
||||
message=text_to_prepend+message
|
||||
async with aiohttp.ClientSession() as session:
|
||||
print('Sending w media')
|
||||
webhook = nextcord.Webhook.from_url(webhookUrl, session=session)
|
||||
try: # Try sending to discord
|
||||
f = nextcord.File(filem)
|
||||
await webhook.send(file=f,username=username,avatar_url=channelAvatarUrl)
|
||||
except: # If it fails upload to imgur
|
||||
print('File too big, uploading to imgur')
|
||||
try:
|
||||
image = await imgur(filem) # Upload to imgur
|
||||
#print(image)
|
||||
image = image['data']['link']
|
||||
print(f'Imgur: {image}')
|
||||
await webhook.send(content=image,username=username,avatar_url=channelAvatarUrl) # Send imgur link to discord
|
||||
except Exception as ee:
|
||||
print(f'Error {ee.args}')
|
||||
for line in textwrap.wrap(message, 2000, replace_whitespace=False): # Send message to discord
|
||||
await webhook.send(content=line,username=username,avatar_url=channelAvatarUrl)
|
||||
|
||||
async def send_to_webhook(message,username,channelAvatarUrl,webhookUrl): # Send message to webhook
|
||||
if(text_to_prepend is not None):
|
||||
message=text_to_prepend+message
|
||||
async with aiohttp.ClientSession() as session:
|
||||
print('Sending w/o media')
|
||||
webhook = nextcord.Webhook.from_url(webhookUrl, session=session)
|
||||
for line in textwrap.wrap(message, 2000, replace_whitespace=False): # Send message to discord
|
||||
await webhook.send(content=line,username=username,avatar_url=channelAvatarUrl)
|
||||
|
||||
if __name__ == "__main__":
|
||||
start()
|
||||
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
aiohttp==3.8.1
|
||||
json5==0.9.10
|
||||
nextcord==2.1.0
|
||||
nextcord_ext_menus==1.5.4
|
||||
python-dotenv==0.20.0
|
||||
requests==2.28.1
|
||||
Telethon==1.24.0
|
||||
validators==0.20.0
|
||||
Reference in New Issue
Block a user