# █ █ ▀ █▄▀ ▄▀█ █▀█ ▀ # █▀█ █ █ █ █▀█ █▀▄ █ # © Copyright 2022 # https://t.me/hikariatama # # 🔒 Licensed under the GNU AGPLv3 # 🌐 https://www.gnu.org/licenses/agpl-3.0.html # scope: hikka_min 1.2.10 # meta pic: https://img.icons8.com/stickers/500/000000/cards.png # meta banner: https://mods.hikariatama.ru/badges/flash_cards.jpg # meta developer: @hikarimods import asyncio import io import json import re from random import randint from telethon.tl.types import Message from .. import loader, utils TEMPLATE = """ Testing ^title_deck_name^

^deck_name^

Loading...

Start test
""" @loader.tds class FlashCardsMod(loader.Module): """Flash cards for learning""" strings = { "name": "FlashCards", "deck_not_found": "🚫 Deck not foundYou haven't provided deck name", "deck_created": "#Deck #{} {} successfully created!", "deck_removed": "🚫 Deck removed", "save_deck_no_reply": ( "🚫 This command should be used in reply to message with deck items." ), "deck_saved": "✅ Deck saved!", "generating_page": "⚙️ Generating page, please wait ...", "offline_testing": "📖 Offline testing, based on deck {}", } strings_ru = { "deck_not_found": "🚫 Дека не найденаТы не указал имя деки", "deck_created": "#Deck #{} {} успешно создана!", "deck_removed": "🚫 Дека удалена", "save_deck_no_reply": ( "🚫 Эта команда должна выполняться в ответ на измененную деку." ), "deck_saved": "✅ Дека сохранена!", "generating_page": "⚙️ Генерирую страницу, секунду...", "offline_testing": "📖 Оффлайн тестирование на основе деки {}", "_cmd_doc_newdeck": " - Создать новую деку", "_cmd_doc_decks": "Показать деки", "_cmd_doc_deletedeck": " - Удалить деку", "_cmd_doc_listdeck": " - Показать деку", "_cmd_doc_editdeck": " - Редактировать деку", "_cmd_doc_savedeck": " - Сохранить деку", "_cmd_doc_htmldeck": " - Сгенерировать оффлайн-тестирование по деке", "_cls_doc": "Флеш-карты для обучения", } strings_de = { "deck_not_found": "🚫 Deck nicht gefundenDu hast keinen Decknamen angegeben", "deck_created": "#Deck #{} {} erfolgreich erstellt!", "deck_removed": "🚫 Deck entfernt", "save_deck_no_reply": ( "🚫 Dieser Befehl sollte in Antwort auf eine Nachricht mit" " Deck-Elementen" " verwendet werden." ), "deck_saved": "✅ Deck gespeichert!", "generating_page": "⚙️ Seite wird generiert, bitte warten ...", "offline_testing": "📖 Offline-Testing basierend auf dem Deck {}", "_cmd_doc_newdeck": " - Erstelle ein neues Deck", "_cmd_doc_decks": "Zeige Decks", "_cmd_doc_deletedeck": " - Deck löschen", "_cmd_doc_listdeck": " - Deck anzeigen", "_cmd_doc_editdeck": " - Deck bearbeiten", "_cmd_doc_savedeck": " - Deck speichern", "_cmd_doc_htmldeck": " - Offline-Testing basierend auf dem Deck", "_cls_doc": "Flash-Karten für das Lernen", } strings_tr = { "deck_not_found": "🚫 Deck bulunamadıDeck adı belirtmedin", "deck_created": "#Deck #{} {} başarıyla oluşturuldu!", "deck_removed": "🚫 Deck kaldırıldı", "save_deck_no_reply": "🚫 Bu komut, deck öğeleriyle yanıtlanmalıdır.", "deck_saved": "✅ Deck kaydedildi!", "generating_page": "⚙️ Sayfa oluşturuluyor, lütfen bekleyin ...", "offline_testing": "📖 {} deckine dayalı çevrimdışı test", "_cmd_doc_newdeck": " - Yeni bir deck oluştur", "_cmd_doc_decks": "Deckleri göster", "_cmd_doc_deletedeck": " - Deck sil", "_cmd_doc_listdeck": " - Decki göster", "_cmd_doc_editdeck": " - Decki düzenle", "_cmd_doc_savedeck": " - Decki kaydet", "_cmd_doc_htmldeck": " - Decke dayalı çevrimdışı test oluştur", "_cls_doc": "Öğrenmek için flaş kartlar", } strings_hi = { "deck_not_found": "🚫 डेक नहीं मिलाआपने डेक का नाम नहीं दिया", "deck_created": "#Deck #{} {} सफलतापूर्वक बनाया गया!", "deck_removed": "🚫 डेक हटा दिया गया", "save_deck_no_reply": ( "🚫 यह कमांड डेक आइटम के साथ उत्तर देने के लिए उपयोग किया जाना चाहिए।" ), "deck_saved": "✅ डेक सहेज लिया गया!", "generating_page": "⚙️ पेज उत्पन्न किया जा रहा है, कृपया प्रतीक्षा करें ...", "offline_testing": "📖 {} डेक पर आधारित ऑफ़लाइन परीक्षण", "_cmd_doc_newdeck": "<नाम> - एक नया डेक बनाएं", "_cmd_doc_decks": "डेक दिखाएं", "_cmd_doc_deletedeck": "<आईडी> - डेक हटाएं", "_cmd_doc_listdeck": "<आईडी> - डेक दिखाएं", "_cmd_doc_editdeck": "<आईडी> - डेक संपादित करें", "_cmd_doc_savedeck": "<उत्तर> - डेक सहेजें", "_cmd_doc_htmldeck": "<आईडी> - डेक पर आधारित ऑफ़लाइन परीक्षण बनाएं", "_cls_doc": "फ्लैश कार्ड अध्ययन के लिए", } strings_uz = { "deck_not_found": "🚫 Deck topilmadiDeck nomini kiritmadingiz", "deck_created": "#Deck #{} {} muvaffaqiyatli yaratildi!", "deck_removed": "🚫 Deck o'chirildi", "save_deck_no_reply": ( "🚫 Bu buyruq deck elementlari bilan javob berilishi kerak." ), "deck_saved": "✅ Deck saqlandi!", "generating_page": "⚙️ Sahifa yaratilmoqda, iltimos kuting ...", "offline_testing": "📖 {} deckiga asoslangan oflayn test", "_cmd_doc_newdeck": " - Yangi deck yaratish", "_cmd_doc_decks": "Decklarni ko'rsatish", "_cmd_doc_deletedeck": " - Deckni o'chirish", "_cmd_doc_listdeck": " - Deckni ko'rsatish", "_cmd_doc_editdeck": " - Deckni tahrirlash", "_cmd_doc_savedeck": " - Deckni saqlash", "_cmd_doc_htmldeck": " - Deckiga asoslangan oflayn test yaratish", "_cls_doc": "O'rganish uchun flash kartalar", } async def client_ready(self): self.decks = self.get("decks", {}) def get_deck_from_reply(self, reply, limit=None): if reply is None: return False if "#Deck" in reply.text: counter = 1 for line in reply.text.split("\n"): line = line.split() if len(line) > 1: deck = ( line[1] .replace("", "") .replace("", "") .replace("#", "") ) try: int(deck) except Exception: pass if deck in self.decks: if ( limit is None or not limit and "#Decks" not in reply.text or counter == limit ): return deck else: counter += 1 return False async def get_from_message(self, message: Message): args = utils.get_args_raw(message) try: args = args.split()[0] except Exception: pass if args.startswith("#"): args = args[1:] try: int_args = int(args) except Exception: args = False int_args = False if int(int_args) < 1000: args = self.get_deck_from_reply(await message.get_reply_message(), int_args) if not args or args not in self.decks: await utils.answer(message, self.strings("deck_not_found")) await asyncio.sleep(2) await message.delete() return False return args async def newdeckcmd(self, message: Message): """ - New deck of cards""" args = utils.get_args_raw(message) if args == "": await utils.answer(message, self.strings("no_deck_name")) await asyncio.sleep(2) await message.delete() return random_id = str(randint(10000, 99999)) self.decks[random_id] = {"name": args, "cards": [("sample", "sample")]} self.set("decks", self.decks) await utils.answer( message, self.strings("deck_created").format(random_id, args), ) async def deckscmd(self, message: Message): """List decks""" res = "#Decks:\n\n" for counter, (item_id, item) in enumerate(self.decks.items(), start=1): if len(item["cards"]) == 0: items = "No cards" else: items = "".join( f"\n {front} - {back}" for front, back in item["cards"][:2] ) if len(item["cards"]) > 2: items += "\n <...>" res += ( f"🔸{counter}. {item_id} |" f" {item['name']}{items}\n\n" ) await utils.answer(message, res) async def deletedeckcmd(self, message: Message): """ - Delete deck""" deck_id = await self.get_from_message(message) if not deck_id: return del self.decks[deck_id] self.set("decks", self.decks) reply = await message.get_reply_message() if reply: if "#Decks" in reply.text: await self.deckscmd(reply) elif "#Deck" in reply.text: await reply.edit(reply.text + "\n" + self.strings("deck_removed")) await utils.answer(message, self.strings("deck_removed")) async def listdeckcmd(self, message: Message): """ - List deck items""" deck_id = await self.get_from_message(message) if not deck_id: return deck = self.decks[deck_id] res = f"📋#Deck #{deck_id} {deck['name']}:\n➖➖➖➖➖➖➖➖➖➖" for i, (front, back) in enumerate(deck["cards"], start=1): res += f"\n{i}. {front} - {back}" await utils.answer(message, res) async def editdeckcmd(self, message: Message): """ - Edit deck items""" deck_id = await self.get_from_message(message) if not deck_id: return deck = self.decks[deck_id] res = f"📋#Deck #{deck_id} \"{deck['name']}\":\n➖➖➖➖➖➖➖➖➖➖" for front, back in deck["cards"]: res += f"\n{front} - {back}" res += ( "\n➖➖➖➖➖➖➖➖➖➖\nEdit and type .savedeck in reply to" " this" " message\nNote: you can edit title and cards, but other message should" " stay untouched, otherwise it can be saved incorrectly! #Editing" ) await utils.answer(message, res) def remove_html(self, text): return re.sub(r"<.*?>", "", text) async def savedeckcmd(self, message: Message): """ - Save deck. Do not use if you don't know what is this""" reply = await message.get_reply_message() if not reply or "#Editing" not in reply.text: await utils.answer(message, self.strings("save_deck_no_reply")) await asyncio.sleep(2) await message.delete() return False deck_id = await self.get_from_message(message) if not deck_id: return deck = self.decks[deck_id] self.decks[deck_id]["cards"] = [] items = reply.text.split("\n") for item in items[2:-3]: self.decks[deck_id]["cards"].append( ( self.remove_html(item.split(" - ")[0]), self.remove_html(item.split(" - ")[1]), ) ) try: self.decks[deck_id]["name"] = self.remove_html( re.search(r""(.+?)"", items[0]).group(1) ) except Exception: pass self.set("decks", self.decks) res = f"📋#Deck #{deck_id} {deck['name']}:\n➖➖➖➖➖➖➖➖➖➖" for i, (front, back) in enumerate(deck["cards"], start=1): res += f"\n{i}. {front} - {back}" res += "\n➖➖➖➖➖➖➖➖➖➖\n" + self.strings("deck_saved") await utils.answer(reply, res) await message.delete() async def htmldeckcmd(self, message: Message): """ - Generates the page with specified deck""" deck_id = await self.get_from_message(message) if not deck_id: return deck = self.decks[deck_id] await utils.answer(message, self.strings("generating_page")) deck_name = deck["name"] loc_cards = deck["cards"].copy() cards = dict(loc_cards) json_cards = json.dumps(cards).replace('"', '\\"') txt = io.BytesIO( TEMPLATE.replace("^title_deck_name^", deck_name) .replace("^deck_name^", deck_name) .replace("^json_cards^", json_cards) .encode("utf-8") ) txt.name = "testing.html" await message.delete() await message.client.send_file( message.to_id, txt, caption=self.strings("offline_testing").format(deck_name), )