summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Kirillov <w96k@runbox.com>2024-10-09 04:53:26 +0400
committerMikhail Kirillov <w96k@runbox.com>2024-10-09 22:46:19 +0400
commit662342863e37e8661f818218df7bb72bc18bf4eb (patch)
tree79ff9b3884a36e7afec820a8b7c3f235f2e6f1f1
parent0d48ea28aeb8a6290d2aeab202efa9c8d6e30fe3 (diff)
Add movies commands
-rw-r--r--commands/__init__.py4
-rw-r--r--commands/movie.py105
-rw-r--r--commands/users.py36
-rw-r--r--main.py13
-rw-r--r--requirements.txt1
-rw-r--r--strings.py18
-rw-r--r--utils.py15
7 files changed, 181 insertions, 11 deletions
diff --git a/commands/__init__.py b/commands/__init__.py
index b494867..09c0867 100644
--- a/commands/__init__.py
+++ b/commands/__init__.py
@@ -10,4 +10,6 @@
# <http://creativecommons.org/publicdomain/zero/1.0/>
from .meta import about
-from .users import set_users, add_users, list_users, remove_users, chooser_user
+from .users import set_users, add_users, list_users, remove_users, \
+ chooser_user, who_is_next
+from .movie import movie, movies, remove_movies
diff --git a/commands/movie.py b/commands/movie.py
new file mode 100644
index 0000000..b7be8cd
--- /dev/null
+++ b/commands/movie.py
@@ -0,0 +1,105 @@
+# This file is part of python-cinema-club-bot
+# contributed in 2024 by Mikhail Kirillov (~w96k) <w96k@runbox.com>
+
+# To the extent possible under law, the author(s) have dedicated all copyright
+# and related and neighboring rights to this software to the public domain
+# worldwide. This software is distributed without any warranty.
+
+# You should have received a copy of the CC0 Public Domain Dedication along
+# with this software. If not, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+
+from telegram import Update, error
+from telegram.ext import ContextTypes
+from imdb import Cinemagoer
+from pprint import pformat
+
+from utils import context_init
+
+from strings import MOVIE_NOT_PROVIDED, EXPECTED_ONE_MOVIE, \
+ MOVIE_ANOTHER_USER, FETCHING_MOVIE, FETCHING_ERROR, \
+ MOVIE_REMOVE, MOVIE_SET
+
+
+imdb = Cinemagoer()
+
+
+async def movie(
+ update: Update,
+ context: ContextTypes.DEFAULT_TYPE
+) -> None:
+ context_init(context)
+
+ chooser = context.chat_data["users"][0] or None
+ username = update.message.from_user.username
+
+ if "@"+username != chooser:
+ raise error.TelegramError(MOVIE_ANOTHER_USER.format(user=chooser))
+
+ if context.args == []:
+ raise error.TelegramError(MOVIE_NOT_PROVIDED)
+
+ if len(context.args) > 1:
+ raise error.TelegramError(EXPECTED_ONE_MOVIE)
+
+ movie_id = context.args[0]
+
+ await update.message.reply_text(FETCHING_MOVIE.format(id=movie_id))
+
+ try:
+ movie = imdb.get_movie(movie_id)
+ except:
+ raise error.TelegramError(FETCHING_ERROR)
+
+ movie_dict = dict(
+ title=movie.data.get("title"),
+ id=movie.getID(),
+ user=update.effective_user.username,
+ poster=movie.data.get("cover url")
+ )
+
+ if len(context.chat_data["movies"]) > 0 and \
+ context.chat_data["movies"][-1]["user"] == username:
+ context.chat_data["movies"][-1] = movie_dict
+ else:
+ context.chat_data["movies"].append(movie_dict)
+
+ await update.message.reply_text(
+ MOVIE_SET.format(title=movie_dict["title"], user=movie_dict["user"])
+ )
+
+
+async def movies(
+ update: Update,
+ context: ContextTypes.DEFAULT_TYPE
+) -> None:
+ context_init(context)
+
+ movies = context.chat_data["movies"].copy()
+
+ for movie in movies:
+ if movie["poster"] or None:
+ del movie["poster"]
+
+ await update.message.reply_text(pformat(movies))
+
+
+async def remove_movies(
+ update: Update,
+ context: ContextTypes.DEFAULT_TYPE
+) -> None:
+ context_init(context)
+
+ if context.args == []:
+ raise error.TelegramError(MOVIE_NOT_PROVIDED)
+
+ movies = context.chat_data["movies"]
+
+ for movie_id in context.args:
+ for movie in movies:
+ if movie["id"] == movie_id:
+ context.chat_data["movies"].remove(movie)
+ await update.message.reply_text(
+ MOVIE_REMOVE.format(title=movie["title"], id=["movie.id"])
+ )
+
diff --git a/commands/users.py b/commands/users.py
index 413b681..497d7dd 100644
--- a/commands/users.py
+++ b/commands/users.py
@@ -14,8 +14,9 @@ from telegram.ext import ContextTypes
from collections import deque
from strings import USER_NOT_PROVIDED, USERS_ADDED, USERS_REMOVED, \
- EXPECTED_ONE_USER, USER_SET, USER_ADD, USER_REMOVE
-from utils import context_init
+ EXPECTED_ONE_USER, USER_SET, USER_ADD, USER_REMOVE, ADD_MORE_USERS, \
+ NEXT_MOVIE_USER, USER_NOT_FOUND, USER_CHOOSE
+from utils import context_init, create_users_string
async def set_users(
@@ -53,7 +54,23 @@ async def list_users(
) -> None:
context_init(context)
- await update.message.reply_text(context.chat_data["users"])
+ users = context.chat_data["users"]
+
+ await update.message.reply_markdown(create_users_string(users))
+
+
+async def who_is_next(
+ update: Update,
+ context: ContextTypes.DEFAULT_TYPE
+) -> None:
+ context_init(context)
+
+ users = context.chat_data["users"]
+
+ if len(users) > 0:
+ await update.message.reply_text(NEXT_MOVIE_USER.format(user=users[0]))
+ else:
+ await update.message.reply_text(ADD_MORE_USERS)
async def remove_users(
@@ -91,9 +108,16 @@ async def chooser_user(
chooser = context.args[0]
users = deque(context.chat_data["users"])
- chooser_index = users.index(chooser)
+ try:
+ chooser_index = users.index(chooser)
+ except ValueError:
+ raise error.TelegramError(USER_NOT_FOUND.format(user=chooser))
+
users.rotate(-chooser_index)
+ users = list(users)
+
+ context.chat_data["users"] = users
- context.chat_data["users"] = list(users)
+ await update.message.reply_text(USER_CHOOSE.format(user=users[0]))
- await update.message.reply_text(context.chat_data["users"])
+ await update.message.reply_markdown(create_users_string(users))
diff --git a/main.py b/main.py
index 10c05a7..6035f76 100644
--- a/main.py
+++ b/main.py
@@ -16,7 +16,7 @@ from dotenv import load_dotenv
import os
import logging
-from strings import INVALID_COMMAND
+from strings import INVALID_COMMAND, UNDEFINED_ERROR
from persistence import Persistence
import commands
@@ -38,9 +38,12 @@ async def unknown(update: Update, context: ContextTypes.DEFAULT_TYPE):
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
logging.error("Exception:", exc_info=context.error)
+ error_message = context.error.message \
+ if hasattr(context.error, "message") else UNDEFINED_ERROR
+
await context.bot.send_message(
chat_id=update.effective_chat.id,
- text=context.error.message
+ text=error_message
)
if __name__ == "__main__":
@@ -52,11 +55,17 @@ if __name__ == "__main__":
app.add_handler(CommandHandler("about", commands.about))
# Movie commands
+ app.add_handler(CommandHandler("movie", commands.movie))
+ app.add_handler(CommandHandler("movies", commands.movies))
+ app.add_handler(CommandHandler("movies_remove", commands.remove_movies))
+
+ # Users commands
app.add_handler(CommandHandler("set", commands.set_users))
app.add_handler(CommandHandler("add", commands.add_users))
app.add_handler(CommandHandler("list", commands.list_users))
app.add_handler(CommandHandler("remove", commands.remove_users))
app.add_handler(CommandHandler("chooser", commands.chooser_user))
+ app.add_handler(CommandHandler("next", commands.who_is_next))
app.add_handler(MessageHandler(filters.COMMAND, unknown))
app.add_error_handler(error_handler)
diff --git a/requirements.txt b/requirements.txt
index b07e05a..7f8ae4c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
python-dotenv==0.20.0
python-telegram-bot==21.6
+cinemagoer==2023.5.1
diff --git a/strings.py b/strings.py
index 84171b8..4a51308 100644
--- a/strings.py
+++ b/strings.py
@@ -10,11 +10,29 @@
# <http://creativecommons.org/publicdomain/zero/1.0/>
INVALID_COMMAND = "Invalid command. Available commands: /add /list /remove /chooser /about"
+
+MOVIE_ANOTHER_USER = "Movie should choose another user ({user})"
+MOVIE_NOT_PROVIDED = "Movie is not provided"
+MOVIE_NOT_FOUND = "Movie not found on IMDB"
+EXPECTED_ONE_MOVIE = "Expected only one movie"
+FETCHING_MOVIE = "Movie with ID {id} is being fetched: https://imdb.com/title/tt{id}/"
+FETCHING_ERROR = "Couldn't fetch movie or it is not found. Provide IMDB id, for example: 0133093"
+MOVIE_REMOVE = "Movie \"{title}\" with id {id} has been removed"
+MOVIE_SET = "Movie \"{title}\" proposed by {user} is succesfully set as next to watch"
+
+USER_NOT_FOUND = "Provided user ({user}) not found. Check /list"
USER_NOT_PROVIDED = "User(s) is not provided"
EXPECTED_ONE_USER = "Expected only one user"
+ADD_MORE_USERS = "There is no users added. You can add people who can choose movies using /add nickname"
+NEXT_MOVIE_USER = "Next movie choice is up to {user}"
+
USER_ADD = "User {user} has been added"
USERS_ADDED = "Users have been added successfully. Use /list to view."
+
USER_REMOVE = "User {user} has been removed. Use /list to view."
USERS_REMOVED = "Users has been removed"
+
USER_SET = "Users have been set successfully. Use /list to view."
+USER_CHOOSE = "Next movie should choose: {user}"
+UNDEFINED_ERROR = "Exception: something unexpected happened. Check the logs."
diff --git a/utils.py b/utils.py
index 4b28c03..93ad3ed 100644
--- a/utils.py
+++ b/utils.py
@@ -13,11 +13,22 @@ from telegram.ext import ContextTypes
def context_init(context: ContextTypes.DEFAULT_TYPE):
- '''
+ """
Initialize chat context with starting values
- '''
+ """
if "users" not in context.chat_data:
context.chat_data["users"]: list[str] = []
+ if "movies" not in context.chat_data:
+ context.chat_data["movies"]: list[dict] = []
+
return context
+
+
+def normalize_username(username: str):
+ return username.replace("@", "")
+
+
+def create_users_string(users: list[str]) -> str:
+ return "`" + ", ".join(users) + "`"