-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Customizable texts via Project Fluent (#9)
* Updated all dependencies to their actual versions * Updated pydantic to v2 along with config * Added Project Fluent library and its loader * Updates field validators * Added SpinTextFilter to handle localized spin text * Make localized spin keyboard * Cache created keyboard, since it's always the same until restart * Pass config through dispatcher * Use localized texts for handlers * Greatly speed up getting dice combo text * Optionally send zero balance sticker (easter egg?) * Added more config parameters * Deleted const.py file * Use throttle time from config * Updated LICENSE * Translated dice_check.py to English * Localizable bot commands * More comments in spin.py * Added sample localization files for RU and EN * Hardcode sleep after slot machine spin * Updated env_example * Added README.md in English, updated README.ru.md in Russian * Removed .gitlab-ci.yml * Updated docker-compose.example.yml
- Loading branch information
1 parent
09ef66c
commit 389cbc6
Showing
23 changed files
with
402 additions
and
211 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,37 @@ | ||
[<img src="https://img.shields.io/badge/Telegram-%40DifichentoBot-blue">](https://t.me/DifichentoBot) | ||
[<img src="https://img.shields.io/badge/Telegram-%40DifichentoBot-blue">](https://t.me/DifichentoBot) (Ru) | ||
|
||
# Виртуальное казино в Telegram | ||
> 🇷🇺 README на русском доступен [здесь](README.ru.md) | ||
В конце октября 2020 года команда Telegram выпустила [очередное обновление](https://telegram.org/blog/pinned-messages-locations-playlists/ru?ln=a) | ||
мессенджера с поддержкой дайса игрового автомата. Вот он: | ||
# Telegram Virtual Casino | ||
|
||
![игровой автомат](repo_images/slot_machine.png) | ||
In October 2020 Telegram team released [yet another update](https://telegram.org/blog/pinned-messages-locations-playlists) | ||
with slot machine dice. Here it is: | ||
|
||
Согласно [документации на тип Dice](https://core.telegram.org/bots/api#dice) в Bot API, слот-машина | ||
может принимать значения от 1 до 64 включительно. В файле `casino.py` вы найдёте функции для сопоставления значения дайса | ||
с тройкой выпавших элементов игрового автомата. Для демонстрации создан бот [@DifichentoBot](https://t.me/difichentobot) с | ||
ведением счёта на виртуальные очки, начиная с 50. | ||
Важным отличием от «традиционного» казино является невозможность влиять | ||
на выпадающие комбинации, т.к. итоговое значение генерируется на стороне Telegram. | ||
![slot machine dice](repo_images/slot_machine.png) | ||
|
||
## Технологии | ||
According to [Dice type documentation](https://core.telegram.org/bots/api#dice) in Bot API, slot machine | ||
emits values 1 to 64. In [dice_check.py](bot/dice_check.py) file you can find all the logic regarding | ||
matching dice integer value with visual three-icons representation. There is also a test bot [@DifichentoBot](https://t.me/difichentobot) | ||
in Russian to test how it works. | ||
Dice are generated on Telegram server-side, you your bot cannot affect the result. | ||
|
||
* [aiogram](https://github.com/aiogram/aiogram) — работа с Telegram Bot API; | ||
* [redis](https://redis.io) — персистентное хранение данных; | ||
* [cachetools](https://cachetools.readthedocs.io/en/stable) — реализация троттлинга для борьбы с флудом; | ||
* [Docker](https://www.docker.com) и [Docker-Compose](https://docs.docker.com/compose) — быстрое разворачивание бота \ | ||
в изолированном контейнере. | ||
## Technology | ||
|
||
* [aiogram](https://github.com/aiogram/aiogram) — asyncio Telegram Bot API framework; | ||
* [redis](https://redis.io) — persistent data storage (persistency enabled separately); | ||
* [cachetools](https://cachetools.readthedocs.io/en/stable) — for anti-flood throttling mechanism; | ||
* [Docker](https://www.docker.com) and [Docker-Compose](https://docs.docker.com/compose) — quickly deploy bot in containers. | ||
* Systemd | ||
|
||
## Установка | ||
## Installation | ||
|
||
Скопируйте файл `env_example` как `.env` (с точкой в начале), откройте и отредактируйте содержимое. Создайте каталоги | ||
`redis_data` и `redis_config`, в последний подложите свой конфиг `redis.conf` (в репозитории есть пример). \ | ||
Запустите бота командой `docker-compose up -d`. | ||
Copy `env_example` file to `.env` (with leading dot), open and edit it. Create `redis_data` and `redis_config` | ||
directories, put `redis.conf` file into the latter (there is [example](redis.example.conf) in this repo). | ||
Run the bot with `docker-compose up -d` command. | ||
|
||
Альтернативный вариант: используйте Systemd, пример службы тоже есть в репозитории. | ||
Alternative way: you can use Systemd services, there is also an [example](casino-bot.example.service) available. | ||
|
||
## Благодарности | ||
## Credits to | ||
|
||
* [@Tishka17](https://t.me/Tishka17) за изначальный вектор направления | ||
* [@svinerus](https://t.me/svinerus) за компактную реализацию определения выпавшей комбинации (f6f42a841d3c1778f0e32) | ||
* [@Tishka17](https://t.me/Tishka17) for initial inspiration | ||
* [@svinerus](https://t.me/svinerus) for compact dice combination check (f6f42a841d3c1778f0e32) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
[<img src="https://img.shields.io/badge/Telegram-%40DifichentoBot-blue">](https://t.me/DifichentoBot) | ||
|
||
# Виртуальное казино в Telegram | ||
|
||
В конце октября 2020 года команда Telegram выпустила [очередное обновление](https://telegram.org/blog/pinned-messages-locations-playlists/ru?ln=a) | ||
мессенджера с поддержкой дайса игрового автомата. Вот он: | ||
|
||
![игровой автомат](repo_images/slot_machine.png) | ||
|
||
Согласно [документации на тип Dice](https://core.telegram.org/bots/api#dice) в Bot API, слот-машина | ||
может принимать значения от 1 до 64 включительно. В файле [dice_check.py](bot/dice_check.py) вы найдёте функции | ||
для сопоставления значения дайса с тройкой выпавших элементов игрового автомата. | ||
Для демонстрации создан бот [@DifichentoBot](https://t.me/difichentobot) с ведением счёта на виртуальные очки. | ||
Важным отличием от «традиционного» казино является невозможность влиять | ||
на выпадающие комбинации, т.к. итоговое значение генерируется на стороне Telegram. | ||
|
||
## Технологии | ||
|
||
* [aiogram](https://github.com/aiogram/aiogram) — работа с Telegram Bot API; | ||
* [redis](https://redis.io) — персистентное хранение данных (персистентность включается отдельно); | ||
* [cachetools](https://cachetools.readthedocs.io/en/stable) — реализация троттлинга для борьбы с флудом; | ||
* [Docker](https://www.docker.com) и [Docker-Compose](https://docs.docker.com/compose) — быстрое разворачивание бота в изолированном контейнере. | ||
* Systemd | ||
|
||
## Установка | ||
|
||
Скопируйте файл `env_example` как `.env` (с точкой в начале), откройте и отредактируйте содержимое. Создайте каталоги | ||
`redis_data` и `redis_config`, в последний подложите свой конфиг `redis.conf` | ||
(в репозитории есть [пример](redis.example.conf)). Запустите бота командой `docker-compose up -d`. | ||
|
||
Альтернативный вариант: используйте Systemd, пример службы тоже есть в [репозитории](casino-bot.example.service). | ||
|
||
## Благодарности | ||
|
||
* [@Tishka17](https://t.me/Tishka17) за изначальный вектор направления | ||
* [@svinerus](https://t.me/svinerus) за компактную реализацию определения выпавшей комбинации (f6f42a841d3c1778f0e32) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,31 @@ | ||
from enum import Enum | ||
from typing import Optional | ||
|
||
from pydantic import BaseSettings, validator, SecretStr, RedisDsn | ||
from pydantic import field_validator, SecretStr, RedisDsn, FieldValidationInfo | ||
from pydantic_settings import BaseSettings, SettingsConfigDict | ||
|
||
|
||
class Settings(BaseSettings): | ||
bot_token: SecretStr | ||
fsm_mode: str | ||
redis: Optional[RedisDsn] | ||
class FSMMode(str, Enum): | ||
MEMORY = "memory" | ||
REDIS = "redis" | ||
|
||
@validator("fsm_mode") | ||
def fsm_type_check(cls, v): | ||
if v not in ("memory", "redis"): | ||
raise ValueError("Incorrect fsm_mode. Must be one of: memory, redis") | ||
return v | ||
|
||
@validator("redis") | ||
def skip_validating_redis(cls, v, values): | ||
if values["fsm_mode"] == "redis" and v is None: | ||
raise ValueError("Redis config is missing, though fsm_type is 'redis'") | ||
class Settings(BaseSettings): | ||
bot_token: SecretStr | ||
fsm_mode: FSMMode | ||
redis: Optional[RedisDsn] = None | ||
bot_language: str | ||
starting_points: int = 50 | ||
send_gameover_sticker: bool = False | ||
throttle_time_spin: int = 2 | ||
throttle_time_other: int = 1 | ||
|
||
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8') | ||
|
||
@field_validator("redis", mode="after") | ||
@classmethod | ||
def skip_validating_redis(cls, v: Optional[RedisDsn], info: FieldValidationInfo): | ||
if info.data.get("fsm_mode") == FSMMode.REDIS and v is None: | ||
err = 'FSM Mode is set to "Redis", but Redis DNS is missing!' | ||
raise ValueError(err) | ||
return v | ||
|
||
class Config: | ||
env_file = '.env' | ||
env_file_encoding = 'utf-8' | ||
|
||
|
||
config = Settings() |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from .spin_text_filter import SpinTextFilter | ||
|
||
__all__ = [ | ||
"SpinTextFilter" | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from aiogram.filters import BaseFilter | ||
from aiogram.types import Message | ||
from fluent.runtime import FluentLocalization | ||
|
||
|
||
class SpinTextFilter(BaseFilter): | ||
async def __call__(self, message: Message, l10n: FluentLocalization) -> bool: | ||
return message.text == l10n.format_value("spin-button-text") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from pathlib import Path | ||
|
||
from fluent.runtime import FluentLocalization, FluentResourceLoader | ||
|
||
|
||
def get_fluent_localization(language: str) -> FluentLocalization: | ||
""" | ||
Loads FTL files for chosen language | ||
:param language: language name, as passed from configuration outside | ||
:return: FluentLocalization object with loaded FTL files for chosen language | ||
""" | ||
|
||
# Check "locales" directory on the same level as this file | ||
locales_dir = Path(__file__).parent.joinpath("locales") | ||
if not locales_dir.exists(): | ||
err = '"locales" directory does not exist' | ||
raise FileNotFoundError(err) | ||
if not locales_dir.is_dir(): | ||
err = '"locales" is not a directory' | ||
raise NotADirectoryError(err) | ||
|
||
locales_dir = locales_dir.absolute() | ||
locale_dir_found = False | ||
for directory in Path.iterdir(locales_dir): | ||
if directory.stem == language: | ||
locale_dir_found = True | ||
break | ||
if not locale_dir_found: | ||
err = f'Directory for "{language}" locale not found' | ||
raise FileNotFoundError(err) | ||
|
||
locale_files = list() | ||
for file in Path.iterdir(Path.joinpath(locales_dir, language)): | ||
if file.suffix == ".ftl": | ||
locale_files.append(str(file.absolute())) | ||
l10n_loader = FluentResourceLoader(str(Path.joinpath(locales_dir, "{locale}"))) | ||
|
||
return FluentLocalization([language], locale_files, l10n_loader) |
Oops, something went wrong.