Creating a Telegram Bot Using Python (Downloading and Sending Videos/Audio from YouTube)
Creating a Telegram Bot Using Python (Downloading and Sending Videos/Audio from YouTube)
Hello friends, I’m here with a rather lengthy post. Actually, it’s not that long, but since I want to explain some of the code in this project and the working principles, it will get extended.
In this project, we will write a bot for Telegram using Python. This bot will receive messages via Telegram, search YouTube, show the results to the user, and then send the selected video/song as a file to them.
Additionally, we will keep statistics such as the number of searches, the number of audio/video files downloaded, and the number of unique users who use the bot in a simple database system (sqlite). Finally, we will also have a very basic log system that simply serves errors to us as a ".txt" file.
Don't worry about the messiness of the code, as I will share the whole code as one unit on GitHub at the bottom of the page.
Starting the Project
Python Libraries Used in Our Project
- sqlite3
- We use it to create a database and to keep statistics.
- python-telegram-bot
- We use it to receive and send messages with Telegram.
- pytube
- We use it to search and perform downloads on YouTube.
- termcolor
- We use it for coloring in the terminal.
Summary of Scripts Used in the Project
- Base.py
- The script that combines all scripts and allows us to use the scripts in a simpler and more understandable way.
- ColoredPrint.py
- This script contains functions that we created for printing colored text in the terminal.
- DBManager.py
- The script containing the functions related to database operations.
- LogManager.py
- The script we created for keeping log records.
- Settings.py
- Our script that maintains the settings.
- TelegramBot.py
- The script that enables us to communicate with Telegram.
- YouTubeManager.py
- The script where we perform operations related to YouTube.
- MailManager.py
- The script that contains functions we can use to send emails.
- Currently, I’m not using this script, but if I do such a project in the future, I prepared this page to automatically email statistics/errors.
- Videos
- This is the folder where the videos are downloaded.
- Audios
- This is the folder where the audios are downloaded.
- Logs
- This is the folder where the log records are stored.
Project Code (Scripts)
Settings.py
# This project created by urhoba
# www.urhoba.net
#region DB Settings
class DBSettings: # We created a class for database settings.
sqliteDB = "db.urhoba" # inside this class we define the name of our sqlite database file.
#endregion
#region Mail Settings
class MailSettings: # We created a class for sending mail.
fromMail = "ahmetbohur@urhoba.net" # the username of our SMTP mail.
fromPassword = "" # the password of our SMTP mail.
smtpHost = "smtp.yandex.com" # the provider/server for our SMTP mail.
smtpPort = 465 # the port address of our SMTP mail.
#endregion
#region Download Settings
class DownloadSettings: # Settings for downloaded files.
musicFolder = "songs" # The folder name for downloaded audio files.
videoFolder = "videos" # The folder name for downloaded video files.
#endregion
#region Telegram Settings
class TelegramSettings: # Our class for Telegram settings.
telegramAPI = "" # We write our Telegram API address here.
#endregion
ColoredPrint.py
from termcolor import colored # we import colored from the termcolor library.
#region Green Print
def GreenPrint(text): # We create a function to print in green.
print(colored(text, 'green')) # We print the incoming text in green.
#endregion
#region Red Print
def RedPrint(text): # We create a function to print in red.
print(colored(text, 'red')) # We print the incoming text in red.
#endregion
LogManager.py
# This project created by urhoba
# www.urhoba.net
from datetime import date, datetime # Library we use to get the time information of when the error occurred.
import locale # Library for outputting time information in system language.
import os # Library for file operations.
import ColoredPrint # Library for also printing error to terminal.
#region Locale Settings
locale.setlocale(locale.LC_ALL, '') # We set the time info to be in system language.
#endregion
class LogManager: # We create a class called LogManager
#region Init
def __init__(self, logFileName) -> None: # When calling this class, we want the file name to create an error file.
self._logFileName = logFileName # we write the file name
#endregion
#region Add Log
def AddLog(self, errorText): # We create a function called AddLog(errorMessage).
_nowTime = datetime.now() # We get the date.
_nowTime = datetime.strftime(_nowTime, "%c") # Make the date a string.
logFile = open(os.getcwd()+"/logs/"+self._logFileName + ".txt", "a") # We create the log file.
try:
with logFile as f: # We open the log file.
f.write(f"\nDate : {_nowTime}\nError: {errorText}\n") # We write the new error at the bottom of the log file.
ColoredPrint.RedPrint(f'Date : {_nowTime}\nError: {errorText}\n') # We print the error to the screen.
except:
ColoredPrint.RedPrint("An issue occurred while creating the Log!") # If an error occurs during log file creation, we print to screen.
finally:
logFile.close() # We close the log file.
#endregionYouTubeManager.py
# This project created by urhoba
# www.urhoba.net
from pytube import YouTube # Library for downloading video/audio from YouTube via PyTube.
from pytube import Search # Library for searching on YouTube via PyTube.
import ssl # SSL library, we use this on MAC devices to fix PyTube SSL errors.
import os # Library for file operations.
import os.path # Specifically the library I use to check if a file exists.
import re # Library for detecting REGEX (I haven’t used it here yet but I may at any time. If unused in your project, remember to remove it for output!)
from LogManager import LogManager # We import our LogManager script.
from Settings import DownloadSettings # We import the DownloadSettings class from our Settings script.
import ColoredPrint # We import our class for printing colored text to the screen.
#region SSL Settings
ssl._create_default_https_context = ssl._create_stdlib_context # We fix the MAC device SSL error here.
#endregion
class YouTubeManager:
#region Init
def __init__(self) -> None:
self.logManager = LogManager("YouTubeManagerLog") # We create logManager to create log record by using our LogManager class.
#endregion
#region Search Modules
def SearchVideo(self, searchQuery): # We created a function to perform searches and asked for the searchQuery value.
try:
search = Search(searchQuery) # We search on YouTube and if there is no problem, assign the result to search.
return search.results # We return the results with search.result.
except:
self.logManager.AddLog(f"An issue occurred while searching for video! \nSearch query : {searchQuery}") # If there is an error, we add to the log with logManager
ColoredPrint.RedPrint(f"An issue occurred while searching for video! \nSearch query : {searchQuery}") # Uselessly, we also print to the screen. (I call it useless because logManager already handles this.)
#endregion
#region File Modules
def FileCheck(self, file): # We create a function to check if file exists, we send the file path here.
if os.path.isfile(file) and os.access(file, os.R_OK): # We check if file exists.
return True # If file exists
else: # if not
return False # returns False.
def DeleteFile(self, file): # We create a delete function so that files do not use up space on the server.
os.remove(file) # We delete the file.
def FileNameFormatter(self, name): # Some operating systems do not support certain characters (e.g. /\) so we use this function for formatting.
validFileName = "".join([c for c in name if c.isalpha() or c.isdigit() or c==' ']).rstrip() # We remove unsupported characters.
return validFileName # Return formatted name.
#endregion
#region Download Modules
def DownloadVideo(self, videoURL): # We create a function to download video. Important point: we send the video hash value to this function. For example: watch?v=YXwSDEG3pTQ, the YXwSDEG3pTQ part in the url is what you use for YouTube videos.
try:
youtube = YouTube(f"https://www.youtube.com/watch?v={videoURL}") # We fetch video information.
videoTitle = youtube.title # We get the video title.
fileName = self.FileNameFormatter(videoTitle) + ".mp4" # We check the video name and add it to our variable.
if self.FileCheck(DownloadSettings.videoFolder+"/"+fileName) == False: # We check if file exists.
youtube.streams.get_highest_resolution().download(output_path=DownloadSettings.videoFolder, filename=fileName) # If not, we download.
return videoTitle, videoURL, DownloadSettings.videoFolder + "/" + fileName # We send the video title, url and file path.
except:
self.logManager.AddLog(f"An issue occurred while downloading video! \nVideo link : {videoURL}") # On error, we log.
ColoredPrint.RedPrint(f"An issue occurred while downloading video! \nVideo link : {videoURL}") # We print to screen.
return False # If error, return False.
def DownloadAudio(self, songURL): # Function to download audio.
try:
youtube = YouTube(f"https://www.youtube.com/watch?v={songURL}") # We get the video info.
songTitle = youtube.title # We get video title.
fileName = self.FileNameFormatter(songTitle) + ".mp4" # We check the video title.
if self.FileCheck(DownloadSettings.musicFolder+"/"+fileName) == False: # We check if file exists.
youtube.streams.get_audio_only().download(output_path=DownloadSettings.musicFolder, filename=fileName) # If there isn't one, we download.
return songTitle, songURL,DownloadSettings.musicFolder + "/" + fileName # Return values like in video function.
except:
self.logManager.AddLog(f"An issue occurred while downloading audio! \nAudio link : {songURL}") # On error, we log.
ColoredPrint.RedPrint(f"An issue occurred while downloading audio! \nAudio link : {songURL}") # We print to screen.
return False # If there is an error, return False.
#endregion
DBManager.py
# This project created by urhoba
# www.urhoba.net
import sqlite3 # We use SQLite3 as the database, so we import the library.
from sqlite3.dbapi2 import Cursor # This is an unused library (automatically created). Remove if not used.
from LogManager import LogManager # We import our logManager script for errors.
from Settings import DBSettings # We import the DBSettings class from our settings script.
import ColoredPrint # We import our class for printing colored text.
class DBManager:
#region Init
def __init__(self) -> None: # When DBManager is called.
self._CreateVideoDB() # Call the function to create the video db.
self._CreateAudioDB() # Call the function for audio db.
self._CreateUserDB() # Call the function for user db.
self._CreateBotStatsDB() # Call the function for bot stats.
self.logManager = LogManager("DBManagerLog") # Create logManager for logging.
#endregion
#region Connect
def _Connect(self): # Function to connect to the db.
self.db = sqlite3.connect(DBSettings.sqliteDB) # Create db variable and connect.
ColoredPrint.GreenPrint("Connected to database.") # Indicate connection.
#endregion
#region Create DB Modules # DB create functions.
def _CreateVideoDB(self): # Function to create video db.
try:
self._Connect() # Connect to db.
cursor = self.db.cursor() # Create cursor.
sqlQuery = "CREATE TABLE IF NOT EXISTS videos (videoTitle, videoID, videoFile, videoDownloadCount)" # SQL query
cursor.execute(sqlQuery) # Create db.
ColoredPrint.GreenPrint("Video db created.") # Indicate creation. (If db exists, doesn't recreate but prints created.)
except:
self.logManager.AddLog("An error occurred while creating video db!") # If error, log.
ColoredPrint.RedPrint("An error occurred while creating video db!") # Print to screen.
finally:
self.db.close() # Close db connection.
# All db create functions above repeat same logic, so not explained again below.
def _CreateAudioDB(self):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "CREATE TABLE IF NOT EXISTS audios (audioTitle, audioID, audioFile, audioDownloadCount)"
cursor.execute(sqlQuery)
ColoredPrint.GreenPrint("Audio db created.")
except:
self.logManager.AddLog("An error occurred while creating audio db!")
ColoredPrint.RedPrint("An error occurred while creating audio db!")
finally:
self.db.close()
def _CreateUserDB(self):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "CREATE TABLE IF NOT EXISTS users (userID, userName, userVideoDownloadCount, userAudioDownloadCount, userSearchCount)"
cursor.execute(sqlQuery)
ColoredPrint.GreenPrint("User db created.")
except:
self.logManager.AddLog("An error occurred while creating user db!")
ColoredPrint.RedPrint("An error occurred while creating user db!")
finally:
self.db.close()
def _CreateBotStatsDB(self):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "CREATE TABLE IF NOT EXISTS stats (botID, audioDownloadCount, videoDownloadCount, searchCount, userCount)"
cursor.execute(sqlQuery)
ColoredPrint.GreenPrint("Stats db created.")
except:
self.logManager.AddLog("An error occurred while creating stats db!")
ColoredPrint.RedPrint("An error occurred while creating stats db!")
finally:
self.db.close()
#endregion
#region Add Modules # Functions for adding data to created dbs.
def AddVideo(self, videoTitle, videoID, videoFile): # Function to add video
try:
self._Connect() # Connect to db.
cursor = self.db.cursor() # Create cursor.
sqlQuery = "INSERT INTO videos (videoTitle, videoID, videoFile, videoDownloadCount) VALUES (?,?,?,?)" # SQL query
sqlValues = (videoTitle, videoID, videoFile, 1) # Get values.
cursor.execute(sqlQuery, sqlValues) # Add data.
self.db.commit() # Commit.
ColoredPrint.GreenPrint(f"Video added. \nVideo Title : {videoTitle} \nVideo ID : {videoID}") # Print to screen.
except: # If error, log and print screen.
self.logManager.AddLog(f"An error occurred while adding video to db! \nVideo Title : {videoTitle} \nVideo ID : {videoID}\nVideo File : {videoFile}")
ColoredPrint.RedPrint(f"An error occurred while adding video to db! \nVideo Title : {videoTitle} \nVideo ID : {videoID}\nVideo File : {videoFile}")
finally:
self.db.close() # Close db connection.
# All Add Modules repeat same logic as above, so not explained individually.
def AddAudio(self, audioTitle, audioID, audioFile):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "INSERT INTO audios (audioTitle, audioID, audioFile, audioDownloadCount) VALUES (?,?,?,?)"
sqlValues = (audioTitle, audioID, audioFile, 1)
cursor.execute(sqlQuery, sqlValues)
self.db.commit()
ColoredPrint.GreenPrint(f"Audio added. \nAudio Title : {audioTitle} \nAudio ID : {audioID}")
except:
self.logManager.AddLog(f"An error occurred while adding audio to db! \nAudio Title : {audioTitle} \nAudio ID : {audioID}\nAudio File : {audioFile}")
ColoredPrint.RedPrint(f"An error occurred while adding audio to db! \nAudio Title : {audioTitle} \nAudio ID : {audioID}\nAudio File : {audioFile}")
finally:
self.db.close()
def AddUser(self, userID, userName):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "INSERT INTO users (userID, userName, userVideoDownloadCount, userAudioDownloadCount, userSearchCount) VALUES (?,?,?,?,?)"
sqlValues = (userID, userName, 0, 0, 0)
cursor.execute(sqlQuery, sqlValues)
self.db.commit()
ColoredPrint.GreenPrint(f"User added. \nUsername : {userName}\nUser ID : {userID}")
except:
self.logManager.AddLog(f"An error occurred while adding user to db! \nUser ID : {userID}\nUsername : {userName}")
ColoredPrint.RedPrint(f"An error occurred while adding user to db! \nUser ID : {userID}\nUsername : {userName}")
finally:
self.db.close()
def AddBot(self, botID = 1):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "INSERT INTO stats (botID, audioDownloadCount, videoDownloadCount, searchCount, userCount) VALUES (?,?,?,?,?)"
sqlValues = (botID, 0, 0, 0, 0)
cursor.execute(sqlQuery, sqlValues)
self.db.commit()
ColoredPrint.GreenPrint(f"Bot added. \nBot ID : {botID}")
except:
self.logManager.AddLog(f"An error occurred while adding bot to db! \nBot ID : {botID}")
ColoredPrint.RedPrint(f"An error occurred while adding bot to db! \nBot ID : {botID}")
finally:
self.db.close()
#endregion
#region Check Modules # Functions to check if data exists.
def CheckVideoWithVideoID(self, videoID): # Function to check if video exists in db by video ID.
try:
self._Connect() # Connect to db.
cursor = self.db.cursor() # Create cursor.
sqlQuery = "SELECT * FROM videos WHERE videoID = '%s'" % videoID # SQL by videoID
check = cursor.execute(sqlQuery).fetchall() # Search.
if len(check) > 0: # If check > 0, video exists.
return True # Return True.
else: # If check == 0
return False # Return False.
except: # Catch errors and return False.
self.logManager.AddLog(f"Issue occurred while checking video in db! \nvideo ID : {videoID}")
ColoredPrint.RedPrint(f"Issue occurred while checking video in db! \nvideo ID : {videoID}")
return False
finally:
self.db.close() # Close db connection.
# All Check Modules repeat same logic, so not explained further.
def CheckAudioWithAudioID(self, audioID):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "SELECT * FROM audios WHERE audioID = '%s'" % audioID
check = cursor.execute(sqlQuery).fetchall()
if len(check) > 0:
return True
else:
return False
except:
self.logManager.AddLog(f"Issue occurred while checking audio in db! \nAudio ID : {audioID}")
ColoredPrint.RedPrint(f"Issue occurred while checking audio in db! \nAudio ID : {audioID}")
return False
finally:
self.db.close()
def CheckUserWithID(self, userID):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "SELECT * FROM users WHERE userID = %s" % userID
check = cursor.execute(sqlQuery).fetchall()
if len(check) > 0:
return True
else:
return False
except:
self.logManager.AddLog(f"Issue occurred while checking user in db! \nUser ID : {userID}")
ColoredPrint.RedPrint(f"Issue occurred while checking user in db! \nUser ID : {userID}")
return False
finally:
self.db.close()
def CheckBotStatsWithID(self, botID = 1):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "SELECT * FROM stats WHERE botID = %s" % botID
check = cursor.execute(sqlQuery).fetchall()
if len(check) > 0:
return True
else:
return False
except:
self.logManager.AddLog(f"Issue occurred while checking bot in db! \nBot ID : {botID}")
ColoredPrint.RedPrint(f"Issue occurred while checking bot in db! \nBot ID : {botID}")
return False
finally:
self.db.close()
#endregion
#region Download - Search Count Update Modules # Functions to update data in the db.
def AudioDownloadCountUpdate(self, audioID): # Function to update audio download count by audioID.
try:
self._Connect() # Connect to db.
cursor = self.db.cursor() # Create cursor.
sqlQuery = " UPDATE audios SET audioDownloadCount = audioDownloadCount + 1 WHERE audioID = '%s'" % audioID # SQL query
cursor.execute(sqlQuery) # Add data.
self.db.commit() # Save.
return True # Indicate saved.
except:
self.logManager.AddLog(f"Issue occurred while increasing audio download count in db! \nAudio ID : {audioID}")
ColoredPrint.RedPrint(f"Issue occurred while increasing audio download count in db! \nAudio ID : {audioID}")
return False # If error, return False.
finally:
self.db.close() # Close connection.
def VideoDownloadCountUpdate(self, videoID):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = " UPDATE videos SET videoDownloadCount = videoDownloadCount + 1 WHERE videoID = '%s'" % videoID
cursor.execute(sqlQuery)
self.db.commit()
return True
except:
self.logManager.AddLog(f"Issue occurred while increasing video download count in db! \nVideo ID : {videoID}")
ColoredPrint.RedPrint(f"Issue occurred while increasing video download count in db! \nVideo ID : {videoID}")
return False
finally:
self.db.close()
def UserVideoDownloadCountUpdate(self, userID):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = " UPDATE users SET userVideoDownloadCount = userVideoDownloadCount + 1 WHERE userID = %s" % userID
cursor.execute(sqlQuery)
self.db.commit()
return True
except:
self.logManager.AddLog(f"Issue occurred while increasing user video download count in db! \nUser ID : {userID}")
ColoredPrint.RedPrint(f"Issue occurred while increasing user video download count in db! \nUser ID : {userID}")
return False
finally:
self.db.close()
def UserAudioDownloadCountUpdate(self, userID):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = " UPDATE users SET userAudioDownloadCount = userAudioDownloadCount + 1 WHERE userID = %s" % userID
cursor.execute(sqlQuery)
self.db.commit()
return True
except:
self.logManager.AddLog(f"Issue occurred while increasing user audio download count in db! \nUser ID : {userID}")
ColoredPrint.RedPrint(f"Issue occurred while increasing user audio download count in db! \nUser ID : {userID}")
return False
finally:
self.db.close()
def UserSearchCountUpdate(self, userID):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = " UPDATE users SET userSearchCount = userSearchCount + 1 WHERE userID = %s" % userID
cursor.execute(sqlQuery)
self.db.commit()
return True
except:
self.logManager.AddLog(f"Issue occurred while increasing user search count in db! \nUser ID : {userID}")
ColoredPrint.RedPrint(f"Issue occurred while increasing user search count in db! \nUser ID : {userID}")
return False
finally:
self.db.close()
def BotAudioCountUpdate(self, botID = 1):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "UPDATE stats SET audioDownloadCount = audioDownloadCount + 1 WHERE botID = %s" % botID
cursor.execute(sqlQuery)
self.db.commit()
except:
self.logManager.AddLog(f"Issue occurred while increasing audio count in db! \nBot ID : {botID} ")
ColoredPrint.RedPrint(f"Issue occurred while increasing audio count in db! \nBot ID : {botID} ")
finally:
self.db.close()
def BotVideoCountUpdate(self, botID = 1):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "UPDATE stats SET videoDownloadCount = videoDownloadCount + 1 WHERE botID = %s" % botID
cursor.execute(sqlQuery)
self.db.commit()
except:
self.logManager.AddLog(f"Issue occurred while increasing video count in db! \nBot ID : {botID} ")
ColoredPrint.RedPrint(f"Issue occurred while increasing video count in db! \nBot ID : {botID} ")
finally:
self.db.close()
def BotSearchCountUpdate(self, botID = 1):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "UPDATE stats SET searchCount = searchCount + 1 WHERE botID = %s" % botID
cursor.execute(sqlQuery)
self.db.commit()
except:
self.logManager.AddLog(f"Issue occurred while increasing search count in db! \nBot ID : {botID} ")
ColoredPrint.RedPrint(f"Issue occurred while increasing search count in db! \nBot ID : {botID} ")
finally:
self.db.close()
def BotUserCountUpdate(self, botID = 1):
try:
self._Connect()
cursor = self.db.cursor()
sqlQuery = "UPDATE stats SET userCount = userCount + 1 WHERE botID = %s" % botID
cursor.execute(sqlQuery)
self.db.commit()
except:
self.logManager.AddLog(f"Issue occurred while increasing user count in db! \nBot ID : {botID} ")
ColoredPrint.RedPrint(f"Issue occurred while increasing user count in db! \nBot ID : {botID} ")
finally:
self.db.close()
#endregion
#region Get Data Modules
def BotDataGet(self, botID = 1): # Function to get bot stats
try:
self._Connect() # Connect to db.
cursor = self.db.cursor() # Create cursor.
sqlQuery = "SELECT * FROM stats WHERE botID = %s" %botID # Fetch data from db by botID
datas = cursor.execute(sqlQuery).fetchone() # Search.
return datas # Return data.
except:
self.logManager.AddLog(f"An issue occurred while fetching bot data from db! \nBot ID : {botID}")
ColoredPrint.RedPrint(f"An issue occurred while fetching bot data from db! \nBot ID : {botID}")
finally:
self.db.close() # Close db connection.
#endregion
Base.py
# This project created by urhoba
# www.urhoba.net
from telegram import user
from YouTubeManager import YouTubeManager # We import the script we created for YouTube.
from DBManager import DBManager # We import the DBManager script.
class UrhobA:
#region Init
def __init__(self) -> None:
self.yt = YouTubeManager() # We create our YouTubeManager class.
self.dbMan = DBManager() # We create our DBManager class.
if self.dbMan.CheckBotStatsWithID() == False: # We check the bot's state.
self.dbMan.AddBot() # If there's no bot, we create a new bot (This is done only once for the first user; it's never used again.)
#endregion
#region User Modules
def CreateUser(self, userID, userName): # Function to create user record with user info.
if self.dbMan.CheckUserWithID(userID) == False: # We check if user exists.
self.dbMan.AddUser(userID, userName) # If not, we create a new user.
self.dbMan.BotUserCountUpdate() # We increase the user count in bot stats in db.
#endregion
#region File Modules
def DeleteFile(self, fileFolder): # Function to delete file.
self.yt.DeleteFile(fileFolder) # We call the delete function from YouTube script.
#endregion
#region Counter Update Modules
def SearchCountUpdateUser(self, userID, userName): # Function to increase user's search count
if self.dbMan.CheckUserWithID(userID) == True: # We check the user.
self.dbMan.UserSearchCountUpdate(userID) # If user exists, we increase search count.
self.dbMan.BotSearchCountUpdate() # We also increase for bot.
else:
self.CreateUser(userID, userName) # If user does not exist, create one (You can later call this again to add data or else it is skipped).
def VideoDownloadCountUpdateUser(self, userID, userName): # Function to increase video download count.
if self.dbMan.CheckUserWithID(userID) == True: # Check if user exists.
self.dbMan.UserVideoDownloadCountUpdate(userID) # If found, increase count.
self.dbMan.BotVideoCountUpdate() # Increase for bot too.
else:
self.CreateUser(userID, userName) # If not, create user (same as above).
def AudioDownloadCountUpdateUser(self, userID, userName): # Function to increase audio download count.
if self.dbMan.CheckUserWithID(userID) == True: # Check if user exists.
self.dbMan.UserAudioDownloadCountUpdate(userID) # If found, increase count.
self.dbMan.BotAudioCountUpdate() # Increase for bot too.
else:
self.CreateUser(userID, userName) # If not, create user (same as above).
#endregion
#region Search Modules
def SearchVideo(self, searchQuery): # YouTube search function.
result = self.yt.SearchVideo(searchQuery) # We do the search.
return result # Return results.
#endregion
#region Download Modules
def DownloadVideo(self, video_id): # Video download function.
result = self.yt.DownloadVideo(video_id) # download video.
if result == False: # Check if video downloaded.
return False # If not, return False.
else: # If downloaded
if self.dbMan.CheckVideoWithVideoID(video_id): # Check if video exists.
self.dbMan.VideoDownloadCountUpdate(video_id) # If so, increase count.
else: # If not
self.dbMan.AddVideo(result[0], result[1], result[2]) # Add video.
return result[2] # Return file path.
# All steps for video download are repeated for audio file.
def DownloadAudio(self, video_id):
result = self.yt.DownloadAudio(video_id)
if result == False:
return False
else:
if self.dbMan.CheckAudioWithAudioID(video_id):
self.dbMan.AudioDownloadCountUpdate(video_id)
else:
self.dbMan.AddAudio(result[0], result[1], result[2])
return result[2]
#endregion
#region Get Stats Modules
def GetBotDatas(self, botID = 1): # Function for fetching bot stats.
if self.dbMan.CheckBotStatsWithID() == True: # Check if bot exists.
datas = self.dbMan.BotDataGet() # If so, fetch data.
return datas # Return data.
#endregion
Telegram.py
# This project created by urhoba
# www.urhoba.net
from logging import info # Log library.
from telegram import * # Telegram bot library.
from telegram.ext import * # Telegram bot extension library.
from LogManager import LogManager # LogManager script.
from Settings import TelegramSettings # Settings script.
from Base import UrhobA # Base script.
import ColoredPrint # Script for colored terminal output
#region Start Command
def StartCommand(update, context): # Function for /start command.
text = f'''
Hello, {update.message.from_user.first_name}!
I’ll help you find the video or song you are searching for on YouTube and send it to you as a file.
Just enter the name of the video or song you want to search for. 😉
⚠️ To learn how to use it
You can use the
/help command.
'''
urhoba = UrhobA() # Access UrhobA class from base script.
urhoba.CreateUser(update.message.from_user.id, update.message.from_user.username) # Create user.
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Send message.
#endregion
#region Help
def HelpCommand(update, context): # /help function.
text = f'''
Hello, {update.message.from_user.first_name}.
I see you need help, let’s help you out.
Just enter the name of the video or song you want to find.
Among the results:
🎬 Button lets you download the video.
🎧 Button lets you download audio.
🔗 The button takes you to our website.
'''
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Send message.
#endregion
#region UrhobA
def UrhobACommand(update, context): # Function for /urhoba command.
text = f"""
Hello, {update.message.from_user.first_name}.
You can go to our website by clicking the link below.
🔗 UrhobA
"""
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML)
#endregion
#region Stats Command # Function for /stats command.
def StatsCommand(update, context):
urhoba = UrhobA() # Create UrhobA class.
statDatas = urhoba.GetBotDatas() # Fetch bot data
text = f'''
📊 Statistics 📊
🔍 Searches performed : {statDatas[3]}
🎬 Video downloads : {statDatas[2]}
🎧 Audio downloads : {statDatas[1]}
😁 Number of users : {statDatas[4]}
🔗 UrhobA
'''
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Send message.
#endregion
#region Search Modules
def SearchCommand(update, context): # In Telegram groups, since direct messaging for search is not possible, this function works with /search command.
searchText = update.message.text.split("/search")[1].strip() # Removes "/search" part. For example: "/search Ezhel - Mayrig" returns "Ezhel - Mayrig".
Search(update, context, searchText) # Call the search function below.
def Search(update, context, query = None): # Function when user types anything to the bot.
text = "Finding it now. 🔍🔍" # Our search in progress message.
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Send message.
urhoba = UrhobA() # Create Urhoba class
if query == None: # Check if coming from SearchCommand.
searchText = update.message.text # Take the plain text.
else: # If from SearchCommand.
searchText = query # Take value passed.
searchResult = urhoba.SearchVideo(searchText) # Search via Base.py.
try:
if len(searchResult) > 0: # If results more than 0
buttons = [] # Create button array.
for video in searchResult: # Iterate over search results and create buttons.
buttonOne = [InlineKeyboardButton(text=f'{video.title}', callback_data='none')]
buttonTwo = [InlineKeyboardButton(text=f'🎬', callback_data=f'videourhoba{video.video_id}'),
InlineKeyboardButton(text=f'🔗', url="https://www.urhoba.net"),
InlineKeyboardButton(text=f'🎧', callback_data=f'audiourhoba{video.video_id}')]
buttons.append(buttonOne) # Add buttonOne to array.
buttons.append(buttonTwo) # Add buttonTwo to array.
replyMarkup = InlineKeyboardMarkup(buttons) # Assign all buttons.
context.bot.send_message(chat_id=update.message.chat_id, text=f"Search result:\n{searchText}",
parse_mode=ParseMode.HTML, reply_markup=replyMarkup) # Send results + buttons.
else: # If results not more than 0
text = "I couldn't find what you’re looking for. 😢" # Indicate that nothing was found.
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Send message.
urhoba.SearchCountUpdateUser(update.message.from_user.id, update.message.from_user.username) # Increase search count.
except:
text = "An issue occurred while searching for your request! 😢\nWe’ll look into this soon." # User message in case of error.
context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Send message.
logManager = LogManager("TelegramLog") # Log error.
logManager.AddLog(f'Telegram (YouTube) search issue!\n Search Text : {searchText} \n Search result : {searchResult}')
#endregion
#region Button Call Back Modules (Download - Search Result)
def ButtonCallBack(update: Update, context: CallbackQueryHandler): # Function that detects user clicking one of the above buttons.
query = update.callback_query # Get value.
query.answer() # Process.
queryData = query.data.split("urhoba") # Split action.
urhoba = UrhobA() # Call Urhoba class.
text = 'Don’t forget to visit our site. 🥰 \n🔗 UrhobA' # Prepare message.
if queryData[0] == "video": # If video
query.edit_message_text(text=f"⏳ Video file is being prepared.\n⚠️ Sending videos can take longer than audios, please be patient.", parse_mode=ParseMode.HTML) # Send info message.
urhoba.VideoDownloadCountUpdateUser(update.callback_query.from_user.id, update.callback_query.from_user.username) # Increase download count.
videoFolder = urhoba.DownloadVideo(queryData[1]) # Get video file.
if videoFolder == False: # If video file empty.
query.message.reply_text(text='An issue occurred while preparing video file! 😢\nWe’ll look into this soon.', parse_mode=ParseMode.HTML) # State video could not be sent.
else:
try:
query.message.reply_video(video=open(videoFolder, 'rb'), supports_streaming=True, timeout=10000) # Try sending video.
query.message.reply_text(text=text,parse_mode=ParseMode.HTML) # Send text after video.
except:
query.message.reply_text(text='An issue occurred while sending video file! 😢\nWe’ll look into this soon.', parse_mode=ParseMode.HTML)
finally:
urhoba.DeleteFile(videoFolder) # Since I’m using it for demo, I delete the video from the server.
elif queryData[0] == "audio": # If audio, repeat as above for videos.
query.edit_message_text(text=f"⏳ Audio file is being prepared.", parse_mode=ParseMode.HTML)
urhoba.AudioDownloadCountUpdateUser(update.callback_query.from_user.id, update.callback_query.from_user.username)
audioFolder = urhoba.DownloadAudio(queryData[1])
if audioFolder == False:
query.message.reply_text(text='An issue occurred while preparing audio file! 😢\nWe’ll look into this soon.', parse_mode=ParseMode.HTML)
else:
try:
query.message.reply_audio(audio=open(audioFolder, 'rb'))
query.message.reply_text(text=text,parse_mode=ParseMode.HTML)
except:
query.message.reply_text(text='An issue occurred while sending audio file! 😢\nWe’ll look into this soon.', parse_mode=ParseMode.HTML)
finally:
urhoba.DeleteFile(audioFolder)
else: # If song title button clicked, send warning.
text = "⚠️ Please only use the 🎬 or 🎧 buttons."
query.message.reply_text(text=text,parse_mode=ParseMode.HTML)
#endregion
#region Legal Info
def LegalInfoCommand(update, context): # Function for /legal command.
returnedMessage = """
We built UrhobABot with the idea that a legal stream recording tool for the internet that was clean, easy, and not spammy needed to exist.
According to the EFF.org "The law is clear that simply providing the public with a tool for copying digital media does not give rise to copyright liability".
"""
context.bot.send_message(chat_id=update.message.chat_id, text=returnedMessage, parse_mode=ParseMode.HTML)
#endregion
#region Error Handler # Error catching function
def ErrorExcept(update, context):
logManager = LogManager("TelegramLog")
logManager.AddLog(f"Telegram bot error : Update {update} caused error {context.error}")
#endregion
#region Main
def main():
updater = Updater(TelegramSettings.telegramAPI, use_context=True) # Create Telegram bot.
dp = updater.dispatcher # Create handler.
# Catch commands.
dp.add_handler(CommandHandler("start", StartCommand))
dp.add_handler(CommandHandler("legal", LegalInfoCommand))
dp.add_handler(CommandHandler("help", HelpCommand))
dp.add_handler(CommandHandler("stats", StatsCommand))
dp.add_handler(CommandHandler("urhoba", UrhobACommand))
# Catch /search inputs.
dp.add_handler(CommandHandler("search", SearchCommand))
# Catch text messages.
dp.add_handler(MessageHandler(Filters.text & ~Filters.command, Search))
# Catch button clicks.
dp.add_handler(CallbackQueryHandler(ButtonCallBack))
dp.add_error_handler(ErrorExcept) # Catch errors.
updater.start_polling(1) # Start bot.
updater.idle() # Set bot to listen mode.
#endregion
ColoredPrint.GreenPrint("Bot started!") # Indicate bot started.
main() # Run the bot.
MailManager.py
# This project created by urhoba
# www.urhoba.net
from Settings import MailSettings # We import our script with mail settings.
from LogManager import LogManager # We import logManager for error handling.
import smtplib # The library for sending emails.
from email.mime.text import MIMEText # Library for altering MIME text type.
from email.mime.multipart import MIMEMultipart # For using multiple MIME types together.
import ColoredPrint # We import the script for colored text to terminal.
class MailManager:
#region Init
def __init__(self) -> None:
# Assign mail settings to variables.
self.fromMail = MailSettings.fromMail
self.fromPassword = MailSettings.fromPassword
self.smtpHost = MailSettings.smtpHost
self.smtpPort = MailSettings.smtpPort
self.logManager = LogManager("MailManager")
#endregion
#region Send Mail
def SendMail(self, subject, content, toMail): # Our function to send mail, can be used outside this project as SendMail("Subject", "Content", "receiver@domain.com")
try:
message = MIMEMultipart("alternative") # Set MIME type.
message["Subject"] = subject # Specify subject.
message["From"] = self.fromMail # Specify sender.
message["To"] = toMail # Specify receiver.
_content = MIMEText(content.encode('utf-8'), _charset='utf-8') # Set content and charset.
message.attach(_content) # Attach content.
with smtplib.SMTP_SSL(self.smtpHost, self.smtpPort) as server: # Connect to server to send.
server.login(self.fromMail, self.fromPassword) # Login.
server.sendmail(self.fromMail, toMail, message.as_string()) # Send message.
except Exception as e: # Exception handling.
self.logManager.AddLog(f"Mail could not be sent!\nError Code: {e}\nMail subject : {subject} \nMail content : {content} \nReceiver : {toMail}")
ColoredPrint.RedPrint(f"Mail could not be sent!\nError Code: {e}\nMail subject : {subject} \nMail content : {content} \nReceiver : {toMail}")
#endregion

Yorum Gönder