From 1559220d3466acf93d1a678a69e39d07dc99ff75 Mon Sep 17 00:00:00 2001 From: MobCode100 Date: Wed, 26 Jul 2023 20:18:54 +0800 Subject: [PATCH] Sender plugin --- tgcf/config.py | 28 ++++++------ tgcf/live.py | 5 ++- tgcf/past.py | 6 ++- tgcf/plugin_models.py | 10 +++++ tgcf/plugins/__init__.py | 17 +++++++- tgcf/plugins/sender.py | 31 +++++++++++++ tgcf/utils.py | 2 +- .../pages/4_\360\237\224\214_Plugins.py" | 43 +++++++++++++++++++ 8 files changed, 123 insertions(+), 19 deletions(-) create mode 100644 tgcf/plugins/sender.py diff --git a/tgcf/config.py b/tgcf/config.py index 6de9fd91..e980b1ae 100644 --- a/tgcf/config.py +++ b/tgcf/config.py @@ -3,7 +3,7 @@ import logging import os import sys -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Union, Any from dotenv import load_dotenv from pydantic import BaseModel, validator # pylint: disable=no-name-in-module @@ -207,19 +207,6 @@ async def load_admins(client: TelegramClient): return ADMINS -def get_SESSION(): - if CONFIG.login.SESSION_STRING and CONFIG.login.user_type == 1: - logging.info("using session string") - SESSION = StringSession(CONFIG.login.SESSION_STRING) - elif CONFIG.login.BOT_TOKEN and CONFIG.login.user_type == 0: - logging.info("using bot account") - SESSION = "tgcf_bot" - else: - logging.warning("Login information not set!") - sys.exit() - return SESSION - - def setup_mongo(client): mydb = client[MONGO_DB_NAME] @@ -257,3 +244,16 @@ def read_db(): from_to = {} is_bot: Optional[bool] = None logging.info("config.py got executed") + + +def get_SESSION(section: Any = CONFIG.login, default: str = 'tgcf_bot'): + if section.SESSION_STRING and section.user_type == 1: + logging.info("using session string") + SESSION = StringSession(section.SESSION_STRING) + elif section.BOT_TOKEN and section.user_type == 0: + logging.info("using bot account") + SESSION = default + else: + logging.warning("Login information not set!") + sys.exit() + return SESSION \ No newline at end of file diff --git a/tgcf/live.py b/tgcf/live.py index dfece57a..e8f9428a 100644 --- a/tgcf/live.py +++ b/tgcf/live.py @@ -13,7 +13,7 @@ from tgcf import storage as st from tgcf.bot import get_events from tgcf.config import CONFIG, get_SESSION -from tgcf.plugins import apply_plugins +from tgcf.plugins import apply_plugins, load_async_plugins from tgcf.utils import clean_session_files, send_message @@ -119,6 +119,9 @@ async def start_sync() -> None: # clear past session files clean_session_files() + # load async plugins defined in plugin_models + await load_async_plugins() + SESSION = get_SESSION() client = TelegramClient( SESSION, diff --git a/tgcf/past.py b/tgcf/past.py index 89ebd663..5fc3a7fd 100644 --- a/tgcf/past.py +++ b/tgcf/past.py @@ -16,13 +16,17 @@ from tgcf import config from tgcf import storage as st from tgcf.config import CONFIG, get_SESSION, write_config -from tgcf.plugins import apply_plugins +from tgcf.plugins import apply_plugins, load_async_plugins from tgcf.utils import clean_session_files, send_message async def forward_job() -> None: """Forward all existing messages in the concerned chats.""" clean_session_files() + + # load async plugins defined in plugin_models + await load_async_plugins() + if CONFIG.login.user_type != 1: logging.warning( "You cannot use bot account for tgcf past mode. Telegram does not allow bots to access chat history." diff --git a/tgcf/plugin_models.py b/tgcf/plugin_models.py index f392948b..2e58e7c1 100644 --- a/tgcf/plugin_models.py +++ b/tgcf/plugin_models.py @@ -81,6 +81,11 @@ class Caption(BaseModel): header: str = "" footer: str = "" +class Sender(BaseModel): + check: bool = False + user_type: int = 0 # 0:bot, 1:user + BOT_TOKEN: str = "" + SESSION_STRING: str = "" class PluginConfig(BaseModel): filter: Filters = Filters() @@ -89,3 +94,8 @@ class PluginConfig(BaseModel): ocr: OcrConfig = OcrConfig() replace: Replace = Replace() caption: Caption = Caption() + sender: Sender = Sender() + + +# List of plugins that need to load asynchronously +ASYNC_PLUGIN_IDS = ['sender'] \ No newline at end of file diff --git a/tgcf/plugins/__init__.py b/tgcf/plugins/__init__.py index 4a4e8965..ef196c48 100644 --- a/tgcf/plugins/__init__.py +++ b/tgcf/plugins/__init__.py @@ -13,7 +13,7 @@ from telethon.tl.custom.message import Message from tgcf.config import CONFIG -from tgcf.plugin_models import FileType +from tgcf.plugin_models import FileType, ASYNC_PLUGIN_IDS from tgcf.utils import cleanup, stamp PLUGINS = CONFIG.plugins @@ -29,6 +29,7 @@ def __init__(self, message: Message) -> None: self.new_file = None self.cleanup = False self.reply_to = None + self.client = self.message.client async def get_file(self) -> str: """Downloads the file in the message and returns the path where its saved.""" @@ -57,6 +58,9 @@ class TgcfPlugin: def __init__(self, data: Dict[str, Any]) -> None: # TODO data type has changed self.data = data + async def __ainit__(self) -> None: + """Asynchronous initialization here.""" + def modify(self, tm: TgcfMessage) -> TgcfMessage: """Modify the message here.""" return tm @@ -93,13 +97,22 @@ def load_plugins() -> Dict[str, TgcfPlugin]: logging.error(f"Plugin id for {plugin_id} does not match expected id.") continue except AttributeError: - logging.error(f"Found plugin {plugin_id}, but plguin class not found.") + logging.error(f"Found plugin {plugin_id}, but plugin class not found.") else: logging.info(f"Loaded plugin {plugin_id}") _plugins.update({plugin.id_: plugin}) return _plugins +async def load_async_plugins() -> None: + """Load async plugins specified plugin_models.""" + if plugins: + for id in ASYNC_PLUGIN_IDS: + if id in plugins: + await plugins[id].__ainit__() + logging.info(f"Plugin {id} asynchronously loaded") + + async def apply_plugins(message: Message) -> TgcfMessage: """Apply all loaded plugins to a message.""" tm = TgcfMessage(message) diff --git a/tgcf/plugins/sender.py b/tgcf/plugins/sender.py new file mode 100644 index 00000000..15c15c1d --- /dev/null +++ b/tgcf/plugins/sender.py @@ -0,0 +1,31 @@ +import logging +import sys + +from tgcf.plugins import TgcfMessage, TgcfPlugin +from tgcf.config import CONFIG, get_SESSION +from telethon import TelegramClient + +class TgcfSender(TgcfPlugin): + id_ = "sender" + + async def __ainit__(self) -> None: + sender = TelegramClient( + get_SESSION(CONFIG.plugins.sender, 'tgcf_sender'), + CONFIG.login.API_ID, + CONFIG.login.API_HASH, + ) + if self.data.user_type == 0: + if self.data.BOT_TOKEN == "": + logging.warning("[Sender] Bot token not found, but login type is set to bot.") + sys.exit() + await sender.start(bot_token=self.data.BOT_TOKEN) + else: + await sender.start() + self.sender = sender + + async def modify(self, tm: TgcfMessage) -> TgcfMessage: + tm.client = self.sender + if tm.file_type != "nofile": + tm.new_file = await tm.get_file() + tm.cleanup = True + return tm \ No newline at end of file diff --git a/tgcf/utils.py b/tgcf/utils.py index 79980c84..fc6f741a 100644 --- a/tgcf/utils.py +++ b/tgcf/utils.py @@ -31,7 +31,7 @@ def platform_info(): async def send_message(recipient: EntityLike, tm: "TgcfMessage") -> Message: """Forward or send a copy, depending on config.""" - client: TelegramClient = tm.message.client + client: TelegramClient = tm.client if CONFIG.show_forwarded_from: return await client.forward_messages(recipient, tm.message) if tm.new_file: diff --git "a/tgcf/web_ui/pages/4_\360\237\224\214_Plugins.py" "b/tgcf/web_ui/pages/4_\360\237\224\214_Plugins.py" index 4f3a8b68..9a2501f8 100644 --- "a/tgcf/web_ui/pages/4_\360\237\224\214_Plugins.py" +++ "b/tgcf/web_ui/pages/4_\360\237\224\214_Plugins.py" @@ -162,5 +162,48 @@ "You can have blank lines inside header and footer, to make space between the orignal message and captions." ) + with st.expander("Sender"): + st.write("Modify the sender of forwarded messages other than the current user/bot") + st.warning("Show 'Forwarded from' option must be disabled or else messages will not be sent",icon="⚠️") + CONFIG.plugins.sender.check = st.checkbox( + "Set sender to:", value=CONFIG.plugins.sender.check + ) + leftpad,content,rightpad = st.columns([0.05,0.9,0.05]) + with content: + user_type = st.radio("Account Type", ["Bot", "User"], index=CONFIG.plugins.sender.user_type,horizontal=True) + if user_type == "Bot": + CONFIG.plugins.sender.user_type = 0 + CONFIG.plugins.sender.BOT_TOKEN = st.text_input( + "Bot Token", value=CONFIG.plugins.sender.BOT_TOKEN, type="password" + ) + else: + CONFIG.plugins.sender.user_type = 1 + CONFIG.plugins.sender.SESSION_STRING = st.text_input( + "Session String", CONFIG.plugins.sender.SESSION_STRING, type="password" + ) + st.markdown( + """ + ###### How to get session string? + + Link to repl: https://replit.com/@aahnik/tg-login?v=1 + +

+ Click on the above link and enter api id, api hash, and phone no to generate session string. +

+ + + > **Note from developer:** + > + > Due some issues logging in with a user account using a phone no is not supported in this web interface. + > + > I have built a command-line program named tg-login (https://github.com/aahnik/tg-login) that can generate the session string for you. + > + > You can run tg-login on your computer, or securely in this repl. tg-login is open source, and you can also inspect the bash script running in the repl. + > + > What is a session string? + > https://docs.telethon.dev/en/stable/concepts/sessions.html#string-sessions + """ + ,unsafe_allow_html=True) + if st.button("Save"): write_config(CONFIG)