Index: MMANDS
===================================================================
--- COMMANDS	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,16 +1,0 @@
-This file is intended to send command list to @BotFather:
-
-about - Show information about the bot
-set - Set new users to queue (overrides old users)
-add - Add new users to exisiting queue
-list - List of all added users
-queue - Same as /list
-users - Same as /list
-remove - Remove users from queue entirely
-chooser - Set specific user as a chooser for next film
-next - Show who is choosing next movie
-movie - Add new movie by IMDB id
-movies - List of all added movies
-event - Create an event or modify planned one
-events - List all created events
-announce - Post an announcement to planned created event
Index: README
===================================================================
--- README	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ README	(revision ca5a97ee010dcf122b1b39f63800d17571bcf44a)
@@ -2,14 +2,2 @@
 
 Public Domain (CC0) software for managing cinema clubs in group chats.
-
-Install python itself:
-sudo apt install python3 python-is-python3
-
-You can install dependencies on Debian-based systems using apt and pip:
-
-export PYTHONUSERBASE=~/.local
-pip install --user --break-system-packages -r requirements.txt
-
-python main.py
-# or for background run
-nohup python main.py
Index: app.py
===================================================================
--- app.py	(revision ca5a97ee010dcf122b1b39f63800d17571bcf44a)
+++ app.py	(revision ca5a97ee010dcf122b1b39f63800d17571bcf44a)
@@ -0,0 +1,29 @@
+# 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
+from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes
+from dotenv import load_dotenv
+import os
+
+load_dotenv()
+
+
+async def hello(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
+    await update.message.reply_text(f'Hello {update.effective_user.first_name}')
+
+app = ApplicationBuilder().token(
+    os.environ.get('TELEGRAM_TOKEN')
+).build()
+
+app.add_handler(CommandHandler("hello", hello))
+
+app.run_polling()
Index: mmands/__init__.py
===================================================================
--- commands/__init__.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,18 +1,0 @@
-# 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 .meta import about
-from .users import set_users, add_users, list_users, remove_users, \
-    chooser_user, who_is_next
-from .movie import movie, movies
-from .event import create_event, list_events
-from .announce import create_announcement
-
Index: mmands/announce.py
===================================================================
--- commands/announce.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,56 +1,0 @@
-# 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 strings import ANNOUNCEMENT_TEMPLATE, ANNOUNCEMENT_FINISHED_EVENT, \
-    ANNOUNCEMENT_EVENT_NEEDS_EDITING
-from utils import context_init, create_users_string, choose_next_user
-from predicates import has_unfinished_event
-
-async def create_announcement(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    intro = " ".join(context.args)
-
-    events = context.chat_data["events"]
-    movies = context.chat_data["movies"]
-
-    if has_unfinished_event(context):
-        last_event = events[-1]
-        last_movie = movies[-1]
-
-        if last_event["when"] is None or last_event["where"] is None or last_event["movie"] is None:
-            raise error.TelegramError(ANNOUNCEMENT_EVENT_NEEDS_EDITING)
-
-        genres ="#" + " #".join(last_movie["genres"])
-
-        await update.message.reply_markdown(
-            ANNOUNCEMENT_TEMPLATE.format(
-                intro=intro,
-                movie_title=last_movie["title"],
-                movie_id=last_movie["id"],
-                movie_runtime=last_movie["runtime"][0],
-                when=last_event["when"],
-                where=last_event["where"],
-                user=last_movie["user"],
-                rating=last_movie["rating"],
-                genres=genres,
-            )
-        )
-
-        return
-
-    await update.message.reply_text(ANNOUNCEMENT_FINISHED_EVENT)
Index: mmands/event.py
===================================================================
--- commands/event.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,137 +1,0 @@
-# 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 datetime import datetime
-
-from utils import context_init, normalize_username
-from predicates import is_past, has_finished_movie, has_event_without_movie
-from strings import EVENT_ARGS_NOT_PROVIDED, EVENT_INVALID_DATETIME, \
-    EVENT_CREATED, EVENT_EDITED, EVENT_CANT_BE_IN_PAST, \
-    EVENT_WHERE_NOT_PROVIDED, EVENT_MOVIE_NOT_CHOOSEN, EVENTS_LIST, \
-    EVENT_FINISHED, NO_EVENTS, EVENTS_LIST_PLANNING, EVENTS_LIST_MOVIE_SET
-
-
-async def create_event(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-    users = context.chat_data["users"]
-    events = context.chat_data["events"]
-    movies = context.chat_data["movies"]
-
-    last_movie = movies[-1] if movies != [] else None
-
-    if last_movie is None:
-        raise error.TelegramError(EVENT_MOVIE_NOT_CHOOSEN)
-
-    if has_finished_movie(context):
-        raise error.TelegramError(EVENT_FINISHED)
-
-    if context.args == []:
-        raise error.TelegramError(EVENT_ARGS_NOT_PROVIDED)
-
-    argument_when = context.args[0]
-
-    try:
-        event_when = datetime.strptime(argument_when, "%d.%m.%Y/%H:%M")
-    except ValueError:
-        raise error.TelegramError(EVENT_INVALID_DATETIME)
-
-    if is_past(event_when):
-        raise error.TelegramError(
-            EVENT_CANT_BE_IN_PAST.format(
-                when=event_when,
-                today=datetime.today(),
-            )
-        )
-
-    arguments_where = context.args[1:]
-
-    if arguments_where == [] and events == []:
-        raise error.TelegramError(EVENT_WHERE_NOT_PROVIDED)
-
-    old_when = events[-2]["when"] if len(events) >= 2 else None
-    old_where = events[-2]["where"] if len(events) >= 2 else None
-
-    event_where = " ".join(arguments_where) if arguments_where != [] else old_where
-
-    event_dict = dict(
-        when=event_when,
-        where=event_where,
-        movie=last_movie["title"],
-        user=last_movie["user"]
-    )
-
-    if len(events) > 0:
-        events[-1] = event_dict
-    else:
-        events.append(event_dict)
-
-    await update.message.reply_text(
-        EVENT_EDITED.format(
-            old_when=old_when,
-            old_where=old_where,
-            when=event_when,
-            where=event_where,
-            movie=event_dict["movie"],
-        )
-    )
-
-
-async def list_events(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    users = context.chat_data["users"]
-    events = context.chat_data["events"]
-    last_event = events[-1] if events != [] else None
-
-    if last_event and last_event["movie"] is None:
-        last_event["user"] = normalize_username(users[0])
-
-    events_formatted: str = ""
-
-    for event in events:
-        event_status = "FINISHED" \
-            if is_past(event["when"]) else "PLANNED"
-
-        if event["movie"] is None:
-            breakpoint()
-            event_status = "PLANNING"
-            events_formatted += EVENTS_LIST_PLANNING.format(
-                user=event["user"],
-                status=event_status
-            )
-        elif event["when"] is None or event["where"] is None:
-            event_status = "PLANNING"
-            events_formatted += EVENTS_LIST_MOVIE_SET.format(
-                user=event["user"],
-                movie=event["movie"],
-                status=event_status
-            )
-        else:
-            events_formatted += EVENTS_LIST.format(
-                movie=event["movie"],
-                user=event["user"],
-                when=event["when"],
-                where=event["where"],
-                status=event_status
-            )
-
-    if events_formatted == "":
-        events_formatted = NO_EVENTS
-
-    await update.message.reply_text(events_formatted)
Index: mmands/meta.py
===================================================================
--- commands/meta.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,36 +1,0 @@
-# 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
-from telegram.ext import ContextTypes
-from subprocess import check_output
-
-from strings import ABOUT
-
-
-VERSION="0.1"
-
-
-def _get_commit_hash() -> str:
-    return check_output(['git', 'rev-parse', 'HEAD']).decode('ascii').strip()
-
-
-def _get_commit_short_hash() -> str:
-    return check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip()
-
-
-async def about(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
-    await update.message.reply_text(
-        ABOUT.format(
-            version=VERSION,
-            commit=_get_commit_short_hash(),
-        )
-    )
Index: mmands/movie.py
===================================================================
--- commands/movie.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,110 +1,0 @@
-# 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 utils import context_init, choose_next_user, normalize_username, \
-    init_new_event
-from predicates import has_finished_movie
-from strings import MOVIE_NOT_PROVIDED, EXPECTED_ONE_MOVIE, \
-    MOVIE_ANOTHER_USER, FETCHING_MOVIE, FETCHING_ERROR, \
-    MOVIE_REMOVE, MOVIE_SET, MOVIES_LIST, NO_MOVIES, ADD_MORE_USERS
-
-
-imdb = Cinemagoer()
-
-
-async def movie(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    users = context.chat_data["users"]
-
-    if users == []:
-        raise error.TelegramError(ADD_MORE_USERS)
-
-    chooser = users[0]
-    username = update.message.from_user.username
-
-    if has_finished_movie(context):
-        users = context.chat_data["users"] = choose_next_user(context)
-
-    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,
-        rating=movie.data.get("rating"),
-        genres=movie.data.get("genres"),
-        runtime=movie.data.get("runtimes"),
-    )
-
-    if len(context.chat_data["movies"]) > 0 and \
-       context.chat_data["movies"][-1]["user"] == username:
-        context.chat_data["movies"][-1] = movie_dict
-
-        last_event = context.chat_data["events"][-1] \
-            if len(context.chat_data["events"]) > 0 else None
-
-        if last_event and context.chat_data["events"][-1]["user"] == username:
-            last_event["title"] = movie_dict["title"]
-            context.chat_data["events"][-1] = last_event
-    else:
-        init_new_event(context, users[0], movie_dict["title"])
-        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"]
-
-    movies_formatted: str = ""
-
-    for movie in movies:
-        movies_formatted += MOVIES_LIST.format(
-            title=movie["title"],
-            user=movie["user"]
-        )
-
-    if movies_formatted == "":
-        movies_formatted = NO_MOVIES
-
-    await update.message.reply_text(movies_formatted)
-
Index: mmands/users.py
===================================================================
--- commands/users.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,154 +1,0 @@
-# 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 collections import deque
-
-from strings import USER_NOT_PROVIDED, USERS_ADDED, USERS_REMOVED, \
-    EXPECTED_ONE_USER, USER_SET, USER_REMOVE, ADD_MORE_USERS, \
-    NEXT_MOVIE_USER, USER_NOT_FOUND, USER_CHOOSE, NO_USERS, \
-    NEXT_MOVIE
-from utils import context_init, create_users_string, choose_next_user, \
-    normalize_username
-from predicates import has_finished_movie, has_event_without_movie
-
-
-async def set_users(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    if context.args == []:
-        raise error.TelegramError(USER_NOT_PROVIDED)
-
-    context.chat_data["users"] = context.args
-
-    await update.message.reply_text(USER_SET)
-
-
-async def add_users(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    if context.args == []:
-        raise error.TelegramError(USER_NOT_PROVIDED)
-
-    for user in context.args:
-        context.chat_data["users"].append(user)
-
-    await update.message.reply_text(USERS_ADDED)
-
-
-async def list_users(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    users = context.chat_data["users"]
-
-    if users == []:
-        await update.message.reply_text(NO_USERS)
-        return
-
-    if has_finished_movie(context):
-        users = context.chat_data["users"] = choose_next_user(context)
-
-    await update.message.reply_markdown(create_users_string(users))
-
-
-async def who_is_next(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    """
-    This commands sets the next chooser if needed and shows current
-    """
-
-    context_init(context)
-
-    users = context.chat_data["users"]
-
-    if users == []:
-        raise error.TelegramError(ADD_MORE_USERS)
-
-    if has_finished_movie(context):
-        users = context.chat_data["users"] = choose_next_user(context)
-
-    next_user_string = NEXT_MOVIE_USER.format(user=users[0])
-
-    last_movie = context.chat_data["movies"][-1] \
-        if context.chat_data["movies"] != [] else None
-
-    if last_movie and last_movie["user"] == normalize_username(users[0]):
-        next_user_string += NEXT_MOVIE.format(movie=last_movie["title"])
-
-    await update.message.reply_text(next_user_string)
-
-
-async def remove_users(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    if context.args == []:
-        raise error.TelegramError(USER_NOT_PROVIDED)
-
-    for user in context.args:
-        if user == "*":
-            context.chat_data["users"] = []
-            break
-
-        context.chat_data["users"].remove(user)
-        await update.message.reply_text(USER_REMOVE.format(user=user))
-
-    await update.message.reply_text(USERS_REMOVED)
-
-
-async def chooser_user(
-        update: Update,
-        context: ContextTypes.DEFAULT_TYPE
-) -> None:
-    context_init(context)
-
-    if context.args == []:
-        raise error.TelegramError(USER_NOT_PROVIDED)
-
-    if len(context.args) > 1:
-        raise error.TelegramError(EXPECTED_ONE_USER)
-
-    chooser = context.args[0]
-    users = deque(context.chat_data["users"])
-
-    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
-
-    if has_finished_movie(context):
-        users = context.chat_data["users"] = choose_next_user(context)
-
-    if has_event_without_movie(context):
-        context.chat_data["events"][-1]["user"] = users[0]
-
-    await update.message.reply_text(USER_CHOOSE.format(user=users[0]))
-
-    await update.message.reply_markdown(create_users_string(users))
Index: in.py
===================================================================
--- main.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,82 +1,0 @@
-# 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
-from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, \
-    MessageHandler, filters
-from dotenv import load_dotenv
-import os
-import logging
-
-from strings import INVALID_COMMAND, UNDEFINED_ERROR
-from persistence import Persistence
-import commands
-
-
-load_dotenv()
-
-logging.basicConfig(
-    level=logging.INFO,
-    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-)
-
-
-async def unknown(update: Update, context: ContextTypes.DEFAULT_TYPE):
-    await context.bot.send_message(
-        chat_id=update.effective_chat.id,
-        text=INVALID_COMMAND
-    )
-
-
-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=error_message
-    )
-
-if __name__ == "__main__":
-    app = ApplicationBuilder().token(
-        os.environ.get("TELEGRAM_TOKEN")
-    ).persistence(Persistence).build()
-
-    # Meta commands
-    app.add_handler(CommandHandler("about", commands.about))
-
-    # Event commands
-    app.add_handler(CommandHandler("event", commands.create_event))
-    app.add_handler(CommandHandler("events", commands.list_events))
-    app.add_handler(CommandHandler("announce", commands.create_announcement))
-
-    # Movie commands
-    app.add_handler(CommandHandler("movie", commands.movie))
-    app.add_handler(CommandHandler("movies", commands.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("users", commands.list_users))
-    app.add_handler(CommandHandler("queue", 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)
-
-
-    app.run_polling()
-
Index: rsistence.py
===================================================================
--- persistence.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,3 +1,0 @@
-from telegram.ext import PicklePersistence
-
-Persistence = PicklePersistence(filepath='db')
Index: edicates.py
===================================================================
--- predicates.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,54 +1,0 @@
-# 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.ext import ContextTypes
-from datetime import datetime
-from typing import Optional
-
-
-def is_past(dt: Optional[datetime]) -> bool:
-    if dt is None:
-        return False
-
-    return dt < datetime.today()
-
-
-def has_finished_movie(context: ContextTypes.DEFAULT_TYPE) -> bool:
-    events = context.chat_data["events"]
-    movies = context.chat_data["movies"]
-
-    last_event = events[-1] if events != [] else None
-    last_movie = movies[-1] if movies != [] else None
-
-    return last_event is not None and last_movie is not None and \
-        last_event["user"] == last_movie["user"] and \
-        is_past(last_event["when"])
-
-
-def has_event_without_movie(context: ContextTypes.DEFAULT_TYPE) -> bool:
-    events = context.chat_data["events"]
-    last_event = events[-1] if events != [] else None
-
-    return last_event and last_event["movie"] is None
-
-
-def has_unfinished_event(context: ContextTypes.DEFAULT_TYPE) -> bool:
-    events = context.chat_data["events"]
-    last_event = events[-1] if events != [] else None
-
-    if last_event is None:
-        return False
-
-    if last_event["movie"] is None:
-        return False
-
-    return not is_past(last_event["when"])
-
Index: requirements.txt
===================================================================
--- requirements.txt	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ requirements.txt	(revision ca5a97ee010dcf122b1b39f63800d17571bcf44a)
@@ -1,3 +1,2 @@
 python-dotenv==0.20.0
 python-telegram-bot==21.6
-cinemagoer==2023.5.1
Index: rings.py
===================================================================
--- strings.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,99 +1,0 @@
-# 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/>
-
-INVALID_COMMAND = "Invalid command. Available commands: /add /list /remove /chooser /about"
-
-MOVIE_ANOTHER_USER = "Movie should choose another user ({user})"
-MOVIE_NOT_PROVIDED = "Movie IMDB id is not provided. Use /movie <imdb_id>"
-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"
-MOVIES_LIST = "\"{title}\" by {user} \n"
-NO_MOVIES = "No movies.  You can add movie if you are next to choose (see /next). Too add a movie use /movie <imdb_id>"
-
-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}"
-NEXT_MOVIE = " and they have choosen to watch \"{movie}\""
-
-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}"
-NO_USERS = "No user added. You can add users by /add <nickname1> <nickname2>"
-
-EVENT_INVALID_DATETIME = """
-Can't parse provided datetime. It should comply template like this:
-/event 1.08.2024/18:00 <where>
-"""
-EVENT_CANT_BE_IN_PAST = "Event can't happen in the past. You set {when}, but now is {today}"
-EVENT_ARGS_NOT_PROVIDED = """
-Event commands need arguments provided:
-/event <when> <where>
-/event 1.08.2024/18:00 84 Erevan Str 1st entrance 7 floor 451 apartment
-"""
-EVENT_WHERE_NOT_PROVIDED = """
-Second <where> argument is not provided and previous event doesn't has it.
-/event <when> <where>
-/event 1.08.2024/18:00 84 Erevan Str 1st entrance 7 floor 451 apartment
-"""
-
-EVENT_CREATED = "Event \"{movie}\" at {when} was created"
-EVENT_EDITED = "Event \"{movie}\" at {old_when} in {old_where} was modified to {when} in {where}"
-EVENTS_LIST = "[{status}] \"{movie}\" by {user} at {when} in {where}\n"
-EVENTS_LIST_MOVIE_SET = "[{status}] \"{movie}\" by {user}\n"
-EVENTS_LIST_PLANNING = "[{status}] by {user}\n"
-EVENT_MOVIE_NOT_CHOOSEN = "You should choose a film first using /movie <imdb_id>"
-EVENT_MOVIE_NOT_SET = "<None>"
-EVENT_USER_HAD_MOVIE = "User {user} can't set the sa, so he can't choose twice. See /next or /list"
-EVENT_FINISHED = "Event is finished. Use /next to see who chooses a film now."
-NO_EVENTS = "No events."
-
-UNDEFINED_ERROR = "Exception: something unexpected happened. Check the logs."
-
-ANNOUNCEMENT_EVENT_NEEDS_EDITING = "Event is missing either Movie, When or Where fields. See /event"
-ANNOUNCEMENT_FINISHED_EVENT = "There is no planned events. Create one using /event <when> <where>"
-ANNOUNCEMENT_TEMPLATE = """
-{intro}
-
-Movie: {movie_title}
-Choosen by: @{user}
-Runtime: {movie_runtime} minutes
-
-When: {when}
-Where: {where}
-
-Rating: {rating}
-Genres: {genres}
-
-https://imdb.com/title/tt{movie_id}/
-"""
-
-ABOUT = """
-v{version} #{commit}
-
-python-cinema-club-bot is a bot for Telegram specialized for managing cinema club activities. This software is released as Public Domain using CC0 license.
-
-Project information: http://57.129.46.169/trac/wiki/python-cinema-club-bot
-Source code: http://57.129.46.169/cgit/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/>
-    """
Index: ils.py
===================================================================
--- utils.py	(revision ac7b16a5ac02b9a8b4b8c42bcb97f0e27c61ac0c)
+++ 	(revision )
@@ -1,65 +1,0 @@
-# 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.ext import ContextTypes
-from collections import deque
-from typing import Optional
-
-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] = []
-
-    if "events" not in context.chat_data:
-        context.chat_data["events"]: list[dict] = []
-
-    return context
-
-
-def normalize_username(username: str):
-    return username.replace("@", "")
-
-
-def create_users_string(users: list[str]) -> str:
-    return "`" + ", ".join(users) + "`"
-
-
-def choose_next_user(context: ContextTypes.DEFAULT_TYPE) -> list[dict]:
-    users = deque(context.chat_data["users"])
-    users.rotate(-1)  # -1 moves list to left by 1 element
-
-    init_new_event(context, users[0])
-
-    return list(users)
-
-
-def init_new_event(context: ContextTypes.DEFAULT_TYPE, user: dict, movie: Optional[str] = None):
-    events = context.chat_data["events"]
-
-    last_event = events[-1] if events != [] else None
-
-    init_event = dict(
-        when=None,
-        where=None,
-        movie=movie,
-        user=user
-    )
-
-    if last_event and last_event["movie"] is None:
-        events[-1] = init_event
-    else:
-        events.append(init_event)
