From a421d3b292f047bd90ff990b202f5128b2f4d404 Mon Sep 17 00:00:00 2001 From: Manuel Vergara Date: Tue, 16 Jul 2024 23:07:56 +0200 Subject: [PATCH] Add movie Bot for Telegram --- .../06_bots_telegram/06_movie_bot/Dockerfile | 26 + .../06_movie_bot/docker-compose.yaml | 36 ++ .../06_bots_telegram/06_movie_bot/main.py | 47 ++ .../06_movie_bot/requirements.txt | 20 + .../06_movie_bot/src/__init__.py | 1 + .../06_bots_telegram/06_movie_bot/src/bot.py | 468 ++++++++++++++++++ catch-all/06_bots_telegram/README.md | 2 +- 7 files changed, 599 insertions(+), 1 deletion(-) create mode 100644 catch-all/06_bots_telegram/06_movie_bot/Dockerfile create mode 100644 catch-all/06_bots_telegram/06_movie_bot/docker-compose.yaml create mode 100644 catch-all/06_bots_telegram/06_movie_bot/main.py create mode 100644 catch-all/06_bots_telegram/06_movie_bot/requirements.txt create mode 100644 catch-all/06_bots_telegram/06_movie_bot/src/__init__.py create mode 100644 catch-all/06_bots_telegram/06_movie_bot/src/bot.py diff --git a/catch-all/06_bots_telegram/06_movie_bot/Dockerfile b/catch-all/06_bots_telegram/06_movie_bot/Dockerfile new file mode 100644 index 0000000..b977331 --- /dev/null +++ b/catch-all/06_bots_telegram/06_movie_bot/Dockerfile @@ -0,0 +1,26 @@ +FROM python:alpine + +ADD requirements.txt /app/requirements.txt + +RUN apk update && apk upgrade && \ + apk add --no-cache bash && \ + rm -rf /var/cache/apk/* && \ + set -ex && \ + python -m venv /env && \ + /env/bin/pip install --upgrade pip && \ + /env/bin/pip install --no-cache-dir -r /app/requirements.txt && \ + runDeps="$(scanelf --needed --nobanner --recursive /env \ + | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ + | sort -u \ + | xargs -r apk info --installed \ + | sort -u)" && \ + apk add --virtual rundeps $runDeps && \ + apk del rundeps + +ADD . /app +WORKDIR /app + +ENV VIRTUAL_ENV=/env +ENV PATH=/env/bin:$PATH + +CMD ["python", "main.py"] diff --git a/catch-all/06_bots_telegram/06_movie_bot/docker-compose.yaml b/catch-all/06_bots_telegram/06_movie_bot/docker-compose.yaml new file mode 100644 index 0000000..1bcac2b --- /dev/null +++ b/catch-all/06_bots_telegram/06_movie_bot/docker-compose.yaml @@ -0,0 +1,36 @@ +version: '3.7' + +services: + movie_bot: + env_file: + - .env + image: movie_bot_python:latest + container_name: movie_bot + environment: + - PUID=1000 + - PGID=1000 + - TZ=Asia/Kolkata + restart: unless-stopped + depends_on: + bbdd: + condition: service_healthy + + bbdd: + image: mysql:latest + container_name: bbdd_movie_bot + env_file: + - .env + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + ports: + - "3306:3306" + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p${MYSQL_ROOT_PASSWORD}"] + interval: 10s + retries: 5 + start_period: 30s + timeout: 10s \ No newline at end of file diff --git a/catch-all/06_bots_telegram/06_movie_bot/main.py b/catch-all/06_bots_telegram/06_movie_bot/main.py new file mode 100644 index 0000000..8951386 --- /dev/null +++ b/catch-all/06_bots_telegram/06_movie_bot/main.py @@ -0,0 +1,47 @@ +from telegram.ext import CommandHandler, MessageHandler, filters, CallbackQueryHandler + +from src import Botz + + +def main(): + + # Mi nombre de usuario (manuelver) + print(r""" + + _ + _ __ ___ __ _ _ __ _ _ ___| |_ _____ _ __ + | '_ ` _ \ / _` | '_ \| | | |/ _ \ \ \ / / _ \ '__| + | | | | | | (_| | | | | |_| | __/ |\ V / __/ | + |_| |_| |_|\__,_|_| |_|\__,_|\___|_| \_/ \___|_| """) + + bot = Botz() + + bot.app.add_handler(CommandHandler('start', bot.start_command)) + + bot.app.add_handler(CommandHandler('help', bot.help_command)) + + bot.app.add_handler(CommandHandler("find", bot.find_title)) + + bot.app.add_handler(CommandHandler("save", bot.movie_saver)) + + bot.app.add_handler(CommandHandler("remove", bot.movie_remover)) + + bot.app.add_handler(CommandHandler("list", bot.movie_list)) + + bot.app.add_handler(CommandHandler("reboot", bot.reboot)) + + bot.app.add_handler(CommandHandler("status", bot.status)) + + bot.app.add_handler(MessageHandler(filters.TEXT, bot.any_text)) + + bot.app.add_error_handler(bot.error) + + bot.app.add_handler(CallbackQueryHandler(bot.query_handler)) + + print('Bot Started Polling! Check Terminal for Errors') + + bot.app.run_polling(poll_interval=3) + + +if __name__ == '__main__': + main() diff --git a/catch-all/06_bots_telegram/06_movie_bot/requirements.txt b/catch-all/06_bots_telegram/06_movie_bot/requirements.txt new file mode 100644 index 0000000..5d14cc7 --- /dev/null +++ b/catch-all/06_bots_telegram/06_movie_bot/requirements.txt @@ -0,0 +1,20 @@ +aiohttp==3.9.5 +aiosignal==1.3.1 +anyio==4.4.0 +async-timeout==4.0.3 +attrs==23.2.0 +certifi==2024.7.4 +charset-normalizer==3.3.2 +frozenlist==1.4.1 +h11==0.14.0 +httpcore==1.0.5 +httpx==0.27.0 +idna==3.7 +multidict==6.0.5 +mysql-connector-python==9.0.0 +protobuf==5.27.2 +python-dotenv==1.0.1 +python-telegram-bot==21.4 +sniffio==1.3.1 +tcp-latency==0.0.12 +yarl==1.9.4 diff --git a/catch-all/06_bots_telegram/06_movie_bot/src/__init__.py b/catch-all/06_bots_telegram/06_movie_bot/src/__init__.py new file mode 100644 index 0000000..34b63c4 --- /dev/null +++ b/catch-all/06_bots_telegram/06_movie_bot/src/__init__.py @@ -0,0 +1 @@ +from .bot import Botz diff --git a/catch-all/06_bots_telegram/06_movie_bot/src/bot.py b/catch-all/06_bots_telegram/06_movie_bot/src/bot.py new file mode 100644 index 0000000..9725011 --- /dev/null +++ b/catch-all/06_bots_telegram/06_movie_bot/src/bot.py @@ -0,0 +1,468 @@ +from typing import Final +from os import getenv, execl +import sys +from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup +from telegram.ext import Application, ContextTypes +import aiohttp +from dotenv import load_dotenv, find_dotenv +import mysql.connector as msc +import time +from tcp_latency import measure_latency + +print('Iniciando bot...') + +load_dotenv('.env') + +# Telegram Bot +BOT_USERNAME: Final = getenv("BOT_USERNAME") +BOT_API: Final = getenv("BOT_API") + +# OMDB +OMDB: Final = "http://www.omdbapi.com" +OMDB_SITE: Final = "www.omdbapi.com" +OMDB_API: Final = getenv("OMDB_API") + +# TMDB +TMDB_API: Final = getenv("TMDB_API") +TMDB_SITE: Final = "api.themoviedb.org" + +# IMDB +IMDB_LINK: Final = "https://www.imdb.com/title/" + +# MySQL +MYSQL_HOST: Final = getenv("MYSQL_HOST") +MYSQL_PORT: Final = 3306 +MYSQL_USER: Final = getenv("MYSQL_USER") +MYSQL_PASSWORD: Final = getenv("MYSQL_PASSWORD") +MYSQL_DATABASE: Final = getenv("MYSQL_DATABASE") +CREATE_TABLE: Final = getenv("CREATE_TABLE", True) + + +class Botz: + + INTRO_MSG = "*¡Hola! Soy un Bot de Películas \n" \ + "Escribe /help para ver la lista de comandos disponibles* \n" + + HELP_MSG = "*COMANDOS DISPONIBLES*\n\n" \ + " * Comando :* /start\n" \ + " * Descripción :* Muestra la introducción.\n\n" \ + " * Comando :* /help\n" \ + " * Descripción :* Lista los comandos disponibles.\n\n" \ + " * Comando :* /status\n" \ + " * Descripción :* Devuelve el estado del bot.\n\n" \ + " * Comando :* /find nombre-de-la-pelicula \n" \ + " * Descripción :* " \ + " Proporciona los detalles de la película/serie especificada." \ + " Introduce el nombre de la película como argumento del comando /find." \ + " Usa los botones debajo para obtener más información. \n" \ + " ej: /find Godfather \n\n" \ + " * Comando :* /find nombre-de-la-pelicula y=año\n" \ + " * Descripción :* " \ + " Proporciona los detalles de la película/serie especificada." \ + " Introduce el nombre de la película y el año como argumento del comando /find." \ + " Usa los botones de debajo para obtener más información. \n" \ + " ej: /find Godfather y=1972\n\n" \ + " * Comando :* /save IMDB-id \n" \ + " * Descripción :* " \ + " Introduce el ID de IMDB de la película/serie como argumento." \ + " Usa el comando /find para encontrar el ID de IMDB de una película/serie." \ + " Guarda el mensaje/archivo respondido en la base de datos con el ID de IMDB dado." \ + " Siempre usa este comando como respuesta al archivo que se guardará.\n " \ + " ej: /save tt1477834\n\n" \ + " * Comando :* /remove IMDB-id \n" \ + " * Descripción :* " \ + " Introduce el ID de IMDB de la película/serie como argumento." \ + " Usa el comando /find para encontrar el ID de IMDB de una película/serie." \ + " Elimina el archivo del ID de IMDB especificado de la base de datos.\n" \ + " ej: /remove tt1477834\n\n" \ + " * Comando :* /list \n" \ + " * Descripción :* Devuelve el número de películas/series actualmente indexadas en la base de datos.\n" \ + + MOVIE_NOT_FOUND_MSG = "*{} no está indexada actualmente en mi base de datos. 😔*\n\n" \ + "Si tienes esta película en tu chat o en otros grupos, \n" \ + " - Reenvía esa película a mi chat o a este grupo y, \n" \ + " - Usa '*/save {}*' como respuesta al archivo de la película para guardarla en mi base de datos. \n" + + REBOOT_WAIT_MESSAGE = "Reiniciando el bot. Por favor espera ⏲️" + + REBOOT_SUCCESS_MESSAGE = "El bot ha vuelto 😃" + + STATUS_MESSAGE = "*El bot está vivo.* 😃 \n\n" \ + "*Estado de la base de datos :* {} \n" \ + "*Latencia de la base de datos :* {} \n" \ + "*Películas disponibles :* {} \n\n" \ + "*OMDB :* {} \n" \ + "*Latencia de OMDB :* {} \n\n" \ + "*TMDB :* {} \n" \ + "*Latencia de TMDB :* {} \n" + + MOVIE_NOT_FOUND = "*Película/Serie NO ENCONTRADA. \n" \ + "Revisa la ortografía.* \n" + + FIND_MSG = "*Introduce el NOMBRE de la Película/Serie junto con /find. \n" \ + "Ve a /help para más detalles.* \n" + + INVALID_FIND_MSG = "*Comando desconocido: {}* \n" \ + "*Para buscar una película usa: /find * \n" + + SAVE_MSG = "*Introduce el ID de IMDB de la Película/Serie junto con /save. \n" \ + "Ve a /help para más detalles.* \n" + + SAVE_REPLY_MSG = "*Usa este comando como respuesta al archivo que se guardará. \n" \ + "Ve a /help para más detalles.* \n" + + REMOVE_MSG = "*Introduce el ID de IMDB de la Película/Serie junto con /remove. \n" \ + "Ve a /help para más detalles.* \n" + + CHECK_STATUS_MSG = "Recopilando datos. Por favor espera ⏲️" + + def __init__(self) -> None: + self.app = Application.builder().token(BOT_API).build() + + # Set up bot memory + self.memory: list = [] + + # Set up bot movie file cache memory + self.movie_memory: list = [] + + # Set up Mysql Database + self.connection = msc.connect( + host=MYSQL_HOST, user=MYSQL_USER, passwd=MYSQL_PASSWORD, database=MYSQL_DATABASE) + self.cursor = self.connection.cursor() + if CREATE_TABLE == 'True': + self.cursor.execute( + "Create table movie_data(imdb_id varchar(20),from_chat_id varchar(20),message_id varchar(20))") + + async def reboot(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + msg = await update.message.reply_text(self.REBOOT_WAIT_MESSAGE) + time.sleep(5) + await msg.edit_text(self.REBOOT_SUCCESS_MESSAGE) + execl(sys.executable, f'"{sys.executable}"', *sys.argv) + + async def status(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + message = await update.message.reply_text(self.CHECK_STATUS_MSG) + if self.connection.is_connected(): + db_status = "Connected ✅" + db_latency = str(round(measure_latency( + host=MYSQL_HOST, port=MYSQL_PORT, timeout=2.5)[0])) + "ms ⏱️" + self.cursor.execute("select count(*) from movie_data") + movie_number = str(self.cursor.fetchone()[0]) + ' 🎬' + else: + db_status = "Desconectado ❌" + db_latency = "N/A ❌" + movie_number = "N/A ❌" + + omdb_params = { + "apikey": OMDB_API, + "t": '2012', + } + + async with aiohttp.ClientSession() as session: + async with session.get(OMDB, params=omdb_params) as response: + movie_data = await response.json() + if movie_data["Response"] != "False": + omdb_status = "API Disponible.✅" + omdb_latency = str(round(measure_latency( + host=OMDB_SITE, timeout=2.5)[0])) + "ms ⏱️" + + find_TMDB = f'https://api.themoviedb.org/3/find/{movie_data["imdbID"]}?api_key={TMDB_API}&external_source=imdb_id' + + async with aiohttp.ClientSession() as session: + async with session.get(find_TMDB) as response: + data = await response.json() + if 'success' not in data.keys(): + tmdb_status = "API Disponible ✅" + tmdb_latency = str(round(measure_latency( + host=TMDB_SITE, timeout=2.5)[0])) + "ms ⏱️" + else: + tmdb_status = "API no disponible ❌" + tmdb_latency = "N/A ❌" + + else: + omdb_status = "API no disponible.❌" + omdb_latency = "N/A ❌" + tmdb_status = "API no disponible.❌" + tmdb_latency = "N/A ❌" + + await message.edit_text(self.STATUS_MESSAGE.format(db_status, db_latency, movie_number, omdb_status, omdb_latency, tmdb_status, tmdb_latency), parse_mode='markdown') + + # /start command + + async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + await update.message.reply_chat_action(action="typing") + await update.message.reply_photo(photo="https://www.pngmart.com/files/15/Baby-Bender-PNG.png", caption=self.INTRO_MSG, parse_mode='markdown') + + # /help command + async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + await update.message.reply_text(self.HELP_MSG, parse_mode='markdown') + + # Replying to text other than commands + async def any_text(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + message_type: str = update.message.chat.type + if message_type not in ['group', 'supergroup']: + await update.message.reply_text(self.INVALID_FIND_MSG.format(update.message.text), parse_mode='markdown') + + # Error Handling + async def error(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + print(f'\nActualizar\n{update.message}\n\ncausa error {context.error}') + await update.message.reply_text("*Lo siento, se encontró un error.*", parse_mode='markdown') + + # /find command + + async def find_title(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + if len(self.memory) == 25: + self.memory = [] + if len(self.movie_memory) == 25: + self.movie_memory = [] + + if "".join(context.args) == "": + await update.message.reply_text(self.FIND_MSG, parse_mode='markdown') + + else: + if "y=" in context.args[-1]: + movie_name = " ".join(context.args[:-1]) + omdb_params = { + "apikey": OMDB_API, + "t": movie_name, + "y": context.args[-1][2:] + } + else: + movie_name = " ".join(context.args) + omdb_params = { + "apikey": OMDB_API, + "t": movie_name, + } + + for item in self.memory: + if movie_name == item["Title"].lower() or movie_name == item['Title']: + movie_data = item + break + else: + async with aiohttp.ClientSession() as session: + async with session.get(OMDB, params=omdb_params) as response: + movie_data = await response.json() + if movie_data["Response"] != "False": + self.memory.append(movie_data) + + if movie_data["Response"] != "False": + data_str = f"🎬 *Título:* {movie_data['Title']} ({movie_data['Year']})\n\n" \ + f"📖 *Género:* {movie_data['Genre']}\n\n" \ + f"⭐ *Rating:* {movie_data['imdbRating']}/10\n\n" \ + f"🕤 *Duración:* {movie_data['Runtime']}\n\n" \ + f"🎭 *Actores:* {movie_data['Actors']}\n\n" \ + f"🧑 *Director:* {movie_data['Director']}\n\n" \ + f"🆔 *IMDB ID:* {movie_data['imdbID']}\n\n" + + if movie_data['Poster'] != 'N/A': + await update.message.reply_photo(photo=movie_data['Poster']) + else: + find_TMDB = f'https://api.themoviedb.org/3/find/{movie_data["imdbID"]}?api_key={TMDB_API}&external_source=imdb_id' + + TMDB_IMAGE_BASE = 'https://image.tmdb.org/t/p/original' + + async with aiohttp.ClientSession() as session: + async with session.get(find_TMDB) as response: + data = await response.json() + if data['movie_results'] != []: + Poster = data['movie_results'][0]['backdrop_path'] + URL = str(TMDB_IMAGE_BASE+Poster) + await update.message.reply_photo(photo=URL) + elif data['tv_results'] != []: + Poster = data['tv_results'][0]['backdrop_path'] + URL = str(TMDB_IMAGE_BASE+Poster) + await update.message.reply_photo(photo=URL) + + buttons = [ + [InlineKeyboardButton("Plot", callback_data=f"{movie_data['Title']};plot"), + InlineKeyboardButton("Ratings", callback_data=f"{movie_data['Title']};ratings")], + [InlineKeyboardButton("Awards", callback_data=f"{movie_data['Title']};awards"), + InlineKeyboardButton( + "Languages", callback_data=f"{movie_data['Title']};languages"), + InlineKeyboardButton("Rated", callback_data=f"{movie_data['Title']};rated")], + [InlineKeyboardButton("IMDB page", url=f"{IMDB_LINK}{movie_data['imdbID']}"), + InlineKeyboardButton("Trailer", url=await self.get_trailer_url(movie_data["imdbID"], movie_data['Title']))], + [InlineKeyboardButton( + "Get Movie", callback_data=f"{movie_data['Title']};getmovie")] + ] + await update.message.reply_text(data_str, reply_markup=InlineKeyboardMarkup(buttons), parse_mode='markdown') + + else: + await update.message.reply_chat_action(action="typing") + await update.message.reply_photo(photo='https://raw.githubusercontent.com/akkupy/movie_bot/main/assets/check_spelling.jpg', caption=self.MOVIE_NOT_FOUND, parse_mode='markdown') + + @staticmethod + async def get_trailer_url(imdb_id: str, Title: str) -> None: + + find_TMDB = f'https://api.themoviedb.org/3/find/{imdb_id}?api_key={TMDB_API}&external_source=imdb_id' + + YOUTUBE_BASE_URL = 'https://www.youtube.com/watch?v=' + + async with aiohttp.ClientSession() as session: + async with session.get(find_TMDB) as response: + data = await response.json() + if data['movie_results'] != []: + TMDB_ID = data['movie_results'][0]['id'] + TYPE = 'movie' + elif data['tv_results'] != []: + TMDB_ID = data['tv_results'][0]['id'] + TYPE = 'tv' + else: + return f'https://www.youtube.com/results?search_query={Title}' + + video_TMDB = f'https://api.themoviedb.org/3/{TYPE}/{TMDB_ID}/videos?api_key={TMDB_API}' + async with session.get(video_TMDB) as response: + data = await response.json() + if data['results'] != []: + video = data['results'][0]['key'] + else: + return f'https://www.youtube.com/results?search_query={Title}' + return YOUTUBE_BASE_URL+video + + @staticmethod + def get_rating(movie_json: dict) -> str: + rating_str: str = "" + for rating in movie_json["Ratings"]: + rating_str += f"{rating['Source']}: {rating['Value']}\n" + return f"*{movie_json['Title']} Ratings* ⭐\n\n{rating_str}" + + @staticmethod + def get_rated(movie_json: dict) -> str: + return f"*{movie_json['Title']} Rated* 🔞\n\n{movie_json['Rated']}" + + @staticmethod + def get_plot(movie_json: dict) -> str: + return f"*{movie_json['Title']} Plot* 📖\n\n{movie_json['Plot']}" + + @staticmethod + def get_languages(movie_json: dict) -> str: + return f"*{movie_json['Title']} Languages* 🗣️\n\n{movie_json['Language']}" + + @staticmethod + def get_awards(movie_json: dict) -> str: + return f"*{movie_json['Title']} Awards* 🏆\n\n{movie_json['Awards']}" + + @staticmethod + def get_movie(self, movie_json: dict) -> str: + Flag = False + for item in self.movie_memory: + if movie_json['imdbID'] == item["imdb_id"]: + file_data = item + break + + else: + self.cursor.execute( + "select count(*) from movie_data where imdb_id = '{}'".format(movie_json['imdbID'])) + if self.cursor.fetchone()[0] != 0: + self.cursor.execute( + "select * from movie_data where imdb_id = '{}'".format(movie_json['imdbID'])) + data = self.cursor.fetchone() + file_data = { + 'imdb_id': data[0], + 'from_chat_id': data[1], + 'message_id': data[2], + } + self.movie_memory.append({ + 'imdb_id': data[0], + 'from_chat_id': data[1], + 'message_id': data[2], + }) + else: + Flag = True + from_chat_id = message_id = None + return from_chat_id, message_id + + if not Flag: + from_chat_id, message_id = file_data['from_chat_id'], file_data['message_id'] + return from_chat_id, message_id + + # Query Handler + + async def query_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + query = update.callback_query.data + await update.callback_query.answer() + + title, kword = query.split(";") + for item in self.memory: + if title == item["Title"]: + data = item + break + else: + omdb_params = { + "apikey": OMDB_API, + "t": title, + } + async with aiohttp.ClientSession() as session: + async with session.get(OMDB, params=omdb_params) as result: + data = await result.json() + self.memory.append(data) + if kword == "ratings": + await update.callback_query.message.reply_text(self.get_rating(data), parse_mode='markdown') + elif kword == "plot": + await update.callback_query.message.reply_text(self.get_plot(data), parse_mode='markdown') + elif kword == "rated": + await update.callback_query.message.reply_text(self.get_rated(data), parse_mode='markdown') + elif kword == "awards": + await update.callback_query.message.reply_text(self.get_awards(data), parse_mode='markdown') + elif kword == "languages": + await update.callback_query.message.reply_text(self.get_languages(data), parse_mode='markdown') + elif kword == "getmovie": + from_chat_id, message_id = self.get_movie(self, data) + if from_chat_id == None: + await update.callback_query.message.reply_text(self.MOVIE_NOT_FOUND_MSG.format(data['Title'], data["imdbID"]), parse_mode='markdown') + else: + await update.callback_query.message._bot.forward_message(update.callback_query.message.chat.id, from_chat_id, message_id) + + async def movie_saver(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + + imdb_id = "".join(context.args) + + if imdb_id == "": + await update.message.reply_text(self.SAVE_MSG, parse_mode='markdown') + + elif update.message.reply_to_message == None: + await update.message.reply_text(self.SAVE_REPLY_MSG, parse_mode='markdown') + else: + message_id = update.message.reply_to_message.id + + from_chat_id = update.message.chat.id + + self.cursor.execute( + "select count(*) from movie_data where imdb_id = '{}'".format(imdb_id)) + if self.cursor.fetchone()[0] == 0: + self.cursor.execute("insert into movie_data values('{}',{},{})".format( + imdb_id, from_chat_id, message_id)) + self.connection.commit() + await update.message.reply_text('*Movie/Series saved on database.*\n', parse_mode='markdown') + else: + await update.message.reply_text('*Movie/Series already present on database.*\n', parse_mode='markdown') + + async def movie_remover(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + + imdb_id = "".join(context.args) + + if imdb_id == "": + await update.message.reply_text(self.REMOVE_MSG, parse_mode='markdown') + + else: + + self.cursor.execute( + "select count(*) from movie_data where imdb_id = '{}'".format(imdb_id)) + if self.cursor.fetchone()[0] != 0: + self.cursor.execute( + "delete from movie_data where imdb_id = '{}'".format(imdb_id)) + self.connection.commit() + await update.message.reply_text('*Movie/Series deleted from database.*\n', parse_mode='markdown') + else: + await update.message.reply_text('*Movie/Series not found on database.*\n', parse_mode='markdown') + + count = 0 + for item in self.movie_memory: + if imdb_id == item["imdb_id"]: + del self.movie_memory[count] + count += 1 + + async def movie_list(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + + self.cursor.execute("select count(*) from movie_data") + number = self.cursor.fetchone()[0] + await update.message.reply_text(f'*{number} Movies/Series 🎬 found on database.*', parse_mode='markdown') diff --git a/catch-all/06_bots_telegram/README.md b/catch-all/06_bots_telegram/README.md index 18f5cfa..bf1d4c2 100644 --- a/catch-all/06_bots_telegram/README.md +++ b/catch-all/06_bots_telegram/README.md @@ -7,7 +7,7 @@ | [Bot de traducción](./03_translator_bot/) | Bot que traduce mensajes a varios idiomas. Loggin | intermedio | | [Bot de clima](./04_clima_bot/) | Bot que devuelve el clima de una ciudad | intermedio | | [Bot de noticias](./05_rss_bot/) | Bot que devuelve noticias de última hora | intermedio | -| **Bot de películas** (próximamente) | Bot que devuelve información de películas | avanzado | +| [Bot de películas](./06_movie_bot/) | Bot que devuelve información de películas | avanzado | | **Bot de series** (próximamente) | Bot que devuelve información de series | avanzado | | **Bot de libros** (próximamente) | Bot que devuelve información de libros | avanzado | | **Bot de recetas** (próximamente) | Bot que devuelve recetas de cocina | avanzado |