From 6315c4dd534308ac3b2f132d5ac0e2afdb5b871a Mon Sep 17 00:00:00 2001 From: BingLingGroup <42505588+BingLingGroup@users.noreply.github.com> Date: Wed, 11 Mar 2020 16:57:37 +0800 Subject: [PATCH 1/4] Fix ubuntu install command in readme --- README.md | 2 +- docs/README.zh-Hans.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c32e92e..be287a6 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Include dependencies installation commands. Install from `master` branch. ```bash -apt install python3 python-pip3 git -y +apt install python3 python3-pip git -y pip3 install git+https://github.com/BingLingGroup/delethon.git@master ``` diff --git a/docs/README.zh-Hans.md b/docs/README.zh-Hans.md index cb1e9c3..f9a007f 100644 --- a/docs/README.zh-Hans.md +++ b/docs/README.zh-Hans.md @@ -82,7 +82,7 @@ pip install . 从`master`分支安装。 ```bash -apt install python3 python-pip3 git -y +apt install python3 python3-pip git -y pip3 install git+https://github.com/BingLingGroup/delethon.git@master ``` From bdb6833cb2493b3b7e15d1c7f8c704077ca58b87 Mon Sep 17 00:00:00 2001 From: BingLingGroup <42505588+BingLingGroup@users.noreply.github.com> Date: Wed, 11 Mar 2020 21:23:09 +0800 Subject: [PATCH 2/4] Fix print bugs Update readme --- CHANGELOG.md | 6 +++++- README.md | 18 +++++++++++++++++- delethon/__init__.py | 28 +++++++++++++++++----------- docs/CHANGELOG.zh-Hans.md | 31 +++++++++++++++++-------------- docs/README.zh-Hans.md | 18 +++++++++++++++++- 5 files changed, 73 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a50b91..99d2f43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,12 +13,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Added](#addedunreleased) - [Changed](#changedunreleased) - [0.1.0-alpha - 2020-03-11](#010-alpha---2020-03-11) - - [Added](#added040-alpha) + - [Added](#added010-alpha) Click up arrow to go back to TOC. ### [Unreleased] +#### Changed(Unreleased) + +- Fix print bugs. + ### [0.1.0-alpha] - 2020-03-11 #### Added(0.1.0-alpha) diff --git a/README.md b/README.md index be287a6..1630ce8 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ It can do: It can not do: -- [ ] Delete the messages that's been cached or exported to the local storage. +- [ ] Delete the messages that's been cached, [anti-revoked](https://github.com/SpriteOvO/Telegram-Anti-Revoke) or exported to the local storage. - [ ] Delete the messages in group's recent actions. - [ ] Delete other people's messages for all in group chats unless you have the admin rights of the group. @@ -79,6 +79,13 @@ pip install . Include dependencies installation commands. +Install from `dev` branch. + +```bash +apt install python3 python3-pip git -y +pip3 install git+https://github.com/BingLingGroup/delethon.git@dev +``` + Install from `master` branch. ```bash @@ -102,6 +109,15 @@ Choco installation command is for cmd.(not Powershell) @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" ``` +Install from `dev` branch. + +```batch +choco install git python curl -y +curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +python get-pip.py +pip install git+https://github.com/BingLingGroup/delethon.git@dev +``` + Install from `master` branch. ```batch diff --git a/delethon/__init__.py b/delethon/__init__.py index e9964ff..125a20c 100644 --- a/delethon/__init__.py +++ b/delethon/__init__.py @@ -46,6 +46,8 @@ async def iter_users_msg( # pylint: disable=too-many-arguments, too-many-branch """ msg_count = 0 id_user_dict = {} + if args.log_level > 0: + print() if not user: async for message in client.iter_messages( chat_entity, @@ -200,7 +202,7 @@ async def iter_dialog( # pylint: disable=too-many-branches, too-many-statements if not args.chats: if args.log_level > 0: print("Error: No chats input.") - return 1 + return for chat in args.chats: try: chat_entity = await client.get_input_entity(chat) @@ -224,14 +226,6 @@ async def iter_dialog( # pylint: disable=too-many-branches, too-many-statements msg_filter=msg_filter, media_filters=media_filters) - if not args.only_print: - if args.log_level > 0: - print(_("Delete {msg_count} messages in total.").format( - msg_count=total)) - else: - print(_("Print {msg_count} messages in total.").format( - msg_count=total)) - else: if args.users: for user in args.users: @@ -249,6 +243,10 @@ async def iter_dialog( # pylint: disable=too-many-branches, too-many-statements msg_filter=msg_filter, media_filters=media_filters) else: + if not args.chats: + if args.log_level > 0: + print("Error: No chats input.") + return for chat in args.chats: try: chat_entity = await client.get_input_entity(chat) @@ -274,6 +272,14 @@ async def iter_dialog( # pylint: disable=too-many-branches, too-many-statements msg_filter=msg_filter, media_filters=media_filters) + if not args.only_print: + if args.log_level > 0: + print(_("Delete {msg_count} messages in total.").format( + msg_count=total)) + else: + print(_("Print {msg_count} messages in total.").format( + msg_count=total)) + def str_to_msg_filter(filter_str): # pylint: disable=too-many-branches """ @@ -388,12 +394,12 @@ def main(): # pylint: disable=too-many-branches if not args.api_id: if args.log_level > 0: print("Error: No api_id input.") - return 1 + return 1 if not args.api_hash: if args.log_level > 0: print("Error: No api_hash input.") - return 1 + return 1 if args.log_level == 0 and args.only_print: return 1 diff --git a/docs/CHANGELOG.zh-Hans.md b/docs/CHANGELOG.zh-Hans.md index 7a50b91..25b1cfb 100644 --- a/docs/CHANGELOG.zh-Hans.md +++ b/docs/CHANGELOG.zh-Hans.md @@ -1,29 +1,32 @@ -## Changelog +## 更新日志 -[简体中文](docs/CHANGELOG.zh-Hans.md) +[English](../CHANGELOG.md) -All notable changes to this project will be documented in this file. +本项目的所有明显改变将被记录在这个文件里。 -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +本文件的格式将会基于[Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),同时本项目的版本号将遵守[Semantic Versioning](https://semver.org/lang/zh-CN/)。 -## TOC +## 目录 -- [Unreleased](#unreleased) - - [Added](#addedunreleased) - - [Changed](#changedunreleased) +- [未发布](#未发布) + - [添加](#添加未发布) + - [修改](#修改未发布) - [0.1.0-alpha - 2020-03-11](#010-alpha---2020-03-11) - - [Added](#added040-alpha) + - [添加](#添加010-alpha) -Click up arrow to go back to TOC. +点击上箭头以返回目录。 -### [Unreleased] +### [未发布] + +#### 修改(未发布) + +- 修复输出问题。 ### [0.1.0-alpha] - 2020-03-11 -#### Added(0.1.0-alpha) +#### 添加(0.1.0-alpha) -- Add basic messages deleting functions. +- 添加基本消息删除功能。  ↑  diff --git a/docs/README.zh-Hans.md b/docs/README.zh-Hans.md index f9a007f..f19ac72 100644 --- a/docs/README.zh-Hans.md +++ b/docs/README.zh-Hans.md @@ -40,7 +40,7 @@ 它不能做到: -- [ ] 删除已被缓存或者导出到本地的消息。 +- [ ] 删除已被缓存,已被[防撤回](https://github.com/SpriteOvO/Telegram-Anti-Revoke)或者导出到本地的消息。 - [ ] 删除群组最近活动中的消息。 - [ ] 删除群组中其他人的消息,除非你有群组管理员权限。 @@ -79,6 +79,13 @@ pip install . 包括依赖安装指令。 +从`dev`分支安装。 + +```bash +apt install python3 python3-pip git -y +pip3 install git+https://github.com/BingLingGroup/delethon.git@dev +``` + 从`master`分支安装。 ```bash @@ -102,6 +109,15 @@ pip3 install git+https://github.com/BingLingGroup/delethon.git@master @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" ``` +从`dev`分支安装。 + +```batch +choco install git python curl -y +curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +python get-pip.py +pip install git+https://github.com/BingLingGroup/delethon.git@dev +``` + 从`master`分支安装。 ```batch From 73e80743373c58111cdcbc5417874c3f2fa71b9d Mon Sep 17 00:00:00 2001 From: BingLingGroup <42505588+BingLingGroup@users.noreply.github.com> Date: Wed, 18 Mar 2020 09:58:48 +0800 Subject: [PATCH 3/4] Add exceptions for __init__.py --- delethon/__init__.py | 189 +++++++++++++++++++++-------------------- delethon/exceptions.py | 25 ++++++ 2 files changed, 122 insertions(+), 92 deletions(-) create mode 100644 delethon/exceptions.py diff --git a/delethon/__init__.py b/delethon/__init__.py index 125a20c..e256974 100644 --- a/delethon/__init__.py +++ b/delethon/__init__.py @@ -18,6 +18,7 @@ # Any changes to the path and your own modules from delethon import options from delethon import constants +from delethon import exceptions INIT_TEXT = gettext.translation(domain=__name__, @@ -391,102 +392,106 @@ def main(): # pylint: disable=too-many-branches """ args = options.get_cmd_args() - if not args.api_id: - if args.log_level > 0: - print("Error: No api_id input.") - return 1 + try: + if not args.api_id: + raise exceptions.DelethonException(_("Error: No api_id input.")) + + if not args.api_hash: + raise exceptions.DelethonException(_("Error: No api_hash input.")) + + if args.log_level == 0 and args.only_print: + raise exceptions.DelethonException("") + + if args.proxy_type == "SOCKS5": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.SOCKS5, + args.proxy_address, + args.proxy_port, + args.proxy_username, + args.proxy_password)) + elif args.proxy_type == "SOCKS4": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.SOCKS4, + args.proxy_address, + args.proxy_port, + args.proxy_username, + args.proxy_password)) + elif args.proxy_type == "HTTP": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.HTTP, + args.proxy_address, + args.proxy_port, + args.proxy_username, + args.proxy_password)) + elif args.proxy_type == "MTPROTO": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + connection= + telethon.connection.ConnectionTcpMTProxyRandomizedIntermediate, + proxy=(args.proxy_address, + args.proxy_port, + args.proxy_password)) + elif os.environ.get("HTTP_PROXY"): + http_proxy_list = os.environ["HTTP_PROXY"].split(":") + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.HTTP, + http_proxy_list[1][2:], + int(http_proxy_list[2]), + args.proxy_username, + args.proxy_password)) + else: + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash) - if not args.api_hash: - if args.log_level > 0: - print("Error: No api_hash input.") - return 1 - - if args.log_level == 0 and args.only_print: - return 1 - - if args.proxy_type == "SOCKS5": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.SOCKS5, - args.proxy_address, - args.proxy_port, - args.proxy_username, - args.proxy_password)) - elif args.proxy_type == "SOCKS4": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.SOCKS4, - args.proxy_address, - args.proxy_port, - args.proxy_username, - args.proxy_password)) - elif args.proxy_type == "HTTP": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.HTTP, - args.proxy_address, - args.proxy_port, - args.proxy_username, - args.proxy_password)) - elif args.proxy_type == "MTPROTO": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - connection= - telethon.connection.ConnectionTcpMTProxyRandomizedIntermediate, - proxy=(args.proxy_address, - args.proxy_port, - args.proxy_password)) - elif os.environ.get("HTTP_PROXY"): - http_proxy_list = os.environ["HTTP_PROXY"].split(":") - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.HTTP, - http_proxy_list[1][2:], - int(http_proxy_list[2]), - args.proxy_username, - args.proxy_password)) - else: - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash) + client.start() - client.start() + if args.offset_day: + utc = pytz.UTC() + args.offset_day = utc.localize( + datetime.datetime.today() - datetime.timedelta(days=args.offset_day)) - if args.offset_day: - utc = pytz.UTC() - args.offset_day = utc.localize( - datetime.datetime.today() - datetime.timedelta(days=args.offset_day)) + if args.filter: + msg_filter = str_to_msg_filter(args.filter) + else: + msg_filter = None + + if args.filters: + media_filters = [] + for filter_str in args.filters: + media_filter = str_to_media_filter(filter_str) + if media_filter: + media_filters.append(media_filter) + else: + media_filters = None - if args.filter: - msg_filter = str_to_msg_filter(args.filter) - else: - msg_filter = None + with client: + client.loop.run_until_complete(iter_dialog( + args, + client, + msg_filter, + media_filters)) - if args.filters: - media_filters = [] - for filter_str in args.filters: - media_filter = str_to_media_filter(filter_str) - if media_filter: - media_filters.append(media_filter) - else: - media_filters = None - - with client: - client.loop.run_until_complete(iter_dialog( - args, - client, - msg_filter, - media_filters)) + except exceptions.DelethonException as err_msg: + if args.log_level > 0: + print(err_msg) + except KeyboardInterrupt: + if args.log_level > 0: + print(_("\nKeyboardInterrupt. Works stopped.")) return 0 diff --git a/delethon/exceptions.py b/delethon/exceptions.py new file mode 100644 index 0000000..9976cfd --- /dev/null +++ b/delethon/exceptions.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Defines exceptions used by delethon. +""" + +# Import built-in modules +import sys + + +class DelethonException(Exception): + """ + Raised when something need to print + and works need to be stopped. + """ + + def __init__(self, msg): + super(DelethonException, self).__init__(msg) + try: + self.msg = str(msg) + except UnicodeEncodeError: + self.msg = msg.encode(sys.stdout.encoding) + + def __str__(self): + return self.msg From 12960cfdbe3c99a75eae1a668cf94cb520ace243 Mon Sep 17 00:00:00 2001 From: BingLingGroup <42505588+BingLingGroup@users.noreply.github.com> Date: Wed, 18 Mar 2020 16:22:03 +0800 Subject: [PATCH 4/4] Add option to input a group of options to avoid starting the delethon multiple times --- CHANGELOG.md | 18 +- delethon/__init__.py | 478 +--------------- delethon/cmdline_utils.py | 523 ++++++++++++++++++ .../LC_MESSAGES/delethon.cmdline_utils.po | 62 +++ .../zh_CN/LC_MESSAGES/delethon.options.po | 108 ++-- .../data/locale/zh_CN/LC_MESSAGES/delethon.po | 40 +- delethon/metadata.py | 2 +- delethon/options.py | 24 +- docs/CHANGELOG.zh-Hans.md | 20 +- 9 files changed, 751 insertions(+), 524 deletions(-) create mode 100644 delethon/cmdline_utils.py create mode 100644 delethon/data/locale/zh_CN/LC_MESSAGES/delethon.cmdline_utils.po diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d2f43..0f7ac5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,16 +10,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## TOC - [Unreleased](#unreleased) - - [Added](#addedunreleased) - - [Changed](#changedunreleased) +- [0.1.1-alpha - 2020-03-18](#011-alpha---2020-03-18) + - [Added](#added011-alpha) + - [Changed](#changed011-alpha) - [0.1.0-alpha - 2020-03-11](#010-alpha---2020-03-11) - [Added](#added010-alpha) Click up arrow to go back to TOC. -### [Unreleased] +### Unreleased -#### Changed(Unreleased) +### [0.1.1-alpha] - 2020-03-18 + +#### Added(0.1.1-alpha) + +- Add option to input a group of options to avoid starting the delethon multiple times. + +#### Changed(0.1.1-alpha) - Fix print bugs. @@ -31,5 +38,6 @@ Click up arrow to go back to TOC.  ↑  -[Unreleased]: https://github.com/BingLingGroup/autosub/compare/0.1.0-alpha...HEAD +[Unreleased]: https://github.com/BingLingGroup/autosub/compare/0.1.1-alpha...HEAD +[0.1.1-alpha]: https://github.com/BingLingGroup/autosub/compare/0.1.0-alpha...0.1.1-alpha [0.1.0-alpha]: https://github.com/BingLingGroup/autosub/releases/tag/0.1.0-alpha diff --git a/delethon/__init__.py b/delethon/__init__.py index e256974..78c5f7e 100644 --- a/delethon/__init__.py +++ b/delethon/__init__.py @@ -5,20 +5,17 @@ """ # Import built-in modules -import os -import datetime import gettext +import shlex +import gc # Import third-party modules -import telethon -import socks -import pytz - # Any changes to the path and your own modules from delethon import options from delethon import constants from delethon import exceptions +from delethon import cmdline_utils INIT_TEXT = gettext.translation(domain=__name__, @@ -33,459 +30,40 @@ _ = INIT_TEXT.gettext -async def iter_users_msg( # pylint: disable=too-many-arguments, too-many-branches - # pylint: disable=unidiomatic-typecheck, too-many-statements - args, - chat_entity, - client, - msg_filter=None, - media_filters=None, - user=None): - """ - Get or delete the message from iter_messages. - Ref: https://docs.telethon.dev/en/latest/modules/custom.html#module-telethon.tl.custom.message - """ - msg_count = 0 - id_user_dict = {} - if args.log_level > 0: - print() - if not user: - async for message in client.iter_messages( - chat_entity, - limit=args.limit, - offset_date=args.offset_day, - offset_id=args.offset_id, - max_id=args.max_id, - min_id=args.min_id, - add_offset=args.add_offset, - search=args.search, - filter=msg_filter, - wait_time=args.wait_time, - ids=args.ids, - reverse=args.reverse): - if media_filters: - if message.media: - # https://docs.telethon.dev/en/latest/modules/custom.html#module-telethon.tl.custom.message - # None for "convenience" - if type(message.media) not in media_filters: - continue - else: - if telethon.types.MessageMediaEmpty not in media_filters: - continue - if args.log_level == 0: - await client.delete_messages(chat_entity, message.id) - continue - if args.log_level == 1: - print("id: {user_id} {date}".format( - user_id=message.from_id, - date=message.date)) - elif args.log_level == 2: - user_entity = id_user_dict.get(message.from_id) - if user_entity: - print("{first_name} {last_name}(@{username})" - "(uid: {user_id}) {date} (mid: {msg_id})".format( - first_name=user_entity.first_name, - last_name=user_entity.last_name, - username=user_entity.username, - user_id=message.from_id, - date=message.date, - msg_id=message.id)) - else: - id_user_dict[message.from_id] = await client.get_entity(message.from_id) - print("{first_name} {last_name}(@{username})" - "(uid: {user_id}) {date} (mid: {msg_id})".format( - first_name=id_user_dict[message.from_id].first_name, - last_name=id_user_dict[message.from_id].last_name, - username=id_user_dict[message.from_id].username, - user_id=message.from_id, - date=message.date, - msg_id=message.id)) - print(message.message) - print() - msg_count = msg_count + 1 - if not args.only_print: - await client.delete_messages(chat_entity, message.id) - else: - user_entity = await client.get_entity(user) - async for message in client.iter_messages( - chat_entity, - limit=args.limit, - offset_date=args.offset_day, - offset_id=args.offset_id, - max_id=args.max_id, - min_id=args.min_id, - add_offset=args.add_offset, - search=args.search, - filter=msg_filter, - wait_time=args.wait_time, - ids=args.ids, - reverse=args.reverse, - from_user=user): - if media_filters: - if message.media: - # https://docs.telethon.dev/en/latest/modules/custom.html#module-telethon.tl.custom.message - # None for "convenience" - if type(message.media) not in media_filters: - continue - else: - if telethon.types.MessageMediaEmpty not in media_filters: - continue - if args.log_level == 0: - await client.delete_messages(chat_entity, message.id) - continue - if args.log_level == 1: - print("uid: {user_id} {date} (mid: {msg_id})".format( - user_id=message.from_id, - date=message.date, - msg_id=message.id)) - elif args.log_level == 2: - print("{first_name} {last_name}(@{username})" - "(uid: {user_id}) {date} (mid: {msg_id})".format( - first_name=user_entity.first_name, - last_name=user_entity.last_name, - username=user_entity.username, - user_id=message.from_id, - date=message.date, - msg_id=message.id)) - print(message.message) - print() - msg_count = msg_count + 1 - if not args.only_print: - await client.delete_messages(chat_entity, message.id) - if args.log_level == 0: - return 0 - - chat = await client.get_entity(chat_entity) - - if isinstance(chat, telethon.types.User): - title = chat.username - else: - title = chat.title - - if not args.only_print: - print(_("\nDelete {msg_count} messages in chat \"{chat}\"(id: {chat_id}).").format( - msg_count=msg_count, - chat=title, - chat_id=chat.id)) - else: - print(_("\nPrint {msg_count} messages in chat \"{chat}\"(id: {chat_id}).").format( - msg_count=msg_count, - chat=title, - chat_id=chat.id)) - return msg_count - - -async def iter_dialog( # pylint: disable=too-many-branches, too-many-statements - args, - client, - msg_filter, - media_filters=None): - """ - Get or delete the message from client. - """ - user_list = [] - - total = 0 - - if args.me: - user_list.append(await client.get_me()) - - if not args.users and not user_list: - if args.all_chats: - async for chat_entity in client.iter_dialogs(limit=None): - total = total + await iter_users_msg( - args, - chat_entity=chat_entity, - client=client, - msg_filter=msg_filter, - media_filters=media_filters) - else: - if not args.chats: - if args.log_level > 0: - print("Error: No chats input.") - return - for chat in args.chats: - try: - chat_entity = await client.get_input_entity(chat) - except ValueError as error: - chat_entity = None - try: - chat_id = int(chat) - async for dialog in client.iter_dialogs(limit=None): - if dialog.id == chat_id: - chat_entity = dialog - except ValueError: - async for dialog in client.iter_dialogs(limit=None): - if dialog.name == chat: - chat_entity = dialog - if not chat_entity: - raise error - total = total + await iter_users_msg( - args, - chat_entity=chat_entity, - client=client, - msg_filter=msg_filter, - media_filters=media_filters) - - else: - if args.users: - for user in args.users: - user_entity = await client.get_input_entity(user) - user_list.append(user_entity) - - if args.all_chats: - async for chat_entity in client.iter_dialogs(limit=None): - for user in user_list: - total = total + await iter_users_msg( - args, - chat_entity=chat_entity, - client=client, - user=user, - msg_filter=msg_filter, - media_filters=media_filters) - else: - if not args.chats: - if args.log_level > 0: - print("Error: No chats input.") - return - for chat in args.chats: - try: - chat_entity = await client.get_input_entity(chat) - except ValueError as error: - chat_entity = None - try: - chat_id = int(chat) - async for dialog in client.iter_dialogs(limit=None): - if dialog.id == chat_id: - chat_entity = dialog - except ValueError: - async for dialog in client.iter_dialogs(limit=None): - if dialog.name == chat: - chat_entity = dialog - if not chat_entity: - raise error - for user in user_list: - total = total + await iter_users_msg( - args, - chat_entity=chat_entity, - client=client, - user=user, - msg_filter=msg_filter, - media_filters=media_filters) - - if not args.only_print: - if args.log_level > 0: - print(_("Delete {msg_count} messages in total.").format( - msg_count=total)) - else: - print(_("Print {msg_count} messages in total.").format( - msg_count=total)) - - -def str_to_msg_filter(filter_str): # pylint: disable=too-many-branches - """ - Get types.InputMessagesFilter from filter_str - """ - if filter_str.lower() == "chatphotos": - msg_filter = \ - telethon.types.InputMessagesFilterChatPhotos - elif filter_str.lower() == "contacts": - msg_filter = \ - telethon.types.InputMessagesFilterContacts - elif filter_str.lower() == "document": - msg_filter = \ - telethon.types.InputMessagesFilterDocument - elif filter_str.lower() == "empty": - msg_filter = \ - telethon.types.InputMessagesFilterEmpty - elif filter_str.lower() == "geo": - msg_filter = \ - telethon.types.InputMessagesFilterGeo - elif filter_str.lower() == "gif": - msg_filter = \ - telethon.types.InputMessagesFilterGif - elif filter_str.lower() == "music": - msg_filter = \ - telethon.types.InputMessagesFilterMusic - elif filter_str.lower() == "mentions": - msg_filter = \ - telethon.types.InputMessagesFilterMyMentions - elif filter_str.lower() == "phonecalls": - msg_filter = \ - telethon.types.InputMessagesFilterPhoneCalls - elif filter_str.lower() == "photovideo": - msg_filter = \ - telethon.types.InputMessagesFilterPhotoVideo - elif filter_str.lower() == "photos": - msg_filter = \ - telethon.types.InputMessagesFilterPhotos - elif filter_str.lower() == "roundvideo": - msg_filter = \ - telethon.types.InputMessagesFilterRoundVideo - elif filter_str.lower() == "roundvoice": - msg_filter = \ - telethon.types.InputMessagesFilterRoundVoice - elif filter_str.lower() == "url": - msg_filter = \ - telethon.types.InputMessagesFilterUrl - elif filter_str.lower() == "video": - msg_filter = \ - telethon.types.InputMessagesFilterVideo - elif filter_str.lower() == "voice": - msg_filter = \ - telethon.types.InputMessagesFilterVoice - else: - msg_filter = None - - return msg_filter - - -def str_to_media_filter(filter_str): # pylint: disable=too-many-branches - """ - Get types.TypeMessageMedia from filter_str - """ - if filter_str.lower() == "contact": - media_filter = \ - telethon.types.MessageMediaContact - elif filter_str.lower() == "document": - media_filter = \ - telethon.types.MessageMediaDocument - elif filter_str.lower() == "empty": - media_filter = \ - telethon.types.MessageMediaEmpty - elif filter_str.lower() == "game": - media_filter = \ - telethon.types.MessageMediaGame - elif filter_str.lower() == "geo": - media_filter = \ - telethon.types.MessageMediaGeo - elif filter_str.lower() == "geolive": - media_filter = \ - telethon.types.MessageMediaGeoLive - elif filter_str.lower() == "invoice": - media_filter = \ - telethon.types.MessageMediaInvoice - elif filter_str.lower() == "photo": - media_filter = \ - telethon.types.MessageMediaPhoto - elif filter_str.lower() == "poll": - media_filter = \ - telethon.types.MessageMediaPoll - elif filter_str.lower() == "unsupported": - media_filter = \ - telethon.types.MessageMediaUnsupported - elif filter_str.lower() == "venue": - media_filter = \ - telethon.types.MessageMediaVenue - elif filter_str.lower() == "webpage": - media_filter = \ - telethon.types.MessageMediaWebPage - else: - media_filter = None - - return media_filter - - def main(): # pylint: disable=too-many-branches """ Run delethon as a command-line program. """ - args = options.get_cmd_args() - - try: - if not args.api_id: - raise exceptions.DelethonException(_("Error: No api_id input.")) - - if not args.api_hash: - raise exceptions.DelethonException(_("Error: No api_hash input.")) - - if args.log_level == 0 and args.only_print: - raise exceptions.DelethonException("") - if args.proxy_type == "SOCKS5": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.SOCKS5, - args.proxy_address, - args.proxy_port, - args.proxy_username, - args.proxy_password)) - elif args.proxy_type == "SOCKS4": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.SOCKS4, - args.proxy_address, - args.proxy_port, - args.proxy_username, - args.proxy_password)) - elif args.proxy_type == "HTTP": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.HTTP, - args.proxy_address, - args.proxy_port, - args.proxy_username, - args.proxy_password)) - elif args.proxy_type == "MTPROTO": - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - connection= - telethon.connection.ConnectionTcpMTProxyRandomizedIntermediate, - proxy=(args.proxy_address, - args.proxy_port, - args.proxy_password)) - elif os.environ.get("HTTP_PROXY"): - http_proxy_list = os.environ["HTTP_PROXY"].split(":") - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash, - proxy=(socks.HTTP, - http_proxy_list[1][2:], - int(http_proxy_list[2]), - args.proxy_username, - args.proxy_password)) - else: - client = telethon.TelegramClient( - args.session_file, - args.api_id, - args.api_hash) - - client.start() + parser = options.get_cmd_parser() + args = parser.parse_args() - if args.offset_day: - utc = pytz.UTC() - args.offset_day = utc.localize( - datetime.datetime.today() - datetime.timedelta(days=args.offset_day)) + args_list = [] - if args.filter: - msg_filter = str_to_msg_filter(args.filter) - else: - msg_filter = None + if args.argv: + for argv_str in args.argv: + arguments = parser.parse_args(shlex.split(argv_str)) + args_list.append(arguments) + else: + args_list.append(args) - if args.filters: - media_filters = [] - for filter_str in args.filters: - media_filter = str_to_media_filter(filter_str) - if media_filter: - media_filters.append(media_filter) + try: + if len(args_list) > 1: + last_args = args_list[0] + client = cmdline_utils.start_client(last_args) + cmdline_utils.prcs_args(last_args, client) + args_list = args_list[1:] + + for args in args_list: + if not cmdline_utils.is_same_client(args, last_args): + del client + gc.collect(0) + client = cmdline_utils.start_client(args) + cmdline_utils.prcs_args(args, client) + last_args = args else: - media_filters = None - - with client: - client.loop.run_until_complete(iter_dialog( - args, - client, - msg_filter, - media_filters)) + client = cmdline_utils.start_client(args_list[0]) + cmdline_utils.prcs_args(args_list[0], client) except exceptions.DelethonException as err_msg: if args.log_level > 0: diff --git a/delethon/cmdline_utils.py b/delethon/cmdline_utils.py new file mode 100644 index 0000000..72a68bc --- /dev/null +++ b/delethon/cmdline_utils.py @@ -0,0 +1,523 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Defines delethon's command line functionality. +""" + +# Import built-in modules +import os +import datetime +import gettext + + +# Import third-party modules +import telethon +import socks +import pytz + +# Any changes to the path and your own modules +from delethon import constants +from delethon import exceptions + + +CMDLINE_UTILS_TEXT = gettext.translation(domain=__name__, + localedir=constants.LOCALE_PATH, + languages=[constants.CURRENT_LOCALE], + fallback=True) + +try: + _ = CMDLINE_UTILS_TEXT.ugettext +except AttributeError: + # Python 3 fallback + _ = CMDLINE_UTILS_TEXT.gettext + + +async def iter_users_msg( # pylint: disable=too-many-arguments, too-many-branches + # pylint: disable=unidiomatic-typecheck, too-many-statements + args, + chat_entity, + client, + msg_filter=None, + media_filters=None, + user=None): + """ + Get or delete the message from iter_messages. + Ref: https://docs.telethon.dev/en/latest/modules/custom.html#module-telethon.tl.custom.message + """ + msg_count = 0 + id_user_dict = {} + if args.log_level > 0: + print() + if not user: + async for message in client.iter_messages( + chat_entity, + limit=args.limit, + offset_date=args.offset_day, + offset_id=args.offset_id, + max_id=args.max_id, + min_id=args.min_id, + add_offset=args.add_offset, + search=args.search, + filter=msg_filter, + wait_time=args.wait_time, + ids=args.ids, + reverse=args.reverse): + if media_filters: + if message.media: + # https://docs.telethon.dev/en/latest/modules/custom.html#module-telethon.tl.custom.message + # None for "convenience" + if type(message.media) not in media_filters: + continue + else: + if telethon.types.MessageMediaEmpty not in media_filters: + continue + if args.log_level == 0: + await client.delete_messages(chat_entity, message.id) + continue + if args.log_level == 1: + print("id: {user_id} {date}".format( + user_id=message.from_id, + date=message.date)) + elif args.log_level == 2: + user_entity = id_user_dict.get(message.from_id) + if user_entity: + print("{first_name} {last_name}(@{username})" + "(uid: {user_id}) {date} (mid: {msg_id})".format( + first_name=user_entity.first_name, + last_name=user_entity.last_name, + username=user_entity.username, + user_id=message.from_id, + date=message.date, + msg_id=message.id)) + else: + id_user_dict[message.from_id] = await client.get_entity(message.from_id) + print("{first_name} {last_name}(@{username})" + "(uid: {user_id}) {date} (mid: {msg_id})".format( + first_name=id_user_dict[message.from_id].first_name, + last_name=id_user_dict[message.from_id].last_name, + username=id_user_dict[message.from_id].username, + user_id=message.from_id, + date=message.date, + msg_id=message.id)) + print(message.message) + print() + msg_count = msg_count + 1 + if not args.only_print: + await client.delete_messages(chat_entity, message.id) + else: + user_entity = await client.get_entity(user) + async for message in client.iter_messages( + chat_entity, + limit=args.limit, + offset_date=args.offset_day, + offset_id=args.offset_id, + max_id=args.max_id, + min_id=args.min_id, + add_offset=args.add_offset, + search=args.search, + filter=msg_filter, + wait_time=args.wait_time, + ids=args.ids, + reverse=args.reverse, + from_user=user): + if media_filters: + if message.media: + # https://docs.telethon.dev/en/latest/modules/custom.html#module-telethon.tl.custom.message + # None for "convenience" + if type(message.media) not in media_filters: + continue + else: + if telethon.types.MessageMediaEmpty not in media_filters: + continue + if args.log_level == 0: + await client.delete_messages(chat_entity, message.id) + continue + if args.log_level == 1: + print("uid: {user_id} {date} (mid: {msg_id})".format( + user_id=message.from_id, + date=message.date, + msg_id=message.id)) + elif args.log_level == 2: + print("{first_name} {last_name}(@{username})" + "(uid: {user_id}) {date} (mid: {msg_id})".format( + first_name=user_entity.first_name, + last_name=user_entity.last_name, + username=user_entity.username, + user_id=message.from_id, + date=message.date, + msg_id=message.id)) + print(message.message) + print() + msg_count = msg_count + 1 + if not args.only_print: + await client.delete_messages(chat_entity, message.id) + if args.log_level == 0: + return 0 + + chat = await client.get_entity(chat_entity) + + if isinstance(chat, telethon.types.User): + title = "@{}".format(chat.username) + else: + title = chat.title + + if not args.only_print: + print(_("\nDelete {msg_count} messages in chat \"{chat}\"(id: {chat_id}).").format( + msg_count=msg_count, + chat=title, + chat_id=chat.id)) + else: + print(_("\nPrint {msg_count} messages in chat \"{chat}\"(id: {chat_id}).").format( + msg_count=msg_count, + chat=title, + chat_id=chat.id)) + return msg_count + + +async def iter_dialog( # pylint: disable=too-many-branches, too-many-statements + args, + client, + msg_filter, + media_filters=None): + """ + Get or delete the message from client. + """ + user_list = [] + total = 0 + meme = None + + if args.log_level > 1: + meme = await client.get_me() + print(_("\nCurrent login user: " + "{first_name} {last_name}(@{username})").format( + first_name=meme.first_name, + last_name=meme.last_name, + username=meme.username)) + + if args.me: + if not meme: + meme = await client.get_me() + user_list.append(meme) + + if not args.users and not user_list: + if args.all_chats: + async for chat_entity in client.iter_dialogs(limit=None): + total = total + await iter_users_msg( + args, + chat_entity=chat_entity, + client=client, + msg_filter=msg_filter, + media_filters=media_filters) + else: + if not args.chats: + if args.log_level > 0: + print(_("Error: No chats input.")) + return + for chat in args.chats: + try: + chat_entity = await client.get_input_entity(chat) + except ValueError as error: + chat_entity = None + try: + chat_id = int(chat) + async for dialog in client.iter_dialogs(limit=None): + if dialog.id == chat_id: + chat_entity = dialog + except ValueError: + async for dialog in client.iter_dialogs(limit=None): + if dialog.name == chat: + chat_entity = dialog + if not chat_entity: + raise error + total = total + await iter_users_msg( + args, + chat_entity=chat_entity, + client=client, + msg_filter=msg_filter, + media_filters=media_filters) + + else: + if args.users: + for user in args.users: + user_entity = await client.get_input_entity(user) + user_list.append(user_entity) + + if args.all_chats: + async for chat_entity in client.iter_dialogs(limit=None): + for user in user_list: + total = total + await iter_users_msg( + args, + chat_entity=chat_entity, + client=client, + user=user, + msg_filter=msg_filter, + media_filters=media_filters) + else: + if not args.chats: + if args.log_level > 0: + print(_("Error: No chats input.")) + return + for chat in args.chats: + try: + chat_entity = await client.get_input_entity(chat) + except ValueError as error: + chat_entity = None + try: + chat_id = int(chat) + async for dialog in client.iter_dialogs(limit=None): + if dialog.id == chat_id: + chat_entity = dialog + except ValueError: + async for dialog in client.iter_dialogs(limit=None): + if dialog.name == chat: + chat_entity = dialog + if not chat_entity: + raise error + for user in user_list: + total = total + await iter_users_msg( + args, + chat_entity=chat_entity, + client=client, + user=user, + msg_filter=msg_filter, + media_filters=media_filters) + + if not args.only_print: + if args.log_level > 0: + print(_("Delete {msg_count} messages in total.").format( + msg_count=total)) + else: + print(_("Print {msg_count} messages in total.").format( + msg_count=total)) + + +def str_to_msg_filter(filter_str): # pylint: disable=too-many-branches + """ + Get types.InputMessagesFilter from filter_str + """ + if filter_str.lower() == "chatphotos": + msg_filter = \ + telethon.types.InputMessagesFilterChatPhotos + elif filter_str.lower() == "contacts": + msg_filter = \ + telethon.types.InputMessagesFilterContacts + elif filter_str.lower() == "document": + msg_filter = \ + telethon.types.InputMessagesFilterDocument + elif filter_str.lower() == "empty": + msg_filter = \ + telethon.types.InputMessagesFilterEmpty + elif filter_str.lower() == "geo": + msg_filter = \ + telethon.types.InputMessagesFilterGeo + elif filter_str.lower() == "gif": + msg_filter = \ + telethon.types.InputMessagesFilterGif + elif filter_str.lower() == "music": + msg_filter = \ + telethon.types.InputMessagesFilterMusic + elif filter_str.lower() == "mentions": + msg_filter = \ + telethon.types.InputMessagesFilterMyMentions + elif filter_str.lower() == "phonecalls": + msg_filter = \ + telethon.types.InputMessagesFilterPhoneCalls + elif filter_str.lower() == "photovideo": + msg_filter = \ + telethon.types.InputMessagesFilterPhotoVideo + elif filter_str.lower() == "photos": + msg_filter = \ + telethon.types.InputMessagesFilterPhotos + elif filter_str.lower() == "roundvideo": + msg_filter = \ + telethon.types.InputMessagesFilterRoundVideo + elif filter_str.lower() == "roundvoice": + msg_filter = \ + telethon.types.InputMessagesFilterRoundVoice + elif filter_str.lower() == "url": + msg_filter = \ + telethon.types.InputMessagesFilterUrl + elif filter_str.lower() == "video": + msg_filter = \ + telethon.types.InputMessagesFilterVideo + elif filter_str.lower() == "voice": + msg_filter = \ + telethon.types.InputMessagesFilterVoice + else: + msg_filter = None + + return msg_filter + + +def str_to_media_filter(filter_str): # pylint: disable=too-many-branches + """ + Get types.TypeMessageMedia from filter_str + """ + if filter_str.lower() == "contact": + media_filter = \ + telethon.types.MessageMediaContact + elif filter_str.lower() == "document": + media_filter = \ + telethon.types.MessageMediaDocument + elif filter_str.lower() == "empty": + media_filter = \ + telethon.types.MessageMediaEmpty + elif filter_str.lower() == "game": + media_filter = \ + telethon.types.MessageMediaGame + elif filter_str.lower() == "geo": + media_filter = \ + telethon.types.MessageMediaGeo + elif filter_str.lower() == "geolive": + media_filter = \ + telethon.types.MessageMediaGeoLive + elif filter_str.lower() == "invoice": + media_filter = \ + telethon.types.MessageMediaInvoice + elif filter_str.lower() == "photo": + media_filter = \ + telethon.types.MessageMediaPhoto + elif filter_str.lower() == "poll": + media_filter = \ + telethon.types.MessageMediaPoll + elif filter_str.lower() == "unsupported": + media_filter = \ + telethon.types.MessageMediaUnsupported + elif filter_str.lower() == "venue": + media_filter = \ + telethon.types.MessageMediaVenue + elif filter_str.lower() == "webpage": + media_filter = \ + telethon.types.MessageMediaWebPage + else: + media_filter = None + + return media_filter + + +def start_client(args): + """ + Use args to create client. + """ + if not args.api_id: + raise exceptions.DelethonException(_("Error: No api_id input.")) + + if not args.api_hash: + raise exceptions.DelethonException(_("Error: No api_hash input.")) + + if args.log_level == 0 and args.only_print: + raise exceptions.DelethonException("") + + if args.proxy_type == "SOCKS5": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.SOCKS5, + args.proxy_address, + args.proxy_port, + args.proxy_username, + args.proxy_password)) + elif args.proxy_type == "SOCKS4": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.SOCKS4, + args.proxy_address, + args.proxy_port, + args.proxy_username, + args.proxy_password)) + elif args.proxy_type == "HTTP": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.HTTP, + args.proxy_address, + args.proxy_port, + args.proxy_username, + args.proxy_password)) + elif args.proxy_type == "MTPROTO": + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + connection= + telethon.connection.ConnectionTcpMTProxyRandomizedIntermediate, + proxy=(args.proxy_address, + args.proxy_port, + args.proxy_password)) + elif os.environ.get("HTTP_PROXY"): + http_proxy_list = os.environ["HTTP_PROXY"].split(":") + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash, + proxy=(socks.HTTP, + http_proxy_list[1][2:], + int(http_proxy_list[2]), + args.proxy_username, + args.proxy_password)) + else: + client = telethon.TelegramClient( + args.session_file, + args.api_id, + args.api_hash) + + client.start() + + return client + + +def prcs_args(args, client): + """ + Process delethon's args. + """ + if args.offset_day: + utc = pytz.UTC() + args.offset_day = utc.localize( + datetime.datetime.today() - datetime.timedelta(days=args.offset_day)) + + if args.filter: + msg_filter = str_to_msg_filter(args.filter) + else: + msg_filter = None + + if args.filters: + media_filters = [] + for filter_str in args.filters: + media_filter = str_to_media_filter(filter_str) + if media_filter: + media_filters.append(media_filter) + else: + media_filters = None + + with client: + client.loop.run_until_complete(iter_dialog( + args, + client, + msg_filter, + media_filters)) + + +def is_same_client(args, last_args): + """ + Check if the two args can use the same client. + """ + if not args.api_id or not args.api_hash: + args.api_id = last_args.api_id + args.api_hash = last_args.api_hash + args.session_file = last_args.session_file + + if args.api_id == last_args.api_id\ + and args.api_hash == last_args.api_hash\ + and args.proxy_type == last_args.proxy_type\ + and args.proxy_address == last_args.proxy_address\ + and args.proxy_port == last_args.proxy_port: + if args.proxy_username == last_args.proxy_username\ + and args.proxy_password == last_args.proxy_password\ + and args.session_file == last_args.session_file: + return True + + return False diff --git a/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.cmdline_utils.po b/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.cmdline_utils.po new file mode 100644 index 0000000..a0d1bd6 --- /dev/null +++ b/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.cmdline_utils.po @@ -0,0 +1,62 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-03-18 16:16+0800\n" +"PO-Revision-Date: 2020-03-18 15:45+0800\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"X-Generator: Poedit 2.3\n" + +#: delethon/cmdline_utils.py:165 +msgid "" +"\n" +"Delete {msg_count} messages in chat \"{chat}\"(id: {chat_id})." +msgstr "" +"\n" +"在聊天“{chat}”(id: {chat_id})中删除{msg_count}个消息。" + +#: delethon/cmdline_utils.py:170 +msgid "" +"\n" +"Print {msg_count} messages in chat \"{chat}\"(id: {chat_id})." +msgstr "" +"\n" +"在聊天“{chat}”(id: {chat_id})中输出{msg_count}个消息。" + +#: delethon/cmdline_utils.py:191 +msgid "" +"\n" +"Current login user: {first_name} {last_name}(@{username})" +msgstr "" +"\n" +"当前登录用户:{first_name} {last_name}(@{username})" + +#: delethon/cmdline_utils.py:214 delethon/cmdline_utils.py:258 +msgid "Error: No chats input." +msgstr "错误:没有输入对话信息。" + +#: delethon/cmdline_utils.py:287 +msgid "Delete {msg_count} messages in total." +msgstr "总共删除了{msg_count}个消息。" + +#: delethon/cmdline_utils.py:290 +msgid "Print {msg_count} messages in total." +msgstr "总共输出了{msg_count}个消息。" + +#: delethon/cmdline_utils.py:403 +msgid "Error: No api_id input." +msgstr "错误:没有api_id输入。" + +#: delethon/cmdline_utils.py:406 +msgid "Error: No api_hash input." +msgstr "错误:没有api_hash输入。" diff --git a/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.options.po b/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.options.po index 579a06d..c94c7c5 100644 --- a/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.options.po +++ b/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.options.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-11 12:19+0800\n" -"PO-Revision-Date: 2020-03-11 12:20+0800\n" +"POT-Creation-Date: 2020-03-18 16:16+0800\n" +"PO-Revision-Date: 2020-03-18 16:16+0800\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -92,7 +92,15 @@ msgstr "信息选项" msgid "Options to get extra information." msgstr "用于获取额外信息的选项。" -#: delethon/options.py:87 +#: delethon/options.py:83 +msgid "Group Options" +msgstr "组选项" + +#: delethon/options.py:84 +msgid "Options to input group of arguments." +msgstr "用于输入一组参数的选项。" + +#: delethon/options.py:92 #, python-format msgid "" "Telegram app api_id. Input it or set the environment variable " @@ -102,7 +110,7 @@ msgstr "" "Telegram应用api_id。输入它或者设置环境变量“TELEGRAM_API_ID”。你能从https://" "my.telegram.org/apps中获得一个。(参数个数为1)(默认参数为%(default)s)" -#: delethon/options.py:97 +#: delethon/options.py:102 #, python-format msgid "" "Telegram app api_hash. Input it or set the environment variable " @@ -113,11 +121,11 @@ msgstr "" "https://my.telegram.org/apps中获得一个。(参数个数为1)(默认参数" "为%(default)s)" -#: delethon/options.py:105 +#: delethon/options.py:110 msgid "path" msgstr "路径" -#: delethon/options.py:107 +#: delethon/options.py:112 #, python-format msgid "" "Telegram session file path. Ref: https://docs.telethon.dev/en/latest/" @@ -126,11 +134,11 @@ msgstr "" "Telegram会话文件路径。参考:https://docs.telethon.dev/en/latest/concepts/" "sessions.html(参数个数为1)(默认参数为%(default)s)" -#: delethon/options.py:114 +#: delethon/options.py:119 msgid "proxy_type" msgstr "代理类型" -#: delethon/options.py:117 +#: delethon/options.py:122 #, python-format msgid "" "PySocks or MTProto Proxy. Available types: \"SOCKS5\", \"SOCKS4\", \"HTTP\", " @@ -148,11 +156,11 @@ msgstr "" "a-proxy 如果参数个数是0,使用const类型。(参数个数为0或1)(const" "为%(const)s)" -#: delethon/options.py:133 +#: delethon/options.py:138 msgid "address" msgstr "地址" -#: delethon/options.py:135 +#: delethon/options.py:140 #, python-format msgid "" "The IP address or DNS name of the proxy server. (arg_num = 1) (default: " @@ -160,28 +168,28 @@ msgid "" msgstr "" "IP地址或者代理服务器的DNS名称。(参数个数为1)(默认参数为%(default)s)" -#: delethon/options.py:141 +#: delethon/options.py:146 msgid "port" msgstr "端口" -#: delethon/options.py:144 +#: delethon/options.py:149 #, python-format msgid "The port of the proxy server. (arg_num = 1) (default: %(default)s)" msgstr "代理服务器的端口。(参数个数为1)(默认参数为%(default)s)" -#: delethon/options.py:150 +#: delethon/options.py:155 msgid "username" msgstr "用户名" -#: delethon/options.py:151 +#: delethon/options.py:156 msgid "Set proxy username. (arg_num = 1)" msgstr "设置代理用户名。(参数个数为1)" -#: delethon/options.py:157 +#: delethon/options.py:162 msgid "password" msgstr "密码" -#: delethon/options.py:158 +#: delethon/options.py:163 msgid "" "Set proxy password. When using \"MTPROTO\", this option is \"secret\" " "instead. (arg_num = 1)" @@ -189,11 +197,11 @@ msgstr "" "设置代理密码。如果使用\"MTPROTO\",这个参数则会代表\"secret\"。(参数个数为" "1)" -#: delethon/options.py:166 delethon/options.py:179 +#: delethon/options.py:171 delethon/options.py:184 msgid "entity_like" msgstr "实体类" -#: delethon/options.py:167 +#: delethon/options.py:172 msgid "" "Get the messages in the chat entity/entities. entity_like can be Telegram " "username, Group name and so on. If failed to get one, it will use it to " @@ -206,7 +214,7 @@ msgstr "" "参考:https://docs.telethon.dev/en/latest/concepts/entities.html#getting-" "entities(参数个数大于等于1)" -#: delethon/options.py:180 +#: delethon/options.py:185 msgid "" "Get the messages from the user entity/entities. If not input, gets all users " "messages. Ref: https://docs.telethon.dev/en/latest/concepts/entities." @@ -216,23 +224,23 @@ msgstr "" "考https://docs.telethon.dev/en/latest/concepts/entities.html#getting-" "entities(参数个数大于等于1)" -#: delethon/options.py:190 +#: delethon/options.py:195 msgid "Get messages from the current user who is logged in. (arg_num = 0)" msgstr "获取当前登录用户发送的消息。(参数个数为0)" -#: delethon/options.py:196 +#: delethon/options.py:201 msgid "" "Iterate over all the chat entity/entities that the current user joined. " "(arg_num = 0)" msgstr "获得当前登录用户参加的所有对话实体。(参数个数为0)" -#: delethon/options.py:202 delethon/options.py:213 delethon/options.py:222 -#: delethon/options.py:233 delethon/options.py:243 delethon/options.py:253 -#: delethon/options.py:285 delethon/options.py:299 delethon/options.py:349 +#: delethon/options.py:207 delethon/options.py:218 delethon/options.py:227 +#: delethon/options.py:238 delethon/options.py:248 delethon/options.py:258 +#: delethon/options.py:290 delethon/options.py:304 delethon/options.py:354 msgid "int" msgstr "整数" -#: delethon/options.py:204 +#: delethon/options.py:209 msgid "" "Number of messages to be retrieved. Slower when more than 3000. Ref: https://" "docs.telethon.dev/en/latest/modules/client.html#telethon.client.messages." @@ -242,43 +250,43 @@ msgstr "" "latest/modules/client.html#telethon.client.messages.MessageMethods." "iter_messages (参数个数为1)(默认不限制数量)" -#: delethon/options.py:215 +#: delethon/options.py:220 msgid "" "Offset day (messages previous to this day will be retrieved). Exclusive. " "(arg_num = 1)" msgstr "偏移日期(比这天早的消息会被取回)。独占性。(参数个数为1)" -#: delethon/options.py:225 +#: delethon/options.py:230 msgid "" "Offset message ID (only messages previous to the given ID will be " "retrieved). Exclusive. (arg_num = 1)" msgstr "" "偏移消息ID(只有比这个ID更早的消息才会被取回)。独占性。(参数个数为1)" -#: delethon/options.py:236 +#: delethon/options.py:241 msgid "" "All the messages with a higher (newer) ID or equal to this will be excluded. " "(arg_num = 1)" msgstr "所有比这个ID数值更高也就是更新的消息会被排除。(参数个数为1)" -#: delethon/options.py:246 +#: delethon/options.py:251 msgid "" "All the messages with a lower (older) ID or equal to this will be excluded. " "(arg_num = 1)" msgstr "所有比这个ID数值更小也就是更旧的消息会被排除。(参数个数为1)" -#: delethon/options.py:256 +#: delethon/options.py:261 msgid "" "Additional message offset (all of the specified offsets + this offset = " "older messages). (arg_num = 1)" msgstr "" "额外消息偏移(所有制ID那个的偏移加上这个偏移=更旧的消息)。(参数个数为1)" -#: delethon/options.py:263 +#: delethon/options.py:268 msgid "str" msgstr "字符串" -#: delethon/options.py:264 +#: delethon/options.py:269 msgid "" "The string to be used as a search query. Give the same result as other " "Telegram official clients meaning it's not optimized for some non-English " @@ -287,11 +295,11 @@ msgstr "" "用来搜索的字符串。和其他Telegram官方客户端得到的搜索结果一样,意味着对部分非" "英语语言未做优化。(参数个数为1)" -#: delethon/options.py:272 delethon/options.py:334 +#: delethon/options.py:277 delethon/options.py:339 msgid "type" msgstr "类型" -#: delethon/options.py:273 +#: delethon/options.py:278 msgid "" "The filter to use before returning messages. For instance, \"photos\" for " "\"InputMessagesFilterPhotos\" would yield only messages containing photos. " @@ -306,7 +314,7 @@ msgstr "" "geo, gif, music, mentions, phonecalls, photovideo, photos, roundvideo, " "roundvoice, url, video, voice(参数个数为1)" -#: delethon/options.py:287 +#: delethon/options.py:292 msgid "" "Wait time (in seconds) between different GetHistoryRequest. Use this " "parameter to avoid hitting the FloodWaitError as needed. If left to None, it " @@ -318,7 +326,7 @@ msgstr "" "FloodWaitError。如果不输入,超过3000个消息时的等待默认为1秒。如果id参数使用" "了,id超过300时,这个时间将被设置为10秒。(参数个数为1)" -#: delethon/options.py:302 +#: delethon/options.py:307 msgid "" "A single integer ID (or several IDs) for the message that should be " "returned. This parameter takes precedence over the rest (which will be " @@ -331,7 +339,7 @@ msgstr "" "条消息。注意如果消息不存在,会返回None,所以将包含ID的列表压缩在一起能得到一" "对一的结果。(参数个数大于等于1)" -#: delethon/options.py:316 +#: delethon/options.py:321 msgid "" "The messages will be returned in reverse order (from oldest to newest, " "instead of the default newest to oldest). This also means that the meaning " @@ -345,11 +353,11 @@ msgstr "" "的。 同样地,\"--min-id\"等效于\"--offset-id\"而非\"--max-id\"因为消息会按照" "升序返回。(参数个数为0)" -#: delethon/options.py:328 +#: delethon/options.py:333 msgid "Only print message instead of deleting them. (arg_num = 0)" msgstr "只在屏幕上输出消息而非删除他们。(参数个数为0)" -#: delethon/options.py:335 +#: delethon/options.py:340 msgid "" "The filters to use after returning the messages from \"iter_messages\". So " "using it will delete equal to or less amount of messages than the argument " @@ -366,7 +374,7 @@ msgstr "" "unsupported, venue, webpage 参考:https://tl.telethon.dev/types/" "message_media.html(参数个数大于等于1)" -#: delethon/options.py:353 +#: delethon/options.py:358 #, python-format msgid "" "Print different kinds of messages. 0 for nothing. 1 for basic. 2 for more " @@ -375,15 +383,31 @@ msgstr "" "在屏幕上输出不同类别的消息。0为不输出。1为基本信息。2则是更多的信息。(参数个" "数为1)(默认参数为%(default)s)" -#: delethon/options.py:360 +#: delethon/options.py:365 #, python-format msgid "Show %(prog)s help message and exit. (arg_num = 0)" msgstr "显示%(prog)s的帮助信息并退出。(参数个数为0)" -#: delethon/options.py:368 +#: delethon/options.py:373 #, python-format msgid "Show %(prog)s version and exit. (arg_num = 0)" msgstr "显示%(prog)s的版本信息并退出。(参数个数为0)" +#: delethon/options.py:378 +msgid "option_group" +msgstr "一组选项" + +#: delethon/options.py:379 +msgid "" +"A group of options to input to avoid starting the delethon multiple times. " +"Except for the first group, if the group options don't include \"-ai\" or \"-" +"ah\", it will avoid starting the client multiple times to avoid extra " +"consumption. Remember to input the group of options in quotes and escape the " +"original quotes by using backslash \"\\\". (arg_num >= 1)" +msgstr "" +"输入一组选项来避免反复运行delethon。除了第一组参数,如果参数没有包含\"-ai\"和" +"\"-ah\",它会避免重复启动客户端带来的额外消耗。输入一组选项时,需要用引号包" +"围,并且要把原先的引号用反斜线\"\\\"转义。(参数个数大于等于1)" + #~ msgid "Operation Options" #~ msgstr "操作选项" diff --git a/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.po b/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.po index 7f9f4f4..4b8a00b 100644 --- a/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.po +++ b/delethon/data/locale/zh_CN/LC_MESSAGES/delethon.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-10 17:32+0800\n" -"PO-Revision-Date: 2020-03-10 17:33+0800\n" +"POT-Creation-Date: 2020-03-18 15:39+0800\n" +"PO-Revision-Date: 2020-03-18 11:33+0800\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -17,26 +17,30 @@ msgstr "" "Language: zh_CN\n" "X-Generator: Poedit 2.3\n" -#: delethon/__init__.py:163 +#: delethon/__init__.py:73 msgid "" "\n" -"Delete {msg_count} messages in chat \"{chat}\"(id: {chat_id})." +"KeyboardInterrupt. Works stopped." msgstr "" "\n" -"在聊天“{chat}”(id: {chat_id})中删除{msg_count}个消息。" +"键盘中断。操作终止。" -#: delethon/__init__.py:168 -msgid "" -"\n" -"Print {msg_count} messages in chat \"{chat}\"(id: {chat_id})." -msgstr "" -"\n" -"在聊天“{chat}”(id: {chat_id})中输出{msg_count}个消息。" +#~ msgid "" +#~ "\n" +#~ "Delete {msg_count} messages in chat \"{chat}\"(id: {chat_id})." +#~ msgstr "" +#~ "\n" +#~ "在聊天“{chat}”(id: {chat_id})中删除{msg_count}个消息。" + +#~ msgid "" +#~ "\n" +#~ "Print {msg_count} messages in chat \"{chat}\"(id: {chat_id})." +#~ msgstr "" +#~ "\n" +#~ "在聊天“{chat}”(id: {chat_id})中输出{msg_count}个消息。" -#: delethon/__init__.py:229 -msgid "Delete {msg_count} messages in total." -msgstr "总共删除了{msg_count}个消息。" +#~ msgid "Delete {msg_count} messages in total." +#~ msgstr "总共删除了{msg_count}个消息。" -#: delethon/__init__.py:232 -msgid "Print {msg_count} messages in total." -msgstr "总共输出了{msg_count}个消息。" +#~ msgid "Print {msg_count} messages in total." +#~ msgstr "总共输出了{msg_count}个消息。" diff --git a/delethon/metadata.py b/delethon/metadata.py index 677bf99..ec3f005 100644 --- a/delethon/metadata.py +++ b/delethon/metadata.py @@ -7,7 +7,7 @@ _ = str NAME = 'delethon' -VERSION = '0.1.0-alpha' +VERSION = '0.1.1-alpha' DESCRIPTION = _('Delete Telegram messages based on Telethon.') AUTHOR = 'Bing Ling' AUTHOR_EMAIL = 'binglinggroup@outlook.com' diff --git a/delethon/options.py b/delethon/options.py index 6acf409..8bd63cc 100644 --- a/delethon/options.py +++ b/delethon/options.py @@ -31,7 +31,7 @@ M_ = META_TEXT.gettext -def get_cmd_args(): +def get_cmd_parser(): """ Get command-line arguments. """ @@ -79,6 +79,11 @@ def get_cmd_args(): _('Options to get extra information.') ) + options_group = parser.add_argument_group( + _('Group Options'), + _('Options to input group of arguments.') + ) + client_group.add_argument( '-ai', '--api-id', metavar='API_ID', @@ -367,4 +372,19 @@ def get_cmd_args(): + metadata.AUTHOR_EMAIL + '>', help=_("Show %(prog)s version and exit. (arg_num = 0)")) - return parser.parse_args() + options_group.add_argument( + '-a', '--argv', + nargs=argparse.REMAINDER, + metavar=_('option_group'), + help=_("A group of options to input to " + "avoid starting the delethon multiple times. " + "Except for the first group, " + "if the group options don't include \"-ai\" or \"-ah\", " + "it will avoid starting the client multiple times " + "to avoid extra consumption. " + "Remember to input the group of options in quotes " + "and escape the original quotes by using backslash \"\\\". " + "(arg_num >= 1)") + ) + + return parser diff --git a/docs/CHANGELOG.zh-Hans.md b/docs/CHANGELOG.zh-Hans.md index 25b1cfb..c5a2565 100644 --- a/docs/CHANGELOG.zh-Hans.md +++ b/docs/CHANGELOG.zh-Hans.md @@ -9,8 +9,9 @@ ## 目录 - [未发布](#未发布) - - [添加](#添加未发布) - - [修改](#修改未发布) +- [0.1.1-alpha - 2020-03-18](#011-alpha---2020-03-18) + - [添加](#添加011-alpha) + - [修改](#修改011-alpha) - [0.1.0-alpha - 2020-03-11](#010-alpha---2020-03-11) - [添加](#添加010-alpha) @@ -18,7 +19,13 @@ ### [未发布] -#### 修改(未发布) +### [0.1.1-alpha] - 2020-03-18 + +#### 添加(0.1.1-alpha) + +- 添加选项允许输入一组选项来避免delethon的反复启动。 + +#### 修改(0.1.1-alpha) - 修复输出问题。 @@ -28,7 +35,8 @@ - 添加基本消息删除功能。 - ↑  + ↑  -[Unreleased]: https://github.com/BingLingGroup/autosub/compare/0.1.0-alpha...HEAD -[0.1.0-alpha]: https://github.com/BingLingGroup/autosub/releases/tag/0.1.0-alpha +[Unreleased]: https://github.com/BingLingGroup/autosub/compare/0.1.1-alpha...HEAD +[0.1.1-alpha]: https://github.com/BingLingGroup/autosub/compare/0.1.0-alpha...0.1.1-alpha +[0.1.0-alpha]: https://github.com/BingLingGroup/autosub/releases/tag/0.1.0-alpha \ No newline at end of file