Requisitos:
Para realizar esta práctica necesitamos un ordenador con Python instalado y tener creado un bot de Telegram, tienes un tutorial para crear un bot aquí.
El módulo Pytube:
Es un módulo creado por Ronnie Ghose que puedes encontrar en su Github y que permite descargar audio y vídeo directamente de Youtube.
1.-Dependencias:
Antes de comenzar debermos instalar las librerías necesarias para el proyecto, usaremos pip.
Si no tienes instalado pip lo mejor es que hagas un update de los paquetes de instalación antes de instalarlo
sudo apt-get update
sudo apt install python-pip
Para este bot utilizaremos las librerías pyTelegramBotAPI y pytube, además de os.
las instalamos:
pip install pyTelegramBotAPI
pip install pytube
2.-¿Qué hace nuestro bot?:
Nuestro bot tiene un solo comando que es musica, y recibe un parámetro que es la URL del vídeo de Youtube del cual queremos recibir el audio en formato mp3.
Ejemplo de uso:
/musica https://www.youtube.com/watch?v=iIpfWORQWhU
El bot enviará un thumbnail del vídeo y, a continuación, el mp3 extraído del vídeo:
Pero qué hace realmente el bot:
- Busca todos los streams de audio y vídeo que Youtube asocia a la URL del vídeo (hay más de una por las calidades diferentes que puede tener Youtube asociadas a un mismo vídeo).
- Escoge el stream de audio que tiene la mejor calidad.
- Sustituye en el nombre los parénteis por guiones y quita espacios en blanco, para evitar errores con el nombre de fichero, ya que el nombre del vídeo será el nombre del fichero.
- Descarga el fichero en el directorio que indiquemos en la variable path.
- Envía un thumbnail del vídeo por Telegram.
- Envía el fichero mp3 por Telegram. IMPORTANTE Esto solo funciona si el fichero tiene hasta 50Mb, en caso contrario se descargará pero no se enviará (ni se borrará el fichero del equipo que esté ejecutando el bot. Esto es una limitación que se puede evitar instalando un servidor local de Telegram, tenéis más info aquí.
- Borra el fichero mp3 local. (Esto solo ocurrirá si no hay un error al enviar el fichero, por ejemplo si éste tiene más de 50Mb).
3.-Mejoras a implementar:
Algunas mejoras que podrían implementarse son:
- Por una parte dejar elegir al usuario qué stream desea descargar, aquí el reto está en la forma en que Youtube guarda los vídeos, que es muchas veces con un stream de audio y uno de vídeo por separado, los cuales deberían juntarse.
- Por otra parte que el bot funcione para ficheros que pesen más de 50Mb, esto podría solucionarse haciendo una instalación local de Telegram o creando un programa que partiese el mp3 en trozos para enviarlo "troceado" por Telegram, cosa que no es muy elegante...
4.- El bot:
Aquí está el código del bot, se deberá cambiar el texto MITOKEN por el token de tu bot de Telegram y el texto MIPATH por el directorio que tengas habilitado para las descargas de los ficheros, por ejemplo "/home/usuario/pyMusic".
import telebot
import os
import pytube
bot = telebot.TeleBot('MITOKEN')
#directorio donde guardar la descarga
path = "MIPATH"
def main():
bot.polling()
@bot.message_handler(commands=['musica'])
def musica(message):
texto = message.text
chat = message.chat.id
l = len(texto)
url = texto[8:l]
#URL del video de Youtube
try:
yt = pytube.YouTube(url)
imagen = yt.thumbnail_url
#Filtramos las descargas por audio solamente, orden descendiente de calidad y
# el primero que será el que tiene la calidad más alta
stream = yt.streams.filter(mime_type='audio/mp4',only_audio=True).desc().first()
nombre = stream.default_filename
#quitamos espacios y paréntesis y cambiamos el tipo de fichero a mp3
nombre = stream.default_filename
nombre = ''.join(char for char in nombre if char.isalnum())
nombre = nombre.replace(" ", "")
nombre = nombre.replace("(", "-")
nombre = nombre.replace(")", "-")
nombre = nombre.replace("mp4", ".mp3")
#Descargamos el audio seleccionado en el directorio escogido
stream.download(output_path=path,filename=nombre)
#enviar imagen del audio (portada, es el thumbnail del video);
bot.send_photo(chat_id=chat,photo=imagen)
#enviar audio:
bot.send_document(chat_id=chat , document=open(path+nombre,'rb'))
#borrar archivo de musica (solo pasa si se envia sin error)
operation = 'rm '+path+nombre
os.system(operation)
except pytube.exceptions.RegexMatchError:
bot.send_message(chat,'URL de vídeo no existe')
print("URL no encontrada")
except BaseException as err:
print(f"Unexpected {err=}, {type(err)=}")
bot.send_message(chat,'Se ha producido un error')
if __name__ == '__main__':
main()