From e03c862a35a25cfbac63b6ddffa95819e05d5844 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 10 Aug 2022 13:08:15 +0200 Subject: [PATCH] Locales --- README.md | 11 +++-- README_uk.md | 50 ++++++++++++++++++++ config.json | 11 ++++- locale/en.json | 57 ++++++++++++++++++++++ locale/uk.json | 57 ++++++++++++++++++++++ main.py | 120 +++++++++++++++++++++++++++-------------------- modules/utils.py | 45 +++++++++++++++++- requirements.txt | 3 +- 8 files changed, 294 insertions(+), 60 deletions(-) create mode 100644 README_uk.md create mode 100644 locale/en.json create mode 100644 locale/uk.json diff --git a/README.md b/README.md index b0f339d..4705ebf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # TelegramPoster -This bot is used for one and only task - post pictures from my personal archive. Here's its source code so you can also host a bot and have fun with it. Just don't exepect it to be brilliant. It is not. But hey, you can always fork it ;) +This bot is used for one and only task - post pictures from my personal archive. Here's its source code so you can also host a bot and have fun with it. Just don't exepect it to be brilliant. It is not. But hey, you can always fork it ;) +Шукаєш інструкцію українською? А вона [ось тут](https://git.profitroll.eu/profitroll/TelegramPoster/src/branch/master/README_uk.md) знаходиться) ## Installation To make this bot run at first you need to have a Python interpreter and git. Google is your friend finding it. You can also ignore git and simply download source code, should also work fine. After that you're ready to go. @@ -10,7 +11,7 @@ To make this bot run at first you need to have a Python interpreter and git. Goo > If it's non-standart executable path - you should also change > it in scripts you will use (`loop.sh`, `loop.bat`, `start.sh` and `start.bat`). -1. Download the bot. +1. Download the bot: 1. `git clone https://git.end-play.xyz/profitroll/TelegramSender.git` (if you want to use git) 2. `cd ./TelegramSender` @@ -27,10 +28,10 @@ To make this bot run at first you need to have a Python interpreter and git. Goo You can edit with vim, nano, on Windows it's Notepad or Notepad++. Whatever. If you don't know where to find bot_token and your id - here you can find some hints: [get bot token](https://www.siteguarding.com/en/how-to-get-telegram-bot-api-token), [get your id](https://www.alphr.com/telegram-find-user-id/), [get api_hash and api_id](https://core.telegram.org/api/obtaining_api_id). -5. Add bot to the channel +5. Add bot to the channel: To use your bot of course you need to have a channel or group otherwise makes no sense to have such a bot. [Here](https://stackoverflow.com/a/33497769) you can find a quick guide how to add your bot to a channel. -6. Fill your contents folder +6. Fill your contents folder: Of course bot cannot post something from nothing. Configure your `config.json` what media types bot should post (`"posting", "extensions"`), when to post them (`"posting", "time"`) and also where to find them (`"locations"`). You can also move them when sent by setting `"posting", "move_sent"` to `true`. 6. Good to go, run it! @@ -43,7 +44,7 @@ Of course bot also has them. You can perform some actions with them. * `--move-sent` - allows you to move all sent files from queue to sent directories * `--cleanup` - purge files in both `queue` and `sent` folders if they're sent. Requires `--confirm` argument * `--cleanup-index` - purge all sent entries from index. Requires `--confirm` argument -* `--norun` - allows you to execute above arguments without tiggering the bot start itself +* `--norun` - allows you to execute above arguments without triggering the bot start itself Examples: * `python3 ./main.py --move-sent --norun` diff --git a/README_uk.md b/README_uk.md new file mode 100644 index 0000000..2eca61d --- /dev/null +++ b/README_uk.md @@ -0,0 +1,50 @@ +# TelegramPoster +Цей бот використовується для однієї-єдиної задачі - розміщувати фотографії з мого особистого архіву. Ось його код, тож Ви також можете захостити бота самостійно та розважитися з ним. Тільки не очікуйте, що він ідеальним. Не буде. Але гей, Ви завжди можете його доробити під себе ;) + +## Установка +Для запуску цього бота спочатку потрібно мати інтерпретатор Python та встановлений git. Google — Ваш друг у пошуках. Ви також можете ігнорувати git і просто завантажити код, також має спрацювати добре. Після цього Ви готові до встановлення. + +> У цьому README я вважаю, що Ви використовуєте python за замовчуванням у своїй +> системі і PATH Вашої системи містить його. Якщо Ваш python за замовчуванням +> є `python3` або, наприклад, `/home/user/.local/bin/python3.9` - використовуйте його натомість. +> Якщо це нестандартний шлях до виконуваного файлу - Вам також слід змінити +> це у скриптах, які Ви використовуватимете (`loop.sh`, `loop.bat`, `start.sh` та `start.bat`). + +1. Завантажте бота: + 1. `git clone https://git.end-play.xyz/profitroll/TelegramSender.git` (якщо хочете використовувати git) + 2. `cd ./TelegramSender` + +2. Встановіть залежності: + `python -m pip install -r requirements.txt` + Без їх установки бот не зможе працювати взагалі + +3. Встановіть додаткові залежності [Не обов'язково]: + `python -m pip install -r requirements-optional.txt` + Вони не є обов’язковими, але можуть прискорити роботу бота + +4. Налаштуйте свого бота за допомогою текстового редактора: + `nano config.json` + Ви можете редагувати за допомогою vim, nano, у Windows це Notepad або Notepad++. На Ваш смак. + Якщо Ви не знаєте, де знайти bot_token і свій ідентифікатор, тут Ви можете знайти кілька підказок: [отримати токен бота](https://www.siteguarding.com/en/how-to-get-telegram-bot-api-token), [отримати свій ідентифікатор](https://www.alphr.com/telegram-find-user-id/), [отримати api_hash і api_id](https://core.telegram.org/api/obtaining_api_id ). + +5. Додайте бота на канал: + Звичайно, щоб використовувати свого бота, Вам потрібно мати канал або групу, інакше немає сенсу мати такого бота. [Тут](https://stackoverflow.com/a/33497769) Ви можете знайти короткий гайд, як додати свого бота до каналу. + +6. Заповніть папку вмістом: + Звичайно, бот не може опублікувати щось із нічого. Налаштуйте свій `config.json`, які медіа-типи бот повинен публікувати (`"posting", "extensions"`), коли їх публікувати (`"posting", "time"`), а також де їх знайти (`"locations"`). Ви також можете переміщати їх після надсилання, встановивши для `"posting", "move_sent"` значення `true`. + +6. Готово, запускайте! + `python ./main.py` + Або ви також можете використовувати `.\start.bat` на Windows і `bash ./start.sh` на Linux. + Крім того, доступні `loop.sh` і `loop.bat`, якщо ви хочете, щоб ваш бот запускався знову після зупинки або після використання команди `/reboot`. + +## Аргументи командного рядка +Звичайно, у бота вони також є. З ними можна виконувати деякі дії. +* `--move-sent` - дозволяє перемістити всі надіслані файли з черги до папки надісланих +* `--cleanup` - очистити файли в папках `queue` і `sent`, якщо вони вже надіслані. Потрібен аргумент `--confirm` +* `--cleanup-index` - видалити всі надіслані записи з індексу. Потрібен аргумент `--confirm` +* `--norun` - дозволяє виконувати наведені вище аргументи, не запускаючи самого бота + +Приклади: +* `python3 ./main.py --move-sent --norun` +* `python3 ./main.py --cleanup --confirm` \ No newline at end of file diff --git a/config.json b/config.json index 6356d1b..66d148d 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,7 @@ { "module": null, + "locale": "en", + "locale_fallback": "en", "bot": { "api_id": 0, "api_hash": "", @@ -18,7 +20,8 @@ "sent": "data/sent", "index": "data/index.json", "submit": "data/submit.json", - "blocked": "data/blocked.json" + "blocked": "data/blocked.json", + "locale": "locale" }, "posting": { "channel": 0, @@ -56,5 +59,9 @@ }, "submission": { "timeout": 30 - } + }, + "commands": [ + "start", + "rules" + ] } \ No newline at end of file diff --git a/locale/en.json b/locale/en.json new file mode 100644 index 0000000..b2c423f --- /dev/null +++ b/locale/en.json @@ -0,0 +1,57 @@ +{ + "commands": { + "start": "Start using the bot", + "rules": "Photos submission rules" + }, + "commands_admin": { + "reboot": "Restart the bot" + }, + "message": { + "start": "Hi and welcome!\n\nYou can submit your pictures and videos here. We'll review and add them, if we like them. Make sure you send your stuff one at a time and have chosen media that corresponds to our rules.\n\nYou can also write something to us in the description field. We'll send it with the submission itself, if needed.\n\nAlso, make sure you follow the /rules of submission, otherwise your submission will be declined. In case of spam/abuse you may even be blocked.\n\nHave fun and happy submitting!", + "rules": "Photos submission rules:\n1. No porn, only erotics and aesthetics\n2. Nipples are semi-allowed, should be either veiled or barely visible\n3. Genitalia strictly prohibited, but labia prints on clothes or nice pubes/panties/butts - are fine", + "shutdown": "Shutting down bot with pid `{0}`", + "startup": "Starting with pid `{0}`", + "sub_yes": "✅ Submission approved and accepted", + "sub_no": "❌ Submission reviewed and declined", + "sub_blocked": "You were blocked and you can't submit media anymore.", + "sub_unblocked": "You were unblocked and you can now submit media.", + "sub_by": "\n\nSubmitted by:", + "sub_sent": "Media has been submitted.\nWe'll notify you whether it will be accepted or not soon.", + "sub_cooldown": "You can only submit 1 media per {0} seconds", + "post_exception": "Could not send content due to `{exp}`\n\nTraceback:\n```{0}```", + "post_empty": "Could not send content: `Queue folder is empty or contains only unsupported or already sent files.`" + }, + "button": { + "sub_yes": "✅ Accept", + "sub_no": "❌ Deny", + "sub_block": "☠️ Block sender", + "sub_unblock": "🏳️ Unblock sender", + "post_view": "View in channel" + }, + "callback": { + "sub_yes": "✅ Submission approved", + "sub_no": "❌ Submission declined", + "sub_block": "User {0} has been blocked", + "sub_unblock": "User {0} has been unblocked", + "sub_msg_unavail": "Submission message no longer exist", + "sub_media_unavail": "Could not download submission" + }, + "console": { + "shutdown": "Shutting down bot with pid {0}", + "startup":"Starting with pid {0}", + "keyboard_interrupt": "\nShutting down...", + "exception_occured": "Exception {0} happened on task execution", + "post_exception": "Could not send content due to {0}\nTraceback: {1}", + "post_empty": "Could not send content due to queue folder empty with allowed extensions", + "deps_missing": "Required modules are not installed. Run 'pip3 install -r requirements.txt' and restart the program.", + "passed_norun": "Argument --norun passed, not running the main script", + "move_sent_doesnt_exist": "File '{0}' is already moved or does not exist", + "move_sent_doesnt_exception": "Could not move sent file '{0}' to '{1}' due to {2}", + "move_sent_completed": "Moved all sent files to the sent folder", + "cleanup_exception": "Could not remove '{0}' due to {1}", + "cleanup_completed": "Performed cleanup of the sent files", + "cleanup_unathorized": "Requested cleanup of sent files but not authorized. Please pass '--confirm' to perform that", + "cleanup_index_completed": "Performed cleanup of sent files index", + "cleanup_index_unathorized": "Requested cleanup of sent files index but not authorized. Please pass '--confirm' to perform that" + } +} \ No newline at end of file diff --git a/locale/uk.json b/locale/uk.json new file mode 100644 index 0000000..e5a257e --- /dev/null +++ b/locale/uk.json @@ -0,0 +1,57 @@ +{ + "commands": { + "start": "Почати користуватись ботом", + "rules": "Правила пропонування фото" + }, + "commands_admin": { + "reboot": "Перезапустити бота" + }, + "message": { + "start": "Привіт і ласкаво просимо!\n\nТут можна пропонувати свої фотографії та відео. Ми переглянемо та додамо їх, якщо вони нам сподобаються. Переконайтеся, що ви надсилаєте свої матеріали по одному та вибираєте медіа, які відповідають нашим правилам.\n\nВи також можете написати нам щось у полі опису. За потреби ми надішлемо це разом із самим фото.\n\nКрім того, переконайтеся, що ви дотримуєтеся /rules (правил) подання, інакше вашу пропозицію буде відхилено. У разі спаму/зловживань вас можуть навіть заблокувати.\n\nГарного дня та щасливого надсилання!", + "rules": "Правила для пропонування фото:\n1. Ніякого порно, тільки еротика та естетика\n2. Соски можна, але або завуальовані, або зовсім ледь помітні\n3. Геніталії суворо ні, а ось відбитки статевих губ на одязі або гарні лобочки/трусики/попки - без проблем", + "shutdown": "Вимкнення бота з підом `{0}`", + "startup": "Запуск бота з підом `{0}`", + "sub_yes": "✅ Подання схвалено та прийнято", + "sub_no": "❌ Подання розглянуто та відхилено", + "sub_blocked": "Вас заблокували, і ви більше не можете надсилати медіафайли.", + "sub_unblocked": "Вас розблокували, і тепер ви можете надсилати медіафайли.", + "sub_by": "\n\nПредставлено:", + "sub_sent": "Медіа-файл надіслано.\nСкоро ми повідомимо вас, чи буде його прийнято.", + "sub_cooldown": "Ви можете надсилати лише 1 медіафайл на {0} секунд", + "post_exception": "Не вдалося надіслати контент через `{exp}`\n\nTraceback:\n```{0}```", + "post_empty": "Не вдалося надіслати контент: «Папка черги порожня або містить лише непідтримувані або вже надіслані файли»." + }, + "button": { + "sub_yes": "✅ Прийняти", + "sub_no": "❌ Відхилити", + "sub_block": "☠️ Заблокувати відправника", + "sub_unblock": "🏳️ Розблокувати відправника", + "post_view": "Переглянути на каналі" + }, + "callback": { + "sub_yes": "✅ Подання схвалено", + "sub_no": "❌ Подання відхилено", + "sub_block": "Користувача {0} заблоковано", + "sub_unblock": "Користувача {0} розблоковано", + "sub_msg_unavail": "Повідомлення більше не існує", + "sub_media_unavail": "Не вдалося завантажити подання" + }, + "console": { + "shutdown": "Вимкнення бота з підом {0}", + "startup": "Запуск бота з підом {0}", + "keyboard_interrupt": "\nВимикаюсь...", + "exception_occured": "Помилка {0} сталась під час виконання", + "post_exception": "Не вдалося надіслати контент через {0}\nTraceback: {1}", + "post_empty": "Не вдалося надіслати контент через порожню папку черги з дозволеними розширеннями", + "deps_missing": "Необхідні модулі не встановлені. Запустіть 'pip3 install -r requirements.txt' і перезапустіть програму.", + "passed_norun": "Аргумент --norun надано, основний скрипт не запускається", + "move_sent_doesnt_exist": "Файл '{0}' уже переміщено або він не існує", + "move_sent_doesnt_exception": "Неможливо перемістити надісланий файл '{0}' до '{1}' через {2}", + "move_sent_completed": "Переміщено всі надіслані файли до папки надісланих", + "cleanup_exception": "Не вдалося видалити '{0}' через {1}", + "cleanup_completed": "Виконано очищення надісланих файлів", + "cleanup_unathorized": "Надіслано запит на очищення надісланих файлів, але не авторизовано. Для цього надайте аргумент '--confirm'", + "cleanup_index_completed": "Виконано очищення індексу надісланих файлів", + "cleanup_index_unathorized": "Надіслано запит на очищення індексу надісланих файлів, але не авторизовано. Для цього надайте аргумент '--confirm'" + } +} \ No newline at end of file diff --git a/main.py b/main.py index d868639..39d2f71 100644 --- a/main.py +++ b/main.py @@ -8,7 +8,7 @@ import time import traceback from modules.logging import logWrite -from modules.utils import configGet, jsonLoad, jsonSave +from modules.utils import configGet, jsonLoad, jsonSave, killProc, locale # Args ===================================================================================================================================== if "--move-sent" in sys.argv: @@ -16,10 +16,10 @@ if "--move-sent" in sys.argv: try: shutil.move(configGet("queue", "locations")+os.sep+entry, configGet("sent", "locations")+os.sep+entry) except FileNotFoundError: - logWrite(f"File '{entry}' is already moved or does not exist") + logWrite(locale("move_sent_doesnt_exist", "console", locale=configGet("locale")).format(entry)) except Exception as exp: - logWrite(f"Could not move sent file '{entry}' to '{configGet('sent', 'locations')}' due to {exp}") - logWrite(f"Moved all sent files to the sent folder") + logWrite(locale("move_sent_doesnt_exception", "console", locale=configGet("locale")).format(entry, exp)) + logWrite(locale("move_sent_completed", "console", locale=configGet("locale"))) if "--cleanup" in sys.argv: if "--confirm" in sys.argv: @@ -35,23 +35,23 @@ if "--cleanup" in sys.argv: except FileNotFoundError: pass except Exception as exp: - logWrite(f"Could not remove '{entry}' due to {exp}") + logWrite(locale("cleanup_exception", "console", locale=configGet("locale")).format(entry, exp)) jsonSave(index, jsonLoad(configGet("index", "locations"))) - logWrite(f"Performed cleanup of the sent files") + logWrite(locale("cleanup_completed", "console", locale=configGet("locale"))) else: - logWrite(f"Requested cleanup of sent files but not authorized. Please pass '--confirm' to perform that") + logWrite(locale("cleanup_unathorized", "console", locale=configGet("locale"))) if "--cleanup-index" in sys.argv: if "--confirm" in sys.argv: index = jsonLoad(configGet("index", "locations")) index["sent"] = [] jsonSave(index, jsonLoad(configGet("index", "locations"))) - logWrite(f"Performed cleanup of sent files index") + logWrite(locale("cleanup_index_completed", "console", locale=configGet("locale"))) else: - logWrite(f"Requested cleanup of sent files index but not authorized. Please pass '--confirm' to perform that") + logWrite(locale("cleanup_index_unathorized", "console", locale=configGet("locale"))) if "--norun" in sys.argv: - logWrite("Argument --norun passed, not running the main script") + logWrite(locale("passed_norun", "console", locale=configGet("locale"))) sys.exit() #=========================================================================================================================================== @@ -62,7 +62,7 @@ try: from pyrogram import Client, filters, idle # type: ignore from pyrogram.types import ChatPermissions, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton, BotCommand, BotCommandScopeChat # type: ignore except ModuleNotFoundError: - print(f"Required modules are not installed. Run 'pip3 install -r requirements.txt' and restart the program.", flush=True) + print(locale("deps_missing", "console", locale=configGet("locale")), flush=True) sys.exit() #=========================================================================================================================================== @@ -106,9 +106,9 @@ def send_content(): candidate_file = random.choice(list_queue) candidate = configGet("queue", "locations")+os.sep+candidate_file else: - logWrite(f"Could not send content due to queue folder empty with allowed extensions") + logWrite(locale("post_empty", "console", locale=configGet("locale"))) if configGet("error", "reports"): - app.send_message(configGet("admin", "reports"), f"Could not send content: `Queue folder is empty or contains only unsupported or already sent files.`") # type: ignore + app.send_message(configGet("admin", "reports"), locale("post_empty", "message", locale=configGet("locale"))) # type: ignore return if ext_type == "photo": # type: ignore @@ -143,22 +143,27 @@ def send_content(): ])) # type: ignore except Exception as exp: - logWrite(f"Could not send content due to {exp}") + logWrite(f"Could not send content due to {exp}\nTraceback: {traceback.format_exc()}") if configGet("error", "reports"): - app.send_message(configGet("admin", "reports"), f"Could not send content due to `{exp}`\n\nTraceback:\n```{traceback.format_exc()}```") # type: ignore + app.send_message(configGet("admin", "reports"), locale("post_exception", "message", locale=configGet("locale")).format(exp, traceback.format_exc())) # type: ignore -@app.on_message(~ filters.scheduled & filters.command(["start", "help"], prefixes="/")) +@app.on_message(~ filters.scheduled & filters.command(["start"], prefixes="/")) def start(app, msg): if msg.from_user.id not in jsonLoad(configGet("blocked", "locations")): - msg.reply_text(f"Hi and welcome!\n\nYou can submit your pictures and videos here. We'll review and add them, if we like them. Make sure you send your stuff one at a time and have chosen media that corresponds to our rules.\n\nYou can also write something to us in the description field. We'll send it with the submission itself, if needed.\n\nHave fun and happy submitting!") + msg.reply_text(locale("start", "message", locale=msg.from_user.language_code)) + +@app.on_message(~ filters.scheduled & filters.command(["rules", "help"], prefixes="/")) +def start(app, msg): + if msg.from_user.id not in jsonLoad(configGet("blocked", "locations")): + msg.reply_text(locale("rules", "message", locale=msg.from_user.language_code)) @app.on_message(~ filters.scheduled & filters.command(["kill", "die", "reboot"], prefixes=["", "/"])) def kill(app, msg): if msg.from_user.id == configGet("admin", "reports"): - msg.reply_text(f"Shutting down bot with pid `{pid}`") - os.system('kill -9 '+str(pid)) + msg.reply_text(locale("shutdown", "message", locale=configGet("locale")).format(str(pid))) + killProc(pid) # Submission ===================================================================================================================================== @@ -195,6 +200,7 @@ def subUnblock(user): @app.on_message(~ filters.scheduled & filters.photo | filters.video | filters.animation) def get_submission(_, msg): if msg.from_user.id not in jsonLoad(configGet("blocked", "locations")): + user_locale = msg.from_user.language_code if not subLimited(msg.from_user): if msg.caption != None: @@ -202,7 +208,7 @@ def get_submission(_, msg): else: caption = "" - caption += "\n\nSubmitted by:" + caption += locale("sub_by", "message", locale=locale(configGet("locale"))) if msg.from_user.first_name != None: caption += f" {msg.from_user.first_name}" @@ -215,62 +221,66 @@ def get_submission(_, msg): msg.copy(configGet("admin", "reports"), caption=caption, reply_markup=InlineKeyboardMarkup([ [ - InlineKeyboardButton(text="✅ Accept", callback_data=f"sub_yes_{msg.from_user.id}_{msg.id}"), - InlineKeyboardButton(text="❌ Deny", callback_data=f"sub_no_{msg.from_user.id}_{msg.id}") + InlineKeyboardButton(text=locale("sub_yes", "button", locale=configGet("locale")), callback_data=f"sub_yes_{msg.from_user.id}_{msg.id}"), + InlineKeyboardButton(text=locale("sub_no", "button", locale=configGet("locale")), callback_data=f"sub_no_{msg.from_user.id}_{msg.id}") ], [ - InlineKeyboardButton(text="☠️ Block sender", callback_data=f"sub_block_{msg.from_user.id}") + InlineKeyboardButton(text=locale("sub_block", "button", locale=configGet("locale")), callback_data=f"sub_block_{msg.from_user.id}") ], [ - InlineKeyboardButton(text="🏳️ Unblock sender", callback_data=f"sub_unblock_{msg.from_user.id}") + InlineKeyboardButton(text=locale("sub_unblock", "button", locale=configGet("locale")), callback_data=f"sub_unblock_{msg.from_user.id}") ] ] )) - msg.reply_text(f"Media has been submitted.\nWe'll notify you whether it will be accepted or not soon.", quote=True) + msg.reply_text(locale("sub_sent", "message", locale=user_locale), quote=True) subLimit(msg.from_user) else: - msg.reply_text(f'You can only submit 1 media per {configGet("timeout", "submission")} seconds') + msg.reply_text(locale("sub_cooldown", "message", locale=user_locale).format(str(configGet("timeout", "submission")))) @app.on_callback_query(filters.regex("sub_yes_[\s\S]*_[\s\S]*")) # type: ignore def callback_query_yes(app, clb): # type: ignore fullclb = clb.data.split("_") + user_locale = clb.from_user.language_code try: submission = app.get_messages(int(fullclb[2]), int(fullclb[3])) except: - clb.answer(text=f"Submission message no longer exist", show_alert=True) + clb.answer(text=locale("sub_msg_unavail", "message", locale=user_locale), show_alert=True) return try: app.download_media(submission, file_name=configGet("queue", "locations")+os.sep) except: - clb.answer(text=f"Could not download submission", show_alert=True) + clb.answer(text=locale("sub_media_unavail", "message", locale=user_locale), show_alert=True) return - submission.reply_text(f"✅ Submission approved and accepted", quote=True) - clb.answer(text=f"✅ Submission approved", show_alert=True) + submission.reply_text(locale("sub_yes", "message", locale=submission.from_user.language_code), quote=True) + clb.answer(text=locale("sub_yes", "callback", locale=user_locale).format(fullclb[2]), show_alert=True) @app.on_callback_query(filters.regex("sub_no_[\s\S]*_[\s\S]*")) # type: ignore def callback_query_no(app, clb): # type: ignore fullclb = clb.data.split("_") + user_locale = clb.from_user.language_code try: submission = app.get_messages(int(fullclb[2]), int(fullclb[3])) except: - clb.answer(text=f"Submission message no longer exist", show_alert=True) + clb.answer(text=locale("sub_msg_unavail", "message", locale=user_locale), show_alert=True) return - submission.reply_text(f"❌ Submission reviewed and declined", quote=True) - clb.answer(text=f"❌ Submission declined", show_alert=True) + submission.reply_text(locale("sub_no", "message", locale=submission.from_user.language_code), quote=True) + clb.answer(text=locale("sub_no", "callback", locale=user_locale).format(fullclb[2]), show_alert=True) @app.on_callback_query(filters.regex("sub_block_[\s\S]*")) # type: ignore def callback_query_block(app, clb): # type: ignore fullclb = clb.data.split("_") - app.send_message(int(fullclb[2]), "You were blocked and you can't submit media anymore.") + user_locale = clb.from_user.language_code + app.send_message(int(fullclb[2]), locale("sub_msg_unavail", "message", locale=configGet("locale"))) subBlock(int(fullclb[2])) - clb.answer(text=f"User {fullclb[2]} has been blocked", show_alert=True) + clb.answer(text=locale("sub_block", "callback", locale=user_locale).format(fullclb[2]), show_alert=True) @app.on_callback_query(filters.regex("sub_unblock_[\s\S]*")) # type: ignore def callback_query_unblock(app, clb): # type: ignore fullclb = clb.data.split("_") - app.send_message(int(fullclb[2]), "You were unblocked and you can now submit media.") + user_locale = clb.from_user.language_code + app.send_message(int(fullclb[2]), locale("sub_msg_unavail", "message", locale=configGet("locale"))) subUnblock(int(fullclb[2])) - clb.answer(text=f"User {fullclb[2]} has been unblocked", show_alert=True) + clb.answer(text=locale("sub_unblock", "callback", locale=user_locale).format(fullclb[2]), show_alert=True) #=========================================================================================================================================== @@ -287,34 +297,44 @@ def background_task(): except: pass except Exception as exp: - logWrite(f"Exception {exp} happened on task execution") + logWrite(locale("exception_occured", "console", locale=configGet("locale")).format(exp)) except KeyboardInterrupt: - logWrite('\nShutting down...') - app.send_message(configGet("admin", "reports"), f"Shutting down with PID `{pid}`") # type: ignore - os.system('kill -9 '+str(pid)) + logWrite(locale("keyboard_interrupt", "console", locale=configGet("locale"))) + if configGet("shutdown", "reports"): + app.send_message(configGet("admin", "reports"), locale("shutdown", "message", locale=configGet("locale")).format(str(pid))) # type: ignore + killProc(pid) if __name__ == "__main__": - logWrite(f'Starting with PID {pid}') + logWrite(locale("startup", "console", locale=configGet("locale")).format(str(pid))) app.start() # type: ignore - app.send_message(configGet("admin", "reports"), f"Starting with pid `{pid}`") # type: ignore + if configGet("startup", "reports"): + app.send_message(configGet("admin", "reports"), locale("startup", "message", locale=configGet("locale")).format(str(pid))) # type: ignore t = Thread(target=background_task) t.start() - app.set_bot_commands([ # type: ignore - BotCommand("start", "Start using the bot") - ]) + for entry in os.listdir(configGet("locale", "locations")): + if entry.endswith(".json"): + commands_list = [] + for command in configGet("commands"): + commands_list.append(BotCommand(command, locale(command, "commands", locale=entry.replace(".json", "")))) + app.set_bot_commands(commands_list, language_code=entry.replace(".json", "")) + + commands_list = [] + for command in configGet("commands"): + commands_list.append(BotCommand(command, locale(command, "commands", locale=configGet("locale_fallback")))) + app.set_bot_commands(commands_list) app.set_bot_commands([ # type: ignore - BotCommand("reboot", "Reboot the bot"), + BotCommand("reboot", locale("reboot", "commands_admin", locale=configGet("locale"))), ], scope=BotCommandScopeChat(chat_id=configGet("admin", "reports"))) idle() - app.send_message(configGet("admin", "reports"), f"Shutting down with pid `{pid}`") # type: ignore - logWrite(f'Shutting down with PID {pid}') + app.send_message(configGet("admin", "reports"), locale("shutdown", "message", locale=configGet("locale")).format(str(pid))) # type: ignore + logWrite(locale("shutdown", "console", locale=configGet("locale")).format(str(pid))) - subprocess.call(f'kill -9 {pid}', shell=True) # type: ignore \ No newline at end of file + killProc(pid) \ No newline at end of file diff --git a/modules/utils.py b/modules/utils.py index 63b588b..ddab2c8 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -3,7 +3,9 @@ try: except ModuleNotFoundError: import json - +import os +from signal import SIGKILL +import psutil def jsonLoad(filename): """Loads arg1 as json and returns its contents""" @@ -51,4 +53,43 @@ def configGet(key: str, *args: str): this_key = this_dict for dict_key in args: this_key = this_key[dict_key] - return this_key[key] \ No newline at end of file + return this_key[key] + +def locale(key: str, *args: list, locale=configGet("locale")): + """Get value of locale string + Args: + * key (str): The last key of the locale's keys path. + * *args (list): Path to key like: dict[args][key]. + * locale (str): Locale to looked up in. Defaults to config's locale value. + Returns: + * any: Value of provided locale key + """ + if (locale == None): + locale = configGet("locale") + + try: + this_dict = jsonLoad(f'{configGet("locale", "locations")}{os.sep}{locale}.json') + except FileNotFoundError: + try: + this_dict = jsonLoad(f'{configGet("locale", "locations")}{os.sep}{configGet("locale")}.json') + except FileNotFoundError: + try: + this_dict = jsonLoad(f'{configGet("locale_fallback", "locations")}{os.sep}{configGet("locale")}.json') + except: + return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' + + this_key = this_dict + for dict_key in args: + this_key = this_key[dict_key] + + try: + return this_key[key] + except KeyError: + return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' + +def killProc(pid): + if os.name == "posix": + os.kill(pid, SIGKILL) + else: + p = psutil.Process(pid) + p.kill() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 4e5cb94..1acfbc8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ schedule -pyrogram>=2.0.0 \ No newline at end of file +pyrogram>=2.0.0 +psutil \ No newline at end of file