Initial commit
This commit is contained in:
commit
19ee6764b1
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 blank X
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,160 @@
|
||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
import functools
|
||||||
|
import yaml
|
||||||
|
from telethon import TelegramClient, events
|
||||||
|
from telethon.errors.rpcerrorlist import MessageIdInvalidError, ChatNotModifiedError
|
||||||
|
|
||||||
|
with open('config.yaml') as file:
|
||||||
|
config_data = yaml.safe_load(file)
|
||||||
|
|
||||||
|
api_id = config_data['api_id']
|
||||||
|
api_hash = config_data['api_hash']
|
||||||
|
bot_token = config_data.get('bot_token')
|
||||||
|
|
||||||
|
bot_admins = config_data['bot_admins']
|
||||||
|
storage_chat = config_data.get('storage_chat')
|
||||||
|
storage_msg_id = config_data.get('storage_message_id')
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
def is_true(string):
|
||||||
|
string = string.lower()
|
||||||
|
if string in ('true', 'yes', 'on', 'enable'):
|
||||||
|
return True
|
||||||
|
if string in ('false', 'no', 'off', 'disable'):
|
||||||
|
return False
|
||||||
|
raise Exception(f'Invalid boolean string: {string}')
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
client = await TelegramClient('acpbot', api_id, api_hash).start(bot_token=bot_token)
|
||||||
|
client.parse_mode = 'html'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if storage_chat and storage_msg_id:
|
||||||
|
await (await client.get_messages(storage_chat, ids=storage_msg_id)).download_media('acpbot.json')
|
||||||
|
with open('acpbot.json') as file:
|
||||||
|
d = json.load(file)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
d = {'version': 0, 'chats': dict()}
|
||||||
|
# chats dict value: {'enabled': bool, 'lastpinned': int, 'deleteservice': bool, 'deletechannel': bool}
|
||||||
|
|
||||||
|
uploading_lock = asyncio.Lock()
|
||||||
|
processing_lock = asyncio.Lock()
|
||||||
|
chatinit_lock = asyncio.Lock()
|
||||||
|
processing_chats = dict()
|
||||||
|
async def write_d():
|
||||||
|
with open('acpbot.json', 'w') as file:
|
||||||
|
json.dump(d, file)
|
||||||
|
if storage_chat and storage_msg_id and client.is_connected():
|
||||||
|
async with uploading_lock:
|
||||||
|
await client.edit_message(storage_chat, storage_msg_id, file='acpbot.json')
|
||||||
|
|
||||||
|
def get_chat_data(chat_id):
|
||||||
|
chat_id = str(chat_id)
|
||||||
|
if chat_id not in d['chats']:
|
||||||
|
d['chats'][chat_id] = {'enabled': False, 'lastpinned': 0, 'deleteservice': False, 'deletechannel': False}
|
||||||
|
return d['chats'][chat_id]
|
||||||
|
|
||||||
|
def error_dec(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
async def awrapper(e):
|
||||||
|
try:
|
||||||
|
await func(e)
|
||||||
|
except Exception:
|
||||||
|
to_send = traceback.format_exc()
|
||||||
|
try:
|
||||||
|
await e.reply(to_send, parse_mode=None)
|
||||||
|
except Exception:
|
||||||
|
logging.exception('Got an exception while sending an exception to %s', e.chat_id)
|
||||||
|
to_send = traceback.format_exc()
|
||||||
|
for admin_id in bot_admins:
|
||||||
|
try:
|
||||||
|
await e.client.send_message(admin_id, to_send, parse_mode=None)
|
||||||
|
except Exception:
|
||||||
|
logging.exception('Got an exception while sending an exception to %s', admin_id)
|
||||||
|
raise
|
||||||
|
return awrapper
|
||||||
|
|
||||||
|
@error_dec
|
||||||
|
@client.on(events.NewMessage(bot_admins, pattern='/(?:start|help)'))
|
||||||
|
async def start_or_help(e):
|
||||||
|
await e.reply('Prepend "/acp " to your message to use Anti-Channel Pin')
|
||||||
|
|
||||||
|
@error_dec
|
||||||
|
@client.on(events.NewMessage(from_users=bot_admins, pattern='/acp(?:$| (?:start|help))'))
|
||||||
|
async def acp_start_or_help(e):
|
||||||
|
await e.reply(('/acp start - /acp help\n'
|
||||||
|
'/acp help - /acp start\n'
|
||||||
|
'/acp enable - Enables current chat\n'
|
||||||
|
'/acp disable - Disables current chat\n'
|
||||||
|
'/acp service on/off - Enable/Disable deleting service messages\n'
|
||||||
|
'/acp channel on/off - Enable/Disable deleting channel messages\n'))
|
||||||
|
|
||||||
|
@error_dec
|
||||||
|
@client.on(events.NewMessage(from_users=bot_admins, pattern=r'/acp (service|channel) ([Tt]rue|[Oo](?:n|ff)|[Yy]es|[Nn]o|(?:[Ee]n|[Dd]is)able)'))
|
||||||
|
async def toggle_sc_setting(e):
|
||||||
|
turn_on = is_true(e.pattern_match.group(2))
|
||||||
|
setting = 'delete' + e.pattern_match.group(1)
|
||||||
|
get_chat_data(e.chat_id)[setting] = turn_on
|
||||||
|
await e.reply('Setting modified!')
|
||||||
|
await write_d()
|
||||||
|
|
||||||
|
@error_dec
|
||||||
|
@client.on(events.NewMessage(from_users=bot_admins, pattern=r'/acp ([Tt]rue|[Oo](?:n|ff)|[Yy]es|[Nn]o|(?:[Ee]n|[Dd]is)able)'))
|
||||||
|
async def toggle_enabled(e):
|
||||||
|
enable = is_true(e.pattern_match.group(1))
|
||||||
|
get_chat_data(e.chat_id)['enabled'] = enable
|
||||||
|
await e.reply('Setting modified!')
|
||||||
|
await write_d()
|
||||||
|
|
||||||
|
@error_dec
|
||||||
|
@client.on(events.NewMessage)
|
||||||
|
async def handle_new_channel_message(e):
|
||||||
|
if e.from_id:
|
||||||
|
return
|
||||||
|
chat_data = get_chat_data(e.chat_id)
|
||||||
|
if not chat_data['enabled']:
|
||||||
|
return
|
||||||
|
async with chatinit_lock:
|
||||||
|
if e.chat_id not in processing_chats:
|
||||||
|
processing_chats[e.chat_id] = [asyncio.Lock(), set(), True]
|
||||||
|
write_lock, to_delete, _ = processing_chats[e.chat_id]
|
||||||
|
processing_chats[e.chat_id][2] = True
|
||||||
|
to_write = False
|
||||||
|
async with write_lock:
|
||||||
|
if chat_data['deletechannel']:
|
||||||
|
to_delete.add(e.id)
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
async with write_lock, processing_lock:
|
||||||
|
if chat_data['lastpinned'] and processing_chats[e.chat_id][2]:
|
||||||
|
try:
|
||||||
|
service = await e.client.pin_message(e.chat_id, chat_data['lastpinned'])
|
||||||
|
if chat_data['deleteservice']:
|
||||||
|
to_delete.add(service.id)
|
||||||
|
except MessageIdInvalidError:
|
||||||
|
chat_data['lastpinned'] = 0
|
||||||
|
to_write = True
|
||||||
|
except ChatNotModifiedError:
|
||||||
|
pass
|
||||||
|
processing_chats[e.chat_id][2] = False
|
||||||
|
if to_delete:
|
||||||
|
await e.client.delete_messages(e.chat_id, list(to_delete))
|
||||||
|
to_delete.clear()
|
||||||
|
if to_write:
|
||||||
|
await write_d()
|
||||||
|
|
||||||
|
@error_dec
|
||||||
|
@client.on(events.ChatAction)
|
||||||
|
async def handle_new_pin_message(e):
|
||||||
|
if not (e.new_pin or e.unpin):
|
||||||
|
return
|
||||||
|
get_chat_data(e.chat_id)['lastpinned'] = getattr(e.action_message, 'reply_to_msg_id', 0)
|
||||||
|
await write_d()
|
||||||
|
|
||||||
|
await client.run_until_disconnected()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
|
@ -0,0 +1,11 @@
|
||||||
|
api_id: 0
|
||||||
|
api_hash: https://my.telegram.org
|
||||||
|
bot_token: https://t.me/BotFather
|
||||||
|
|
||||||
|
bot_admins:
|
||||||
|
- thekneesocks
|
||||||
|
- mrtanjiro
|
||||||
|
# Below are chats to store seen posts, useful for temporary file systems like Heroku
|
||||||
|
# Set to 0 to disable
|
||||||
|
storage_chat: -1001222674489
|
||||||
|
storage_message_id: 1366
|
|
@ -0,0 +1,2 @@
|
||||||
|
telethon
|
||||||
|
PyYAML
|
Loading…
Reference in New Issue