Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

 Merhaba arkadaşlar oldukça uzun bir yazı ile karşınızdayım, aslında çok uzun da bir yazı değil ancak bu projede bulunan kodları biraz anlatmak ve çalışma prensiblerini anlatmak istediğim için uzayacaktır.

Bu projede Python kullanarak Telegram için bir bot yazacağız ve bu botumuz ile Telegram üzerinden gelen mesajı alıp YouTube üzerinde arama yapacağız daha sonrasında sonuçları kullanıcıya gösterip ardından seçtiği video/şarkıyı ona dosya olarak göndereceğiz.

Bunlara ek olarak bir de yapılan arama sayısını, indirilen ses/video dosya sayısını ve kullanan tekil kullanıcı sayısı istatistiklerini basit bir veri tabanı sistemi ile (sqlite) tutacağız. Son olarak bir de çok basit bir log sistemimiz olacak ki basitçe hataları ".txt" olarak bize sunsun.

Kodlar düzensiz olduğu için kafanızı takmayın hepsini bir bütün olarak GitHub üzerinden sayfanın sonunda paylaşacağım.

Projeye Başlangıç

Yazının bu kısmında projemizde oluşturduğumuz scriptleri ve neden oluşturduğumuzu açıklayacağım çünkü yazıyı çok uzun tutmak istemediğim için ilerleyen kısımlarda çok fazla gerekmedikçe yazı olarak kodları açıklamayacağım, sadece kodun içerisinde bulunan açıklama satırları kısmında kodları açıklamaya çalışacağım.

Not : Burada bulunan kodları kopyala yapıştır yaparak bir proje oluşturmak yerine sayfanın sonunda bulunan Github'da paylaştığım halini indirip kullanmanızı öneriyorum. 
Yazı içerisinde satır kaymalarından ötürü kopyala yapıştır yapmanız durumunda hata almanız ve bu hataları gidermek ile uğraşmanız gerekebilir.

Projemizde Kullandığımız Python Kütüphanelerimiz

Bu proje tamamen sıfırdan yazılmış bir proje değil, bir çok farklı Python kütüphanesinden faydalanılmıştır. Bu kütüphaneleri pip veya pip3 yardımı ile kurabilirsiniz. Gelin kullandığımız kütüphanelere bakalım.
  • sqlite3
    • Veri tabanı oluşturup istatistikleri tutmak için kullanıyoruz.
  • python-telegram-bot
    • Telegram ile mesaj almak ve göndermek için kullanıyoruz.
  • pytube
    • YouTube üzerinde arama yapmak ve indirme işlemini gerçektirmek için kullanıyoruz.
  • termcolor
    • Terminal üzerinde renklendirme yapmak için kullanıyoruz.
Pip ile kurmanız gereken kütüphaneler bunlardır ancak bunların dışında kullandığım kütüphaneler de bulunmaktadır. Hepsini burada yazmıyorum ancak kodların içerisinde açıklama satırı olarak onlar hakkında da bilgi vereceğim.

Projede Kullanılan Scriptlere Dair Özet

Projemiz 8 adet scriptten oluşmaktadır.
  1. Base.py
    1. Tüm scriptleri birleşilip daha kolay ve anlaşılabilir bir şekilde kullanabilmemizi sağlayan scriptimiz.
  2. ColoredPrint.py
    1. Bu scriptimiz terminalde renkli yazı yazmak için oluşturduğumuz fonksiyonları barındırıyor.
  3. DBManager.py
    1. Veri tabanı işlemlerini barındıran fonksiyonların bulunduğu scriptimizdir.
  4. LogManager.py
    1. Log kayıtlarını oluşturmak için oluşturduğumuz scriptimiz.
  5. Settings.py
    1. Ayarları tutan scriptimiz.
  6. TelegramBot.py
    1. Telegram ile iletişim kurmamızı sağlayan scriptimiz.
  7. YouTubeManager.py
    1. YouTube ile ilgili işlemleri yaptığımız scriptimiz.
  8. MailManager.py
    1. Mail göndermek için kullanabileceğimiz fonksiyonları barındıran scriptimiz.
    2. Şu an için bu scripti kullanmıyorum ancak ileride böyle bir proje yapacak olsam bazı istatistikleri / hata çıktılarını otomatik olarak mail atmak için böyle bir sayfa da hazırladım.
Projemiz 3 adet dosyadan oluşmaktadır.
  1. Videos
    1. Videoların indirildiği dosyamızdır.
  2. Audios
    1. Seslerin indirildiği dosyamızdır.
  3. Logs
    1. Log kayıtlarının tutulduğu dosyamızdır.
Kodlarımızı bu kadar dağınık bir şekilde yazmamızın temel sebebi daha okunabilir, düzenli olması için. Aynı zamanda her fonksiyonu oldukça değer döndüren fonksiyonlar halinde hazırlıyoruz ki ileride düzenlememiz gerektiği zaman binlerce satırlık kod blokları arasında arama yapıp düzenlemek yerine aradığımız ilişkili sayfada düzenleyip kolayca istediğimiz hale getirmek için.

Not : Script sayfalarında bolca "#region Örnek-Yazı" şeklinde ifadeler göreceksiniz, bunların ne için kullanıldığını bilmeyeniniz yoktur ancak yine de açıklayayım kodları daha düzgün görmek ve kataloglamak için kullanıyoruz.

Neyse basit bir şekilde projemizi özetlediğimize göre artık kodlarımıza geçebiliriz.

Proje Kodları (Scriptler)

Settings.py

Projemizde belli başlı sabit veya ileri zamanda değiştirilebilir olan değişkenlerimiz bulunuyor, bunlar Telegramın API key i gibi değerler.
Bunları tek tek scriptler içinde gezip bulup düzenlemek yerine biraz daha kolay düzenleyebilmek adına "settings.py" adında bir script oluşturduk ve buradan daha hızlı bir şekilde düzenleyebiliriz.

# This project created by urhoba
# www.urhoba.net

#region DB Settings
class DBSettings: # Veri tabanı ayarları için bir sınıf oluşturduk.
    sqliteDB = "db.urhoba" # bu sınıfın içinde sqlite kullandığımız veri tabanımızın dosyasının adını girdik.
#endregion

#region Mail Settings 
class MailSettings: # Mail göndermek için bir sınıf oluşturduk.
    fromMail = "ahmetbohur@urhoba.net" # SMTP mailimizin kullanıcı adı.
    fromPassword = "" # SMTP mailimizin şifresi.
    smtpHost = "smtp.yandex.com" # SMTP mailimzin sağlayıcısı / sunucusu.
    smtpPort = 465 # SMTP mailimizin port adresi.
#endregion

#region Download Settings
class DownloadSettings: # İndirilen dosyaların ayarları.
    musicFolder = "songs" # Ses dosyamızın indirileceği olacağı klasörün adı.
    videoFolder = "videos" # videoların indirileceği klasörün adı.
#endregion

#region Telegram Settings
class TelegramSettings: # Telegram ayarları için olan sınıfımız.
    telegramAPI = "" # Telegram api adresimizi buraya yazıyoruz.
#endregion


ColoredPrint.py

ColoredPrint scriptimiz, terminale yazı yazdırırken yazdığımız yazının renklenmesini kolaylaştırmak için oluşturduğumuz scriptimizdir.

from termcolor import colored # termcolor kütüphanesini çağırıyoruz ve içinden colored'i import ediyoruz.

#region Green Print
def GreenPrint(text): # Yeşil renkde yazdırmak için bir fonksiyon oluşturuyoruz.
    print(colored(text, 'green')) # Fonksiyonumuza gelen text i yeşil olarak yazdırıyoruz.
#endregion

#region Red Print
def RedPrint(text): # Kırmızı renkde yazdırmak için bir fonksiyon oluşturuyoruz.
    print(colored(text, 'red')) # Fonksiyonumuza gelen text i kırmızı olarak yazdırıyoruz.
#endregion

LogManager.py

Hata aldığımız kodların veya noktaların hata kayıtlarını tutmak için oluşturduğumu scriptimizdir. 
Aldığımız hatayı "logs" klasörü içinde bir .txt uzantılı dosya ile tutar.
Her sınıfın hata dosyası farklıdır ve bunu sınıf içerisinde bu scripte erişerek ismi belirleriz.
# This project created by urhoba
# www.urhoba.net

from datetime import date, datetime # Hatanın ne zaman olduğunu öğrenmek için zaman bilgilerini çekmek için kullandığımız kütüphane.
import locale # Zaman bilgilerinin sistem dilinde çıktı vermesi için kullandığımız kütüphane.
import os # Dosya işlemlerini yapmak için kullandığımız kütüphane.
import ColoredPrint # Aldığımız hatayı aynı zamanda terminalde yazdırmak için kullandığımız kütüphane.

#region Locale Settings 
locale.setlocale(locale.LC_ALL, '') # Zaman bilgilerini sistem dilinde olması için ayarlıyoruz.
#endregion

class LogManager: # LogManager adında bir sınıf oluşturuyoruz
#region Init    
    def __init__(self, logFileName) -> None: # Sınıfı çağırırken bu sınıfı çağırdığımız hata adında dosya oluşturmak için dosya adını istiyoruz
        self._logFileName = logFileName # dosya adını yazdırıyoruz
#endregion

#region Add Log
    def AddLog(self, errorText): # AddLog(hataMesajı) adında bir fonksiyon oluşturuyoruz.
        _nowTime = datetime.now() # Tarihi alıyoruz.
        _nowTime = datetime.strftime(_nowTime, "%c") # Tarihi string haline getiriyoruz.
        logFile = open(os.getcwd()+"/logs/"+self._logFileName + ".txt", "a") # Log dosyası oluşturuyoruz.
        try:
            with logFile as f: # Log dosyasını okuyoruz.
                f.write(f"\nDate : {_nowTime}\nError: {errorText}\n") # Log dosyasının en altına yeni hatamızı yazdırıyoruz.
            ColoredPrint.RedPrint(f'Date : {_nowTime}\nError: {errorText}\n') # Hatamızı ekrana bastırıyoruz.
        except:
            ColoredPrint.RedPrint("Log oluşturulurken bir sorun meydana geldi!") # Log dosyası oluşturulurken bir hata aldıysak bunu ekrana yazdırıyoruz.
        finally:
            logFile.close() # Log dosyamızı kapatıyoruz.
#endregion


YouTubeManager.py

YouTube ile ilgili işlemleri yaptığımız asıl scriptimiz burasıdır. Burada YouTube üzerinde arama, ses ve video indirme gibi özellikleri yazıyoruz. 
Ayrıca bir kaç da sistem fonksiyonu bulunuyor. 
Bunlar ben deneme amaçlı yaptığım için indirilen dosyanın silinmesini sağlamak veya eğer orijinal bir projede kullanılacak ise indirilen verinin tekrar tekrar indirilmesini engellemek amacı ile yazılmış fonksiyonlardır.
# This project created by urhoba
# www.urhoba.net

from pytube import YouTube # PyTube ile YouTube üzerinde ses / video indirmemizi sağlayan kütüphane.
from pytube import Search # PyTube ile YouTube üzerinde arama yapmamızı sağlayan kütüphane.
import ssl # SSL kütüphanesi, bunu MAC cihazlarda PyTube nin ssl hatası vermesi üzerine bu hatayı gidermek için kullanıyoruz.

import os # Dosya işlemleri yapmak için kullandığımız kütüphane.
import os.path # Dosya işlemleri yapmak için özellike benim burada dosya var mı yok mu kontrol etmek için kullandığım kütüphane.
import re # REGEX tespit etmek için kullandığımız kütüphane. (Ben burada şu anda kullanmadım ancak her an kullanabilirim. Bu kütüphaneyi projenizde kullanmadıysanız çıktı alırken kaldırmayı unutmayın!)

from LogManager import LogManager # Oluşturduğumuz LogManager scriptini çağırıyoruz.
from Settings import DownloadSettings # Oluşturduğumuz Settings scriptini çağırıyoruz ve içinden DownloadSettings sınıfını çekiyoruz.
import ColoredPrint # Ekrana renkli yazı yazıdırmak için olan sınıfımızı çağırıyoruz.

#region SSL Settings
ssl._create_default_https_context = ssl._create_stdlib_context # MAC cihazlarda SSL hatasını burada gideriyoruz.
#endregion

class YouTubeManager:
#region Init    
    def __init__(self) -> None:
        self.logManager = LogManager("YouTubeManagerLog") # LogManager sınıfımızı kullanarak log kayıtı oluşturmak için logManager oluşturuyoruz.
#endregion

#region Search Modules    
    def SearchVideo(self, searchQuery): # Arama yapmak için bir fonksiyon oluşturduk ve searchQuery değerini istedik.
        try:
            search = Search(searchQuery) # YouTube üzerinde arama yapıyoruz ve arama yapılırken bir sorun yok ise sonucu search değişkenine atadık.
            return search.results # search.result ile sonuçları döndürdük.
        except:
            self.logManager.AddLog(f"Video aranırken bir sorun meydana geldi! \nArama sorgusu : {searchQuery}") # Bir hata var ise logManager ile log dosyamıza ekledik
            ColoredPrint.RedPrint(f"Video aranırken bir sorun meydana geldi! \nArama sorgusu : {searchQuery}") # Gereksiz bir şekilde bunu eklemişim ama ekrana da yazdırıyoruz. (Gereksiz dememin sebebi logManager zaten bu işlemi yapıyor.)

#endregion

#region File Modules
    def FileCheck(self, file): # Dosya varmı yok mu kontrol etmek için bir fonksiyon oluşturduk, buraya dosya konumunu gönderiyoruz.
        if os.path.isfile(file) and os.access(file, os.R_OK): # Dosya varmı kontrol ediyoruz.
            return True # Dosya varsa True değerini
        else: # yok ise
            return False # False değerini döndürüyor.

    def DeleteFile(self, file): # Dosyanın sunucuda yer kaplamaması için silme fonksiyonu oluşturuyoruz.
        os.remove(file) # Dosyamızı siliyoruz.

    def FileNameFormatter(self, name): # Bazı işletim sistemlerinde bazı karakterler (örneğin: /\) desteklenmiyor bunları yeniden düzenlemek için bir fonksiyon oluşturuyoruz.
        validFileName = "".join([c for c in name if c.isalpha() or c.isdigit() or c==' ']).rstrip() # Desteklenmeyen karakterleri siliyoruz.
        return validFileName # Düzenlenmiş ismi döndürüyoruz.
#endregion

#region Download Modules
    def DownloadVideo(self, videoURL): # Video indirmek için bir fonksiyon oluşturuyoruz. Burada önemli nokta bu fonksiyona videonun hash değerini gönderiyoruz. Örneğin : watch?v=YXwSDEG3pTQ YouTube videosundaki url de bulunan YXwSDEG3pTQ kısmını
        try:
            youtube = YouTube(f"https://www.youtube.com/watch?v={videoURL}") # Video bilgilerini çekiyoruz.
            videoTitle = youtube.title # Video başlığını alıyoruz.
            fileName = self.FileNameFormatter(videoTitle) + ".mp4" # Video adını kontrol edip değişkenimize ekliyoruz.
            if self.FileCheck(DownloadSettings.videoFolder+"/"+fileName) == False: # Dosya varmı kontrol ediyoruz.
                youtube.streams.get_highest_resolution().download(output_path=DownloadSettings.videoFolder, filename=fileName) # Dosyamız yok ise indiriyoruz.
            return videoTitle, videoURL, DownloadSettings.videoFolder + "/" + fileName # video başlığı, video url si ve video dosya konumu bilgilerini gönderiyoruz.
        except:
            self.logManager.AddLog(f"Video indirilirken bir sorun meydana geldi! \nVideo bağlantısı : {videoURL}") # Hata almışsak logManager ile log dosyasına ekliyoruz.
            ColoredPrint.RedPrint(f"Video indirilirken bir sorun meydana geldi! \nVideo bağlantısı : {videoURL}") # Ekrana yazdırıyoruz.
            return False # Hata var ise False değerini döndürüyoruz.

    def DownloadAudio(self, songURL): # Ses indirmek için bir fonksiyon oluşturuyoruz.
        try:
            youtube = YouTube(f"https://www.youtube.com/watch?v={songURL}") # Video bilgilerini çekiyoruz.
            songTitle = youtube.title # Video başlığını çekiyoruz.
            fileName = self.FileNameFormatter(songTitle) + ".mp4" # Video başlığını kontrol ediyoruz. 
            if self.FileCheck(DownloadSettings.musicFolder+"/"+fileName) == False: # Dosya varmı kontrol ediyoruz.
                youtube.streams.get_audio_only().download(output_path=DownloadSettings.musicFolder, filename=fileName) # Dosya yok ise indiriyoruz.
            return songTitle, songURL,DownloadSettings.musicFolder + "/" + fileName # Video indirme fonksiyonundaki gibi değerleri döndürüyoruz.
        except:
            self.logManager.AddLog(f"Ses indirilirken bir sorun meydana geldi! \nSes bağlantısı : {songURL}") # Hata almışsak logManager ile log dosyasına ekliyoruz.
            ColoredPrint.RedPrint(f"Ses indirilirken bir sorun meydana geldi! \nSes bağlantısı : {songURL}") # Ekrana yazdırıyoruz.
            return False # Hata var ise False değerini döndürüyoruz.
#endregion

DBManager.py

Veri tabanı işlemlerini yapmak için oluşturduğumuz scripttir, bu script sayesinde indirilme sayısı, kullanıcı sayısı gibi verileri tutabiliyor ve kolay bir şekilde işlem yapabiliyoruz.
# This project created by urhoba
# www.urhoba.net

import sqlite3 # Veri tabı olarak SQLite3 kullanıyoruz bu yüzden kütüphanesini dahil ediyoruz.
from sqlite3.dbapi2 import Cursor # Kullanmadığım bir kütüphane. (Otomatik olarak oluşturulmuş. Projenizde kullanmıyorsanız silmeyi unutmayın!)
from LogManager import LogManager # Hatalar için logManager scriptimizi çağırıyoruz.
from Settings import DBSettings # Ayarlardan veri tabanı için olan scriptimizi çağırıp DBSettings sınıfını çağırıyoruz.
import ColoredPrint # Ekrana renkli yazı yazdırmak için olan sınıfımızı çağırıyoruz.

class DBManager:
#region Init    
    def __init__(self) -> None: # DBManager çağırıldığı zaman yapılan işlemlerimiz.
        self._CreateVideoDB() # Video için veri tabanı oluştur fonksiyonunu çağırıyoruz.
        self._CreateAudioDB() # Ses için olan veri tabanını oluştur fonksiyonunu çağırıyoruz.
        self._CreateUserDB() # Kullanıcı için olan veri tabanını oluşturan fonksiyonumuzu çağırıyoruz.
        self._CreateBotStatsDB() # Bot istatistikleri için olan veri tabanını oluşturan fonksiyonumuzu çağırıyoruz.
        self.logManager = LogManager("DBManagerLog") # Log oluşturmak için logManager oluşturuyoruz.
#endregion

#region Connect
    def _Connect(self): # Veri tabanına bağlanmak için fonksiyonumuz. 
        self.db = sqlite3.connect(DBSettings.sqliteDB) # Veri tabanı değişkeni oluşturup veri tabanına bağlanıyoruz.
        ColoredPrint.GreenPrint("Veri tabanına bağlanıldı.") # Veri tabanına bağlandığımızı söylüyoruz.
#endregion

#region Create DB Modules # Veri tabanı oluşturma fonksiyonlarımız.
    def _CreateVideoDB(self): # Video veri tabanı oluşturmak için olan fonksiyonumuz.
        try:
            self._Connect() # Veri tabanına bağlanıyoruz.
            cursor = self.db.cursor() # Cursor oluşturuyoruz.
            sqlQuery = "CREATE TABLE IF NOT EXISTS videos (videoTitle, videoID, videoFile, videoDownloadCount)" # SQL Sorgumuzu yazıyoruz
            cursor.execute(sqlQuery) # Veri tabanını oluşturuyoruz.
            ColoredPrint.GreenPrint("Video veri tabanı oluşturuldu.") # Veri tabanı oluşturduğumuzu söylüyoruz. (Burada veri tabanı varsa zaten yeniden veri tabanı oluşmaz ancak oluştu diye ekrana çıktı verir.)
        except:
            self.logManager.AddLog("Video veri tabanı oluşturulurken bir hata meydana geldi!") # Hata almış isek log ekliyoruz.
            ColoredPrint.RedPrint("Video veri tabanı oluşturulurken bir hata meydana geldi!") # Hatamızı ekrana yazdırıyoruz.
        finally:
            self.db.close() # Veri tabanı bağlantısını kapatıyoruz.
# Veri tabanı oluşturma başlığı altında bulunan tüm fonksiyonlar yukarıdaki ile aynı işlemleri yapıyor.
    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("Ses veri tabanı oluşturuldu.")
        except:
            self.logManager.AddLog("Ses veri tabanı oluşturulurken bir hata meydana geldi!")
            ColoredPrint.RedPrint("Ses veri tabanı oluşturulurken bir hata meydana geldi!")
        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("Kullanıcı veri tabanı oluşturuldu.")
        except:
            self.logManager.AddLog("Kullanıcı veri tabanı oluşturulurken bir hata meydana geldi!")
            ColoredPrint.RedPrint("Kullanıcı veri tabanı oluşturulurken bir hata meydana geldi!")
        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("İstatistik veri tabanı oluşturuldu.")
        except:
            self.logManager.AddLog("İstatistik veri tabanı oluşturulurken bir hata meydana geldi!")
            ColoredPrint.RedPrint("İstatistik veri tabanı oluşturulurken bir hata meydana geldi!")
        finally:
            self.db.close()        
         
#endregion

#region Add Modules # Oluşturduğumuz veri tabanına veri eklemek için kullandığımız fonksiyonlarımız.
    def AddVideo(self, videoTitle, videoID, videoFile): # Video eklemek için fonksiyonumuz
        try:
            self._Connect() # Veri tabanına bağlanıyoruz.
            cursor = self.db.cursor() # Cursor oluşturuyoruz.
            sqlQuery = "INSERT INTO videos (videoTitle, videoID, videoFile, videoDownloadCount) VALUES (?,?,?,?)" # SQL sorgumuzu oluşturuyoruz.
            sqlValues = (videoTitle, videoID, videoFile, 1) # Değerlerimizi alıyoruz.
            cursor.execute(sqlQuery, sqlValues) # Veriyi ekliyoruz.
            self.db.commit() # Eklediğimiz veriyi gönderiyoruz.
            ColoredPrint.GreenPrint(f"Video eklendi. \nVideo Başlığı : {videoTitle} \nVideo ID : {videoID}") # Eklenen veriyi ekrana yazdırıyoruz.
        except: # Hata var ise excep içinde log oluşturup ekrana yazdırıyoruz.
            self.logManager.AddLog(f"Veri tabanına video eklenirken bir hata meydana geldi! \nVideo Title : {videoTitle} \nVideo ID : {videoID}\nVideo File : {videoFile}")
            ColoredPrint.RedPrint(f"Veri tabanına video eklenirken bir hata meydana geldi! \nVideo Title : {videoTitle} \nVideo ID : {videoID}\nVideo File : {videoFile}")
        finally:
            self.db.close() # Veri tabanı bağlantısını kapatıyoruz.
# Add Modules içinde bulunan tüm fonksiyonlar yukarıdaki ile aynı işlemleri amaçları doğrultusunda tekrar ediyor o yüzden tek tek açıklamıyorum.
    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"Ses eklendi. \nSes Başlığı : {audioTitle} \nSes ID : {audioID}")
        except:
            self.logManager.AddLog(f"Veri tabanına ses eklenirken bir hata meydana geldi! \nAudio Title : {audioTitle} \nAudio ID : {audioID}\nAudio File : {audioFile}")
            ColoredPrint.RedPrint(f"Veri tabanına ses eklenirken bir hata meydana geldi! \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"Kullanıcı eklendi. \nKullanıcı adı : {userName}\nKullanıcı ID : {userID}")
        except:
            self.logManager.AddLog(f"Veri tabanına kullanıcı eklenirken bir hata meydana geldi! \nKullanıcı ID : {userID}\nKullanıcı adı : {userName}")
            ColoredPrint.RedPrint(f"Veri tabanına kullanıcı eklenirken bir hata meydana geldi! \nKullanıcı ID : {userID}\nKullanıcı adı : {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 eklendi. \nBot ID : {botID}")
        except:
            self.logManager.AddLog(f"Veri tabanına bot eklenirken bir hata meydana geldi! \nBot ID : {botID}")
            ColoredPrint.RedPrint(f"Veri tabanına bot eklenirken bir hata meydana geldi! \nBot ID : {botID}")
        finally:
            self.db.close()        
#endregion
  
#region Check Modules # Veri varmı kontrol ettiğimiz fonksiyonlarımız.
    def CheckVideoWithVideoID(self, videoID): # Video ID sine göre videoyu veri tabanında arayıp varmı yokmu kontrol ettiğimiz fonksiyonumuz.
        try:
            self._Connect() # Veri tabanına bağlanıyoruz.
            cursor = self.db.cursor() # Cursor oluşturuyouz.
            sqlQuery = "SELECT * FROM videos WHERE videoID = '%s'" % videoID # SQL sorgumuz ile videoID sine göre videoyu arıyoruz.
            check = cursor.execute(sqlQuery).fetchall() # Tüm videolar arasında arama yapıyoruz.
            if len(check) > 0: # check değerimiz 0 dan büyük ise videonun var olduğunu bildiriyoruz.
                return True # True döndürüyoruz.
            else: # Check 0 veya 0 dan küçük ise 
                return False # False değerini döndürüyoruz.
        except: # Hataları yakalıyoruz ve hatalı ise False döndürüyoruz.
            self.logManager.AddLog(f"Veri tabanında video doğrulanırken bir sorun meydana geldi! \nvideo ID : {videoID}")
            ColoredPrint.RedPrint(f"Veri tabanında video doğrulanırken bir sorun meydana geldi! \nvideo ID : {videoID}")
            return False
        finally:
            self.db.close() # Veri tabanı bağlantısını kapatıyoruz.
# Check modules içinde bulunan tüm fonksiyonlar aynı şekilde olduğu için geri kalanını açıklamıyorum.
    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"Veri tabanında ses doğrulanırken bir sorun meydana geldi! \nAudio ID : {audioID}")
            ColoredPrint.RedPrint(f"Veri tabanında ses doğrulanırken bir sorun meydana geldi! \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"Veri tabanında kullanıcı doğrulanırken bir sorun meydana geldi! \nUser ID : {userID}")
            ColoredPrint.RedPrint(f"Veri tabanında kullanıcı doğrulanırken bir sorun meydana geldi! \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"Veri tabanında bot doğrulanırken bir sorun meydana geldi! \nBot ID : {botID}")
            ColoredPrint.RedPrint(f"Veri tabanında bot doğrulanırken bir sorun meydana geldi! \nBot ID : {botID}")
            return False
        finally:
            self.db.close()        
#endregion

#region Download - Search Count Update Modules # Veri tabanında veri güncellemek için kullandığımız fonksiyonlarımız.
    def AudioDownloadCountUpdate(self, audioID): # VideoID sine bakarak video indirilme sayını güncelleyen fonksiyonumuz.
        try: 
            self._Connect() # Veri tabanına bağlanıyoruz. 
            cursor = self.db.cursor() # Cursor oluşturuyoruz.
            sqlQuery = " UPDATE audios SET audioDownloadCount = audioDownloadCount + 1 WHERE audioID = '%s'" % audioID # SQL Sorgumuzu döndürüyoruz.
            cursor.execute(sqlQuery) # Verileri ekliyoruz.
            self.db.commit() # Veriyi kaydediyoruz.
            return True # Kaydedildiğini söylüyoruz.
        except:
            self.logManager.AddLog(f"Veri tabanında ses indirme sayısı arttırılırken bir sorun meydana geldi! \nAudio ID : {audioID}")
            ColoredPrint.RedPrint(f"Veri tabanında ses indirme sayısı arttırılırken bir sorun meydana geldi! \nAudio ID : {audioID}")
            return False # Hata var ise False döndürüyoruz.
        finally:
            self.db.close() # Veri tabanına bağlantıyı sonlandırıyoruz.
    
    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"Veri tabanında video indirme sayısı arttırılırken bir sorun meydana geldi! \nVideo ID : {videoID}")
            ColoredPrint.RedPrint(f"Veri tabanında video indirme sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında kullanıcı video indirme sayısı arttırılırken bir sorun meydana geldi! \nUser ID : {userID}")
            ColoredPrint.RedPrint(f"Veri tabanında kullanıcı video indirme sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında kullanıcı ses indirme sayısı arttırılırken bir sorun meydana geldi! \nUser ID : {userID}")
            ColoredPrint.RedPrint(f"Veri tabanında kullanıcı ses indirme sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında kullanıcı arama sayısı arttırılırken bir sorun meydana geldi! \nUser ID : {userID}")
            ColoredPrint.RedPrint(f"Veri tabanında kullanıcı arama sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında ses sayısı arttırılırken bir sorun meydana geldi! \nBot ID : {botID} ")
            ColoredPrint.RedPrint(f"Veri tabanında ses sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında video sayısı arttırılırken bir sorun meydana geldi! \nBot ID : {botID} ")
            ColoredPrint.RedPrint(f"Veri tabanında video sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında sorgu sayısı arttırılırken bir sorun meydana geldi! \nBot ID : {botID} ")
            ColoredPrint.RedPrint(f"Veri tabanında sorgu sayısı arttırılırken bir sorun meydana geldi! \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"Veri tabanında kullanıcı sayısı arttırılırken bir sorun meydana geldi! \nBot ID : {botID} ")
            ColoredPrint.RedPrint(f"Veri tabanında kullanıcı sayısı arttırılırken bir sorun meydana geldi! \nBot ID : {botID} ")
        finally:
            self.db.close()

#endregion

#region Get Data Modules
    def BotDataGet(self, botID = 1): # Bot istatistiklerini çekmek için kullandığımız fonksiyonumuz
        try:
            self._Connect() # Veri tabanına bağlanıyoruz.
            cursor = self.db.cursor() # Cursor oluşturuyoruz.
            sqlQuery = "SELECT * FROM stats WHERE botID = %s" %botID # BotID sine göre veri tabanından verileri çekiyoruz.
            datas = cursor.execute(sqlQuery).fetchone() # Veriler içinde arama yapıyoruz.
            return datas # Çekilen verileri döndürüyoruz.
        except:
            self.logManager.AddLog(f"Veri tabanından bot verileri çekilirken bir sorun meydana geldi! \nBot ID : {botID}")
            ColoredPrint.RedPrint(f"Veri tabanından bot verileri çekilirken bir sorun meydana geldi! \nBot ID : {botID}")
        finally:
            self.db.close() # Veri tabanı bağlantısını kapatıyoruz.
#endregion


Base.py

Base.py diğer scriptleri bir arada kullanarak ayrı ayrı oluşturduğumuz sınıfları birleştirmekte kullandığımız scriptimizdir.
# This project created by urhoba
# www.urhoba.net

from telegram import user
from YouTubeManager import YouTubeManager # YouTube için oluşturduğumuz scriptimizi çekiyoruz.
from DBManager import DBManager # DBManager Scriptimizi çekiyoruz.

class UrhobA:
#region Init    
    def __init__(self) -> None:
        self.yt = YouTubeManager() # YouTubeManager sınıfımızı oluşturuyoruz.
        self.dbMan = DBManager() # DBManager sınıfımızı oluşturuyoruz.
        if self.dbMan.CheckBotStatsWithID() == False: # Bot durmunu kontrol ediyoruz.
            self.dbMan.AddBot() # Bot yok ise yeni bot oluşturuyoruz. (Veri tabanında botumuzu ilk kullanan kullanıcıda sadece bir kereye mahsus oluşturuluyor. ve daha sonra asla kullanılmıyor.)
#endregion

#region User Modules
    def CreateUser(self, userID, userName): # Kullanıcı bilgileri ile kullanıcı kaydı oluşturmak için kullandığımız fonksiyonumuz.
        if self.dbMan.CheckUserWithID(userID) == False: # Kullanıcı varmı kontrol ediyoruz.
            self.dbMan.AddUser(userID, userName) # Kullanıcı yoksa yeni kullanıcı oluşturuyoruz.
            self.dbMan.BotUserCountUpdate() # Veri tabanında bot istatistiklerinde bulunan kullanıcı sayısını arttırıyoruz.
#endregion

#region File Modules
    def DeleteFile(self, fileFolder): # Dosya silmek için olan fonksiyonumuz.
        self.yt.DeleteFile(fileFolder) # YouTube üzerinde bulunan silme fonksiyonumuzu çağırıyoruz.
#endregion

#region Counter Update Modules
    def SearchCountUpdateUser(self, userID, userName): # Kullanıcının arama sayısını arttırmak içni olan fonksiyonumuz
        if self.dbMan.CheckUserWithID(userID) == True: # Kullanıcıyı kontrol ediyoruz.
            self.dbMan.UserSearchCountUpdate(userID) # Kullanıcı bulunmuş ise arama sayısını kullanıcı için arttırıyoruz.
            self.dbMan.BotSearchCountUpdate() # Bot için arttırıyoruz.
        else:
            self.CreateUser(userID, userName) # Kullanıcı yoksa oluşturuyoruz. (Burada daha sonra bu fonksiyonu isterseniz yeniden çağırıp veriyi eklemesini sağlayabilirsiniz yoksa veri eklenmeden geçilir.)
    
    def VideoDownloadCountUpdateUser(self, userID, userName): # Video indirme sayısını arttırmak için olan fonksiyonumuz.
        if self.dbMan.CheckUserWithID(userID) == True: # Kullanıcı varmı kontrol ediyoruz.
            self.dbMan.UserVideoDownloadCountUpdate(userID) # Kullanıcı bulunmuş ise indirme sayısını kullanıcı için arttırıyoruz.
            self.dbMan.BotVideoCountUpdate() # Bot için arttırıyoruz.
        else:
            self.CreateUser(userID, userName) # Kullanıcı yoksa oluşturuyoruz. (Burada daha sonra bu fonksiyonu isterseniz yeniden çağırıp veriyi eklemesini sağlayabilirsiniz yoksa veri eklenmeden geçilir.)

    def AudioDownloadCountUpdateUser(self, userID, userName): # Ses indirme sayısını arttırmak için olan fonksiyonumuz.
        if self.dbMan.CheckUserWithID(userID) == True: # Kullanıcı varmı kontrol ediyoruz.
            self.dbMan.UserAudioDownloadCountUpdate(userID) # Kullanıcı bulunmuş ise indirme sayısını kullanıcı için arttırıyoruz.
            self.dbMan.BotAudioCountUpdate() # Bot için arttırıyoruz.
        else:
            self.CreateUser(userID, userName) # Kullanıcı yoksa oluşturuyoruz. (Burada daha sonra bu fonksiyonu isterseniz yeniden çağırıp veriyi eklemesini sağlayabilirsiniz yoksa veri eklenmeden geçilir.)
#endregion

#region Search Modules    
    def SearchVideo(self, searchQuery): # YouTube arama fonksiyonumuz.
        result = self.yt.SearchVideo(searchQuery) # Aramayı yapıyoruz.
        return result # Sonuçları döndürüyoruz.
#endregion

#region Download Modules
    def DownloadVideo(self, video_id): # Video indirme fonksiyonumuz.
        result = self.yt.DownloadVideo(video_id) # videoyu indiriyoruz.
        if result == False: # Video indirilmiş mi kontrol ediyoruz.
            return False # İndirilememiş ise False döndürüyoruz.
        else: # İndirilmiş ise
            if self.dbMan.CheckVideoWithVideoID(video_id): # Video varmı kontrol ediyoruz.
                self.dbMan.VideoDownloadCountUpdate(video_id) # Video varsa indirilme sayısnı arttırıyoruz.
            else: # Video yoksa
                self.dbMan.AddVideo(result[0], result[1], result[2]) # Videoyu ekliyoruz.
        return result[2] # Videonun dosya yolunu döndürüyoruz.

# Video indirme işleminde yaptıklarımızı ses dosyası için tekrar ediyoruz.
    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): # Bot istatistiklerini çektiğimiz fonksiyonumuz.
        if self.dbMan.CheckBotStatsWithID() == True: # Bot varmı kontrol ediyoruz.
            datas = self.dbMan.BotDataGet() # Bot varsa verileri çekiyoruz.
        return datas # Verileri döndürüyoruz.
#endregion


Telegram.py

Telegram üzerinden kullanıcı ve botun iletişim kurmasını aynı zamanda Base.py de bulunan fonksiyonlar ile botun çalışmasını sağlayan scriptimiz Telegram.py dir.
# This project created by urhoba
# www.urhoba.net

from logging import info # Log için olan kütüphane.
from telegram import * # Telegram bot kütüphanesi.
from telegram.ext import * # Telegram bot özellik kütüpahesi.

from LogManager import LogManager # LogManager scriptimiz.
from Settings import TelegramSettings # Settings scriptimiz.
from Base import UrhobA # Base scriptimiz.

import ColoredPrint # Ekrana renki yazı için olan scriptimiz

#region Start Command
def StartCommand(update, context): # Bota /start komutu geldiğinde çalışan fonksiyonumuz.
    text = f'''\ # Kullanıcıya gidecek olan mesajımız.
Merhaba, {update.message.from_user.first_name}!
YouTube da aradığın o videoyu veya şarkıyı bulmana yardım edecek ve sana dosya olarak göndereceğim.
Sadece aramak istediğin video veya şarkı adını gir. 😉 

⚠️ Nasıl kullanacağını öğrenmek için
/help komutunu kullanabilirsin.
    '''
    urhoba = UrhobA() # Base scriptimize erişip UrhobA sınıfını çekiyoruz.
    urhoba.CreateUser(update.message.from_user.id, update.message.from_user.username) # Kullanıcı oluşturuyoruz.
    context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Mesajımızı gönderiyoruz.
#endregion

#region Help 
def HelpCommand(update, context): # /help için olan fonskiyonumuz.
    text = f'''\
Merhaba, {update.message.from_user.first_name}.
Görüyorum ki yardıma ihtiyacım var, hadi sana yardım edelim.

Bulmak istediğin video veya şarkının adını girmen yeterli olacaktır.

Çıkan sonuçlar arasından;
🎬 Butonu video indirmeni sağlar. 
🎧 Butonu ses indirmeni sağlar.

🔗 Butonu seni internet sitemize yönlendirecektir.
    '''
    context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Mesajı gönderiyoruz.

#endregion

#region UrhobA
def UrhobACommand(update, context): # /urhoba komutu geldiği zaman çalışan fonksiyonumuz.
    text = f"""
Merhaba, {update.message.from_user.first_name}.
Aşağıdaki bağlantıya tıklayıp internet sitemize gidebilirsin.

🔗 UrhobA
    """
    context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML)
#endregion

#region Stats Command # /stats komutu geldiği zaman çalışan fonsksiyonumuz.
def StatsCommand(update, context):
    urhoba = UrhobA() # UrhobA sınıfı oluşturuyoruz.
    statDatas = urhoba.GetBotDatas() # Bot verilerini çekiyoruz
    text = f'''\
📊 İstatistikler 📊
🔍 Yapılan arama : {statDatas[3]}
🎬 Video indirme : {statDatas[2]}
🎧 Ses İndirme : {statDatas[1]}
😁 Kullanıcı sayısı : {statDatas[4]}

🔗 UrhobA     
    '''
    context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Mesajı gönderiyoruz.

#endregion

#region Search Modules
def SearchCommand(update, context): # Telegram gruplarında direkt mesaj üzerinden arama yapılamadığı için /search komutu ile çalışan fonskiyonumuz.
    searchText = update.message.text.split("/search")[1].strip() # "/search" kısmını ayıklıyor. örnek : "/search Ezhel - Mayrig" çıktısı "Ezhel - Mayrig" olacaktır.
    Search(update, context, searchText) # Hemen aşağıda bulunan search fonksiyonunu çağırıyoru.

def Search(update, context, query = None): # Kullanıcı bota herhangi bir şey yazdığı zaman çalışan fonksiyonumuz.
    text = "Hemen buluyorum. 🔍🔍"  # Arama yaptığını söyleyen yazımız.
    context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Yazımızı gönderiyoruz.
    urhoba = UrhobA() # Urhoba class ını oluşturuyoruz.
    if query == None: # SearchCommand fonksiyonundan gelip gelmediğini kontrol ediyoruz.
        searchText = update.message.text # Oradan gelmeiş ise normal yazdığını alıyoruz.
    else: # SearchCommand dan gelmiş ise.
        searchText = query # Gelen değeri alıyoruz.

    searchResult = urhoba.SearchVideo(searchText) # Base.py üzerinden arama yapıyoruz.
    try:
        if len(searchResult) > 0: # Çıkan sonuçlar 0 dan fazla ise
            buttons = [] # Buton dizisi oluşturuyoruz.
            for video in searchResult: # Arama sonuçları içinde geziyoruz ve butonlarımızı oluşturuyoruz.
                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) # buttonOne ı buton a ekliyoruz.
                buttons.append(buttonTwo) # buttonTwo u buton dizimize ekliyoruz.
            replyMarkup = InlineKeyboardMarkup(buttons) # Buttonların button olduğunu bildiriyoruz.
            context.bot.send_message(chat_id=update.message.chat_id, text=f"Arama sonucu:\n{searchText}",
                                    parse_mode=ParseMode.HTML, reply_markup=replyMarkup) # Arama sonucunu ve buttonları gönderiyoruz.
        else: # Eğer arama sonucu 0 dan büyük değilse. 
            text = "Aradığın şeyi bulamadım. 😢" # Bir şey bulamadığımızı söylüyoruz.
            context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Kullanıcıya mesaj atıyoruz.
        urhoba.SearchCountUpdateUser(update.message.from_user.id, update.message.from_user.username) # Arama sayısını arttırıyoruz.
    except:
        text = "İstediğin şeyi ararken bir sorun meydana geldi! 😢\nBunun ile en kısa süre içerisinde ilgileneceğiz." # Bir hata var ise kullanıcıya gidecek mesajımız.
        context.bot.send_message(chat_id=update.message.chat_id, text=text, parse_mode=ParseMode.HTML) # Kullanıcıya mesajımızı gönderiyoruz.
        logManager = LogManager("TelegramLog") # Hatamızı logluyoruz.
        logManager.AddLog(f'Telegram (YouTube) arama yaparken bir sorun meydana geldi!\n Search Text : {searchText} \n Search result : {searchResult}')
#endregion

#region Button Call Back Modules (Download - Search Result)
def ButtonCallBack(update: Update, context: CallbackQueryHandler): # Kullanıcı bir üst fonksiyonda butonlardan birine basmış ise bunu tespit ettiğimiz fonksiyon.
    query = update.callback_query # Dönen değeri alıyoruz.
    query.answer() # Değeri işliyoruz.
    queryData = query.data.split("urhoba") # Ayırma işlemi yapıyoruz.
    urhoba = UrhobA() # Urhoba sınıfı çağırıyoruz.
    text = 'Sitemizi ziyaret etmeyi unutmayın. 🥰 \n🔗 UrhobA' # Mesajımızı hazırlıyoruz.
    if queryData[0] == "video": # Video ise 
        query.edit_message_text(text=f"⏳ Video dosyası hazırlanıyor.\n⚠️ Videoların gönderim süresi ses dosyalarına göre daha uzundur, lütfen sabırlı olun.", parse_mode=ParseMode.HTML) # Önden bilgi mesajı gönderiyoruz.
        urhoba.VideoDownloadCountUpdateUser(update.callback_query.from_user.id, update.callback_query.from_user.username) # İndirme sayısını arttırıyoruz.
        videoFolder = urhoba.DownloadVideo(queryData[1]) # Video dosyasını çekiyoruz.
        if videoFolder == False: # Video dosyası boş ise.
            query.message.reply_text(text='Video dosyası hazırlanırken bir sorun meydana geldi! 😢\nBunun ile en kısa süre içerisinde ilgileneceğiz.', parse_mode=ParseMode.HTML) # Videoyu gönderemediğimizi söylüyoruz.
        else:
            try:
                query.message.reply_video(video=open(videoFolder, 'rb'), supports_streaming=True, timeout=10000) # Videoyu göndermeyi deniyoruz.
                query.message.reply_text(text=text,parse_mode=ParseMode.HTML) # videonun ardından mesajımızı gönderiyoruz.
            except:
                query.message.reply_text(text='Video dosyası gönderilirken bir sorun meydana geldi! 😢\nBunun ile en kısa süre içerisinde ilgileneceğiz.', parse_mode=ParseMode.HTML)
            finally:
                urhoba.DeleteFile(videoFolder) # Burada ben deneme amaçlı kullandığım için sunucuya inen video dosyasını siliyorum.
    elif queryData[0] == "audio": # Buton ses ise video da yaptığımız adımları ses dosyası için tekrar ediyoruz.
        query.edit_message_text(text=f"⏳ Ses dosyası hazırlanıyor.", 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='Ses dosyası hazırlanırken bir sorun meydana geldi! 😢\nBunun ile en kısa süre içerisinde ilgileneceğiz.', 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='Ses dosyası gönderilirken bir sorun meydana geldi! 😢\nBunun ile en kısa süre içerisinde ilgileneceğiz.', parse_mode=ParseMode.HTML)
            finally:
                urhoba.DeleteFile(audioFolder)
    else: # Şarkının adının yazdığı butona tıklanmış ise uyarı mesajı gönderiyoruz.
        text = "⚠️ Lütfen sadece 🎬 veya 🎧 butonlarını kullanın."
        query.message.reply_text(text=text,parse_mode=ParseMode.HTML)


#endregion

#region Legal Info
def LegalInfoCommand(update, context): # /legal komutu geldiğinde çalışan fonksiyonumuz.
    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 # Hata yakalama fonksiyonumuz
def ErrorExcept(update, context):
    logManager = LogManager("TelegramLog")
    logManager.AddLog(f"Telegram bot hatası : Update {update} caused error {context.error}")
#endregion

#region Main
def main():
    updater = Updater(TelegramSettings.telegramAPI, use_context=True) # Telegram botu oluşturuyoruz.
    dp = updater.dispatcher # Yakalayıcı oluşturuyoruz.

	# Komutları yakalıyoruz.
    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))

	# /search ile yazılanları yakalıyoruz.
    dp.add_handler(CommandHandler("search", SearchCommand))
	
    # Yazılanları yakalıyoruz.
    dp.add_handler(MessageHandler(Filters.text & ~Filters.command, Search))

	# Buton tıklamalarını yakalıyoruz.
    dp.add_handler(CallbackQueryHandler(ButtonCallBack))

    dp.add_error_handler(ErrorExcept) # Hataları yakalıyoruz.
    updater.start_polling(1) # Botu başlatıyoruz.
    updater.idle() # Botu dinleme moduna alıyoruz.
#endregion

ColoredPrint.GreenPrint("Bot başlatıldı!") # Botun başlatıldığını söylüyoruz.
main() # Botumuzu çağırıyoruz.


MailManager.py

Şu an için aktif olmayan ancak ilerleyen zamanlarda belki log dosyalarını mail olarak kendime atarım diye yazdığım bir script.
SMTP üzerinden mail göndermenizi sağlıyor.
# This project created by urhoba
# www.urhoba.net

from Settings import MailSettings # Mail ayarlarını içeren scriptimizi çekiyoruz.
from LogManager import LogManager # Log için olan scriptimizi çekiyoruz.

import smtplib # Mail göndermek için olan kütüphanemizi çekiyoruz.
from email.mime.text import MIMEText # Mesaj MIME tipini değiştirmek için olan kütüphanemizi çekiyoruz.
from email.mime.multipart import MIMEMultipart # Çoklu MIME tipini bir arada kullanabilmek için olan kütüphanemizi çekiyoruz.

import ColoredPrint # Terminale renkli yazı yazdırmak için olan scriptimizi çekiyoruz.

class MailManager:
#region Init    
    def __init__(self) -> None:
    	# Mail ayarlarımızı değişkene atıyoruz.
        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): # Mail göndermek için olan fonksiyonumuz SendMail("Başlık", "İçerik", "Alıcı@alanadı.com") şeklinde bu projenin dışında da kullanılabilir.
        try:
            message = MIMEMultipart("alternative") # MIME tipini ayarlıyoruz.
            message["Subject"] = subject # Başlığı belirliyoruz.
            message["From"] = self.fromMail # Gönderen adresini belirliyoruz.
            message["To"] = toMail # Alıcı adresini belirliyoruz.

            _content = MIMEText(content.encode('utf-8'), _charset='utf-8') # İçeriği ve charsetini ayarlıyoruz.
            message.attach(_content) # İçeriği ekliyoruz.

            with smtplib.SMTP_SSL(self.smtpHost, self.smtpPort) as server: # Mesaj göndermek için sunucuya bağlanıyoruz.
                server.login(self.fromMail, self.fromPassword) # Sunucuda giriş yapıyoruz.
                server.sendmail(self.fromMail, toMail, message.as_string()) # Mesjaı gönderiyoruz.
        except Exception as e: # Hataları ayıklıyoruz.
            self.logManager.AddLog(f"Mail gönderilemedi!\nHata Kodu: {e}\nMail başlığı : {subject} \nMail içeriği : {content} \nAlıcı : {toMail}")
            ColoredPrint.RedPrint(f"Mail gönderilemedi!\nHata Kodu: {e}\nMail başlığı : {subject} \nMail içeriği : {content} \nAlıcı : {toMail}")

#endregion

Github Repoları

Aşağıda 2 adet Github reposu bırakıyorum, bunlardan urhoba-blog içinde bulunan buradaki kodlar ile birebir aynı olan ve sayfa güncellenmedikçe güncellenmeyen halini içeriyor.
Diğeri ise direkt bu bota özel olan sayfadır, aldığım hataları giderdiğim ve yeni özellikler eklediğim sürümüdür.


Botumuzdan Görüntüler

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)

Python Kullanarak Telegram Botu Yapma (YouTube'den Video / Ses İndirip Gönderen)