diff --git a/blackList.py b/blackList.py
index 4565f3c..4ecae63 100644
--- a/blackList.py
+++ b/blackList.py
@@ -15,21 +15,96 @@
# along with this program. If not, see .
from re import search
from typing import List
+from textc import textc, timeToStr
+from enum import Enum, unique
+from math import ceil, floor
class BlackInfo:
- uid: int = None
+ __uid: int = None
op_uid: int = None
from_config: bool = False
add_time: int = None
reason: str = None
- def __init__(self, uid: int, op_uid: int = None, add_time: int = None, reason: str = None):
- self.uid = uid
+ @property
+ def uid(self) -> int:
+ return self.__uid
+
+ def __init__(self, uid: int, op_uid: int = None, add_time: int = None, reason: str = None, title: str = None):
+ self.__uid = uid
self.op_uid = op_uid
self.from_config = True if self.op_uid is None else False
self.add_time = add_time
self.reason = reason
+ self.title = title
+
+ @property
+ def name(self) -> str:
+ return f"{self.uid}" if self.title is None else self.title
+
+
+class BlackInfoListIter:
+ def __init__(self, li: List[BlackInfo]):
+ self.__l = li
+ self.__start = 0
+
+ def __next__(self) -> BlackInfo:
+ if self.__start >= len(self.__l):
+ raise StopIteration
+ v = self.__l[self.__start]
+ self.__start += 1
+ return v
+
+
+class BlackInfoList:
+ def __add__(self, b):
+ o = BlackInfoList(self.__l)
+ if isinstance(b, (BlackInfoList, list)):
+ for i in b:
+ o.append(i)
+ elif isinstance(b, BlackInfo):
+ o.append(b)
+ return o
+
+ def __getitem__(self, i) -> BlackInfo:
+ return self.__l[i]
+
+ def __iadd__(self, b):
+ if isinstance(b, (BlackInfoList, list)):
+ for i in b:
+ self.append(i)
+ elif isinstance(b, BlackInfo):
+ self.append(b)
+ return self
+
+ def __init__(self, li: List[BlackInfo] = None):
+ self.__t = []
+ self.__l = []
+ if li is not None:
+ for i in li:
+ self.append(i)
+
+ def __iter__(self):
+ it = BlackInfoListIter(self.__l)
+ return it
+
+ def __len__(self):
+ return len(self.__l)
+
+ def append(self, info: BlackInfo):
+ if info.uid not in self.__t:
+ self.__l.append(info)
+ self.__t.append(info.uid)
+
+ def find(self, uid: int):
+ if uid in self.__t:
+ return self.__t.index(uid)
+ else:
+ return -1
+
+ def isInBlackList(self, chatId: int) -> bool:
+ return chatId in self.__t
class ConfigBlackList:
@@ -43,8 +118,8 @@ class ConfigBlackList:
if search(r'^[\+-]?[0-9]+$', i) is not None:
self.__list.append(int(i))
- def getBlackList(self) -> List[BlackInfo]:
- r = []
+ def getBlackList(self) -> BlackInfoList:
+ r = BlackInfoList()
for i in self.__list:
r.append(BlackInfo(i))
return r
@@ -58,23 +133,129 @@ class BlackList:
from rssbot import main
self._main: main = m
self._configBlackList = ConfigBlackList(m, self._main._setting._blackList)
+ self._blackList = self._main._db.getBlackList()
- def getBlackList(self) -> List[BlackInfo]:
- m = self._configBlackList.getBlackList()
- t = []
- r = []
- for i in m:
- if i.uid not in t:
- t.append(i.uid)
- r.append(i)
+ def ban(self, i: BlackInfo):
+ re = self._main._db.addBlackInfo(i)
+ if re:
+ self._blackList = self._main._db.getBlackList()
+ self.checkRSSList()
+ return re
+
+ def getBlackList(self) -> BlackInfoList:
+ r = self._configBlackList.getBlackList()
+ r += self._blackList
return r
def isInBlackList(self, chatId: int) -> bool:
if self._configBlackList.isInBlackList(chatId):
return True
+ if self._blackList.isInBlackList(chatId):
+ return True
return False
def checkRSSList(self):
li = self.getBlackList()
for i in li:
self._main._db.removeChatInChatList(i.uid)
+
+ def unban(self, userId: int):
+ re = self._main._db.removeFromBlackList(userId)
+ if re:
+ self._blackList = self._main._db.getBlackList()
+ return re
+
+
+@unique
+class InlineKeyBoardForBlackList(Enum):
+ FirstPage = 0
+ LastPage = 1
+ PrevPage = 2
+ NextPage = 3
+ Close = 4
+ BlackInfo = 5
+ BackToList = 6
+ Unban = 7
+ ConfirmUnban = 8
+ CancleUnban = 9
+
+
+def getTextContentForBlackInfo(i: BlackInfo):
+ t = textc()
+ link = '' if i.uid < 0 else f'tg://user?id={i.uid}'
+ t += f'被封禁用户: {i.name}'
+ if i.from_config:
+ t += '来源:配置文件'
+ else:
+ t += '来源:数据库'
+ t += f'封禁操作人:{i.op_uid}'
+ t += f'封禁时间:{timeToStr(i.add_time)}'
+ t += f'封禁理由:{i.reason}'
+ return t.tostr()
+
+
+def getTextContentForUnbanBlackInfo(i: BlackInfo):
+ link = '' if i.uid < 0 else f'tg://user?id={i.uid}'
+ return f'是否要取消封禁{i.name}?'
+
+
+def getInlineKeyBoardForBlackList(bl: BlackInfoList, page: int = 1, lastPage: bool = False, itemIndex: int = None):
+ d = []
+ i = -1
+ lineLimit = 7
+ l = len(bl)
+ pn = ceil(l / lineLimit)
+ if lastPage:
+ page = pn
+ if itemIndex is not None and itemIndex >= 0:
+ page = floor(itemIndex / lineLimit) + 1
+ if l != 0:
+ page = max(min(pn, page), 1)
+ s = max(lineLimit * (page - 1), 0)
+ n = min(lineLimit * page, l)
+ while s < n:
+ d.append([])
+ i += 1
+ d[i].append({'text': bl[s].name, 'callback_data': f'2,{InlineKeyBoardForBlackList.BlackInfo.value},{s},{bl[s].uid}'})
+ s += 1
+ if pn != 1:
+ d.append([])
+ i += 1
+ if page != 1:
+ d[i].append({'text': '上一页', 'callback_data': f'2,{InlineKeyBoardForBlackList.PrevPage.value},{page}'})
+ if page != pn:
+ d[i].append({'text': '下一页', 'callback_data': f'2,{InlineKeyBoardForBlackList.NextPage.value},{page}'})
+ d.append([])
+ i += 1
+ if page != 1:
+ d[i].append({'text': '首页', 'callback_data': f'2,{InlineKeyBoardForBlackList.FirstPage.value}'})
+ if page != pn:
+ d[i].append({'text': '尾页', 'callback_data': f'2,{InlineKeyBoardForBlackList.LastPage.value}'})
+ d.append([])
+ i += 1
+ d[i].append({'text': '关闭', 'callback_data': f'2,{InlineKeyBoardForBlackList.Close.value}'})
+ return {'inline_keyboard': d}
+
+
+def getInlineKeyBoardForBlackInfo(b: BlackInfo, index: int):
+ d = []
+ i = -1
+ if not b.from_config:
+ d.append([])
+ i += 1
+ d[i].append({'text': '取消封禁', 'callback_data': f'2,{InlineKeyBoardForBlackList.Unban.value},{index},{b.uid}'})
+ d.append([])
+ i += 1
+ d[i].append(
+ {'text': '返回', 'callback_data': f'2,{InlineKeyBoardForBlackList.BackToList.value},{index}'})
+ return {'inline_keyboard': d}
+
+
+def getInlineKeyBoardForUnbanBlackInfo(b: BlackInfo, index: int):
+ d = []
+ i = -1
+ d.append([])
+ i += 1
+ d[i].append({'text': '是', 'callback_data': f'2,{InlineKeyBoardForBlackList.ConfirmUnban.value},{index},{b.uid}'})
+ d[i].append({'text': '否', 'callback_data': f'2,{InlineKeyBoardForBlackList.CancleUnban.value},{index},{b.uid}'})
+ return {'inline_keyboard': d}
diff --git a/database.py b/database.py
index 5a042b8..dd1e71d 100644
--- a/database.py
+++ b/database.py
@@ -16,11 +16,11 @@
import sqlite3
from config import RSSConfig
from RSSEntry import RSSEntry, ChatEntry, HashEntry, HashEntries
-from typing import List
+from typing import List, Tuple
from enum import Enum, unique
from threading import Lock
-from hashl import sha256WithBase64
from time import time
+from blackList import BlackInfo, BlackInfoList
VERSION_TABLE = '''CREATE TABLE version (
@@ -64,6 +64,7 @@ userId INT,
op_uid INT,
add_time INT,
reason TEXT,
+name TEXT,
PRIMARY KEY (userId)
)'''
@@ -134,6 +135,9 @@ class database:
if v < [1, 0, 0, 6]:
self._db.execute(USERBLACKLIST_TABLE)
self._db.commit()
+ if v < [1, 0, 0, 7]:
+ self._db.execute('ALTER TABLE userBlackList ADD name TEXT;')
+ self._db.commit()
self._db.execute('VACUUM;')
self.__updateExistsTable()
self.__write_version()
@@ -156,7 +160,7 @@ class database:
self._db.commit()
def __init__(self, m, loc: str):
- self._version = [1, 0, 0, 6]
+ self._version = [1, 0, 0, 7]
self._value_lock = Lock()
self._db = sqlite3.connect(loc, check_same_thread=False)
self._db.execute('VACUUM;')
@@ -266,6 +270,23 @@ class database:
except:
return False
+ def addBlackInfo(self, i: BlackInfo) -> bool:
+ with self._value_lock:
+ try:
+ have_value = False
+ cur = self._db.execute('SELECT * FROM userBlackList WHERE userId=?;', (i.uid,))
+ for i in cur:
+ have_value = True
+ break
+ if have_value:
+ self._db.execute('UPDATE userBlackList SET op_uid=?, add_time=?, reason=?, name=? WHERE userId=?;', (i.op_uid, i.add_time, i.reason, i.title, i.uid))
+ else:
+ self._db.execute('INSERT INTO userBlackList VALUES (?, ?, ?, ?, ?);', (i.uid, i.op_uid, i.add_time, i.reason, i.title))
+ self._db.commit()
+ return True
+ except Exception:
+ return False
+
def getAllRSSList(self) -> List[RSSEntry]:
with self._value_lock:
cur = self._db.execute(f'SELECT * FROM RSSList;')
@@ -287,6 +308,14 @@ class database:
r.append(temp)
return r
+ def getBlackList(self) -> BlackInfoList:
+ with self._value_lock:
+ cur = self._db.execute('SELECT * FROM userBlackList;')
+ li = BlackInfoList()
+ for i in cur:
+ li.append(BlackInfo(i[0], i[1], i[2], i[3], i[4]))
+ return li
+
def getRSSByIdAndChatId(self, id: int, chatId: int) -> RSSEntry:
while self._value_lock:
cur = self._db.execute('SELECT RSSList.title, RSSList.url, RSSList.interval, RSSList.lastupdatetime, RSSList.id, RSSList.lasterrortime, RSSList.forceupdate, RSSList.errorcount, chatList.config FROM chatList INNER JOIN RSSList ON RSSList.id = chatList.id WHERE chatList.chatId = ? AND chatlist.id = ?;', (chatId, id))
@@ -307,7 +336,7 @@ class database:
RSSEntries.append(rssEntry)
return RSSEntries
- def getUserStatus(self, userId: int) -> (userStatus, str):
+ def getUserStatus(self, userId: int) -> Tuple[userStatus, str]:
with self._value_lock:
try:
cur = self._db.execute(
@@ -327,6 +356,15 @@ class database:
except:
return False
+ def removeFromBlackList(self, userId: int):
+ with self._value_lock:
+ try:
+ self._db.execute('DELETE FROM userBlackList WHERE userId=?;', (userId,))
+ self._db.commit()
+ return True
+ except Exception:
+ return False
+
def removeItemInChatList(self, chatId: int, id: int):
with self._value_lock:
try:
diff --git a/rssbot.py b/rssbot.py
index 3d712ac..fafc533 100644
--- a/rssbot.py
+++ b/rssbot.py
@@ -36,10 +36,10 @@ import sys
from fileEntry import FileEntries, remove
from dictdeal import json2data
from rssbotlib import loadRSSBotLib, AddVideoInfoResult
-from time import sleep
+from time import sleep, time
from miraiDatabase import MiraiDatabase
from mirai import Mirai
-from blackList import BlackList
+from blackList import BlackList, InlineKeyBoardForBlackList, getInlineKeyBoardForBlackList, getTextContentForBlackInfo, getInlineKeyBoardForBlackInfo, getTextContentForUnbanBlackInfo, getInlineKeyBoardForUnbanBlackInfo, BlackInfo
MAX_ITEM_IN_MEDIA_GROUP = 10
@@ -702,7 +702,8 @@ class messageHandle(Thread):
if self._chatId is None:
print('未知的chat id')
return -1
- if self._main._blackList.isInBlackList(self._chatId):
+ self._fromUserId = self.__getFromUserId()
+ if self._main._blackList.isInBlackList(self._chatId) and not self._main._setting.botOwnerList.isOwner(self._fromUserId):
c = self.__getChatType()
if c == 'private':
c = '您'
@@ -717,7 +718,6 @@ class messageHandle(Thread):
if 'text' in self._data:
if 'entities' in self._data:
self._botCommand = self.__getBotCommand()
- self._fromUserId = self.__getFromUserId()
if self._fromUserId is not None:
di = {'chat_id': self._chatId}
if self.__getChatType() in ['supergroup', 'group'] and self._fromUserId is not None:
@@ -852,7 +852,7 @@ class messageHandle(Thread):
return
if self._botCommand is None and self._data['chat']['type'] in ['group', 'supergroup']:
return
- if self._botCommand is None or self._botCommand not in ['/help', '/rss', '/rsslist']:
+ if self._botCommand is None or self._botCommand not in ['/help', '/rss', '/rsslist', '/ban', '/banlist', '/unban']:
self._botCommand = '/help'
di = {'chat_id': self._chatId}
if self.__getChatType() in ['supergroup', 'group'] and self._fromUserId is not None:
@@ -860,7 +860,10 @@ class messageHandle(Thread):
if self._botCommand == '/help':
di['text'] = '''/help 显示帮助
/rss url 订阅RSS
-/rsslist [chatId] 获取RSS订阅列表'''
+/rsslist [chatId] 获取RSS订阅列表
+/ban 封禁某用户
+/banlist 查询被封禁列表
+/unban 取消封禁某用户'''
elif self._botCommand == '/rss':
self._botCommandPara = self._getCommandlinePara()
self._uri = None
@@ -893,6 +896,94 @@ class messageHandle(Thread):
else:
di['text'] = '正在确认操作者权限……'
self._needCheckUser = True
+ elif self._botCommand == '/banlist':
+ if self._fromUserId is None or not self._main._setting.botOwnerList.isOwner(self._fromUserId):
+ di['text'] = '❌你没有权限操作,请与Bot主人进行PY交易以获得权限。'
+ else:
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList())
+ elif self._botCommand in ['/ban', '/unban']:
+ isban = self._botCommand == '/ban'
+ words = '封禁' if isban else '取消封禁'
+ if self._fromUserId is None or not self._main._setting.botOwnerList.isOwner(self._fromUserId):
+ di['text'] = '❌你没有权限操作,请与Bot主人进行PY交易以获得权限。'
+ else:
+ ban_uid: int = None
+ title: str = None
+ if 'reply_to_message' in self._data and self._data['reply_to_message'] is not None:
+ try:
+ ban_uid = self._data['reply_to_message']['from']['id']
+ if self._data['reply_to_message']['from']['is_bot']:
+ di['text'] = f'尝试{words}Bot,你的请求被滥权了。'
+ self._main._request('sendMessage', 'post', json=di)
+ return
+ title = self._data['reply_to_message']['from']['first_name']
+ if self._data['reply_to_message']['from']['last_name'] is not None:
+ title += f" {self._data['reply_to_message']['from']['last_name']}"
+ if self._data['reply_to_message']['from']['username'] is not None:
+ title += f" ({self._data['reply_to_message']['from']['username']})"
+ except Exception:
+ pass
+ self._botCommandPara = self._getCommandlinePara()
+ first_uid = False
+ if ban_uid is None:
+ first_uid = True
+ if self._botCommandPara[0] in ['chat', 'channel', 'group']:
+ try:
+ ban_uid = self._data['chat']['id']
+ title = self._data['chat']['title']
+ except Exception:
+ pass
+ else:
+ try:
+ ban_uid = int(self._botCommandPara[0])
+ except Exception:
+ pass
+ if ban_uid is None:
+ di['text'] = f'未找到要{words}的用户。'
+ elif self._main._setting.botOwnerList.isOwner(ban_uid):
+ di['text'] = f'尝试{words}Bot主人,你的请求被滥权了。'
+ else:
+ bl = self._main._blackList.getBlackList()
+ ind = bl.find(ban_uid)
+ if ind > -1:
+ if isban:
+ di['text'] = '该用户已被封禁。'
+ self._main._request('sendMessage', 'post', json=di)
+ return
+ if bl[ind].from_config:
+ di['text'] = '无法取消封禁来自配置文件的用户,请修改配置文件后重启bot。'
+ self._main._request('sendMessage', 'post', json=di)
+ return
+ re = self._main._blackList.unban(bl[ind].uid)
+ if title is None or title == '':
+ title = str(ban_uid)
+ link = '' if ban_uid < 0 else f'tg://user?id={ban_uid}'
+ if re:
+ di['text'] = f'取消封禁{title}成功!'
+ else:
+ di['text'] = f'取消封禁{title}失败!'
+ di['parse_mode'] = 'HTML'
+ else:
+ if not isban:
+ di['text'] = '该用户未被封禁'
+ self._main._request('sendMessage', 'post', json=di)
+ return
+ reason = ''
+ if first_uid and len(self._botCommandPara) > 1:
+ reason = self._botCommandPara[1]
+ elif not first_uid and len(self._botCommandPara) > 0:
+ reason = self._botCommandPara[0]
+ info = BlackInfo(ban_uid, self._fromUserId, int(time()), reason, title)
+ re = self._main._blackList.ban(info)
+ if title is None or title == '':
+ title = str(ban_uid)
+ link = '' if ban_uid < 0 else f'tg://user?id={ban_uid}'
+ if re:
+ di['text'] = f'封禁{title}成功!封禁理由:{reason}'
+ else:
+ di['text'] = f'封禁{title}失败!'
+ di['parse_mode'] = 'HTML'
re = self._main._request('sendMessage', 'post', json=di)
if self._botCommand == '/rss' and self._uri is not None and re is not None and 'ok' in re and re['ok']:
re = re['result']
@@ -969,13 +1060,13 @@ class callbackQueryHandle(Thread):
self.answer('您已被封禁。')
return
l = self._data['data'].split(',')
- if len(l) < 3:
- self.answer('错误的按钮数据。')
- return
self._inputList = l
try:
self._loc = int(l[0])
if self._loc == 0:
+ if len(l) < 3:
+ self.answer('错误的按钮数据。')
+ return
self._hashd = l[1]
self._command = int(l[2])
except:
@@ -1385,6 +1476,96 @@ class callbackQueryHandle(Thread):
chatId, rss, ind, self._main._setting.botOwnerList.isOwner(self._fromUserId))
self._main._request("editMessageText", "post", json=di)
return
+ elif self._loc == 2:
+ if 'message' not in self._data:
+ self.answer('找不到信息。')
+ return
+ if self._fromUserId is None or not self._main._setting.botOwnerList.isOwner(self._fromUserId):
+ self.answer('❌你没有权限操作,请与Bot主人进行PY交易以获得权限。')
+ return
+ try:
+ self._inlineKeyBoardForBlackListCommand = InlineKeyBoardForBlackList(int(self._inputList[1]))
+ except Exception:
+ self.answer('未知的按钮。')
+ return
+ di = {'chat_id': self._data['message']['chat']['id'],
+ 'message_id': self._data['message']['message_id']}
+ if self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.FirstPage:
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList())
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.LastPage:
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList(), lastPage=True)
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.PrevPage:
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList(), int(self._inputList[2]) - 1)
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.NextPage:
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList(), int(self._inputList[2]) + 1)
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.Close:
+ self._main._request("deleteMessage", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand in [InlineKeyBoardForBlackList.BlackInfo, InlineKeyBoardForBlackList.CancleUnban]:
+ bl = self._main._blackList.getBlackList()
+ ind = bl.find(int(self._inputList[3]))
+ if ind == -1:
+ self.answer('在黑名单里找不到该用户。')
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(bl, itemIndex=int(self._inputList[2]))
+ self._main._request("editMessageText", "post", json=di)
+ return
+ else:
+ di['text'] = getTextContentForBlackInfo(bl[ind])
+ di['parse_mode'] = 'HTML'
+ di['reply_markup'] = getInlineKeyBoardForBlackInfo(bl[ind], ind)
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.BackToList:
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList(), itemIndex=int(self._inputList[2]))
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.Unban:
+ bl = self._main._blackList.getBlackList()
+ ind = bl.find(int(self._inputList[3]))
+ if ind == -1:
+ self.answer('在黑名单里找不到该用户。')
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(bl, itemIndex=int(self._inputList[2]))
+ self._main._request("editMessageText", "post", json=di)
+ return
+ else:
+ if bl[ind].from_config:
+ self.answer('无法取消封禁来自配置文件的用户,请修改配置文件后重启bot。')
+ return
+ di['text'] = getTextContentForUnbanBlackInfo(bl[ind])
+ di['parse_mode'] = 'HTML'
+ di['reply_markup'] = getInlineKeyBoardForUnbanBlackInfo(bl[ind], ind)
+ self._main._request("editMessageText", "post", json=di)
+ return
+ elif self._inlineKeyBoardForBlackListCommand == InlineKeyBoardForBlackList.ConfirmUnban:
+ bl = self._main._blackList.getBlackList()
+ ind = bl.find(int(self._inputList[3]))
+ if ind == -1:
+ self.answer('在黑名单里找不到该用户。')
+ else:
+ if bl[ind].from_config:
+ self.answer('无法取消封禁来自配置文件的用户,请修改配置文件后重启bot。')
+ return
+ re = self._main._blackList.unban(bl[ind].uid)
+ self.answer('取消封禁' + ('成功!' if re else '失败!'))
+ di['text'] = '列表如下:'
+ di['reply_markup'] = getInlineKeyBoardForBlackList(self._main._blackList.getBlackList(), itemIndex=int(self._inputList[2]))
+ self._main._request("editMessageText", "post", json=di)
+ return
else:
self.answer('未知的按钮。')
return
diff --git a/textc.py b/textc.py
index 2e96ffe..47c7422 100644
--- a/textc.py
+++ b/textc.py
@@ -162,6 +162,10 @@ class textc:
p.close()
return len(p.s)
+ def __iadd__(self, i):
+ self.addtotext(i)
+ return self
+
def __init__(self):
self.__str = ''
self.__max = 4096