diff --git a/README.md b/README.md index 7bb4022..3993dba 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Telegram RSS Bot +- [开始使用](#开始使用) +- [配置](#配置) +- [命令行参数](#命令行参数) ## 开始使用 安装依赖库,配置好设置里的`token`参数,然后运行`rssbot.py`即可。 ## 配置 @@ -47,7 +50,9 @@ rssbotLib=rssbot.dll ### databaseLocation 可选参数。数据库位置。默认值为`data.db`。 ### retryTTL -可选参数。RSS更新发生错误后,再次更新的间隔时间。默认值为`30`。单位为分。 +可选参数。RSS更新发生错误后,再次更新的间隔时间。支持以`,`为分隔的列表,分别表示第一次更新错误后等待的时间、第二次更新错误后等待的时间……超过列表范围会采用列表中的最后一个值。 +例如设置为`5,15`,则第一次更新错误后等待5分钟,第二次更新错误后等待15分钟,第三次更新错误后等待15分钟…… +默认值为`30`。单位为分。 ### botOwnerList 可选参数。具有特殊权限的用户ID,这些用户可以使用部分特殊功能。可以使用`,`分隔两个不同的ID。 特殊权限: diff --git a/RSSEntry.py b/RSSEntry.py index 0fd4125..c2e41a2 100644 --- a/RSSEntry.py +++ b/RSSEntry.py @@ -139,5 +139,8 @@ class RSSEntry: self.forceupdate = False if data is not None and data[6] is not None: self.forceupdate = bool(data[6]) + self.errorcount = 0 + if data is not None and data[7] is not None: + self.errorcount = data[7] self.chatList = [] self.hashList = HashEntries(maxCount) diff --git a/database.py b/database.py index e099282..b573dd8 100644 --- a/database.py +++ b/database.py @@ -55,6 +55,10 @@ class database: 'ALTER TABLE RSSList ADD forceupdate BOOLEAN;') self._db.execute('UPDATE RSSList SET forceupdate=false;') self._db.commit() + if v < [1, 0, 0, 3]: + self._db.execute('ALTER TABLE RSSList ADD errorcount INT;') + self._db.execute('UPDATE RSSList SET errorcount=0;') + self._db.commit() self.__write_version() return True @@ -76,6 +80,7 @@ lastupdatetime INT, id TEXT, lasterrortime INT, forceupdate BOOLEAN, +errorcount INT, PRIMARY KEY (id) );''') if 'chatList' not in self._exist_tables: @@ -101,7 +106,7 @@ PRIMARY KEY (hash) self._db.commit() def __init__(self, m, loc: str): - self._version = [1, 0, 0, 2] + self._version = [1, 0, 0, 3] self._value_lock = Lock() self._db = sqlite3.connect(loc, check_same_thread=False) ok = self.__check_database() @@ -145,7 +150,7 @@ PRIMARY KEY (hash) f"UPDATE RSSList SET title='{dealtext(title)}', interval={ttl if ttl is not None else 'null'} WHERE id='{hashd}'") else: self._db.execute( - f"INSERT INTO RSSList VALUES ('{dealtext(title)}', '{dealtext(url)}', {ttl if ttl is not None else 'null'}, {int(time())}, '{hashd}', null, false)") + f"INSERT INTO RSSList VALUES ('{dealtext(title)}', '{dealtext(url)}', {ttl if ttl is not None else 'null'}, {int(time())}, '{hashd}', null, false, 0)") cur = self._db.execute( f'SELECT * FROM chatList WHERE id="{hashd}" AND chatId={chatId}') has_data2 = False @@ -199,11 +204,11 @@ PRIMARY KEY (hash) def getRSSListByChatId(self, chatId: int) -> List[RSSEntry]: with self._value_lock: cur = self._db.execute( - f"SELECT RSSList.title, RSSList.url, RSSList.interval, RSSList.lastupdatetime, RSSList.id, RSSList.lasterrortime, RSSList.forceupdate, chatList.config FROM RSSList, chatList WHERE chatList.chatId = {chatId} AND RSSList.id = chatList.id ORDER BY title") + f"SELECT RSSList.title, RSSList.url, RSSList.interval, RSSList.lastupdatetime, RSSList.id, RSSList.lasterrortime, RSSList.forceupdate, RSSList.errorcount, chatList.config FROM RSSList, chatList WHERE chatList.chatId = {chatId} AND RSSList.id = chatList.id ORDER BY title") RSSEntries = [] for i in cur: rssEntry = RSSEntry(i, self._main._setting._maxCount) - rssEntry.chatList.append(ChatEntry((chatId, i[4], i[7]))) + rssEntry.chatList.append(ChatEntry((chatId, i[4], i[8]))) RSSEntries.append(rssEntry) return RSSEntries @@ -307,7 +312,7 @@ PRIMARY KEY (hash) if not has_data: return False self._db.execute( - f"UPDATE RSSList SET title='{dealtext(title)}', interval={ttl if ttl is not None else 'null'}, lastupdatetime={lastupdatetime} WHERE id='{hashd}'") + f"UPDATE RSSList SET title='{dealtext(title)}', interval={ttl if ttl is not None else 'null'}, lastupdatetime={lastupdatetime}, errorcount=0 WHERE id='{hashd}'") cur = self._db.execute( f"SELECT * FROM hashList WHERE id='{hashd}'") has_data2 = False @@ -332,13 +337,14 @@ PRIMARY KEY (hash) cur = self._db.execute( f'SELECT * FROM RSSList WHERE id="{hashd}"') has_data = False - for i in cur: # pylint: disable=unused-variable + for i in cur: + rss = RSSEntry(i, self._main._setting._maxCount) has_data = True break if not has_data: return False self._db.execute( - f"UPDATE RSSList SET lasterrortime={lasterrortime} WHERE id='{hashd}'") + f"UPDATE RSSList SET lasterrortime={lasterrortime}, errorcount={rss.errorcount + 1} WHERE id='{hashd}'") self._db.commit() return True except: diff --git a/readset.py b/readset.py index cb0437f..292d0a8 100644 --- a/readset.py +++ b/readset.py @@ -16,6 +16,7 @@ from typing import List from getopt import getopt from botOwner import BotOwnerList +from retryTTL import RetryTTLList class settings: @@ -49,8 +50,8 @@ class settings: d['sendFileURLScheme'])) if 'sendFileURLScheme' in d and d['sendFileURLScheme'].isnumeric() else False self._rssbotLib = d['rssbotLib'] if 'rssbotLib' in d and d['rssbotLib'] != '' else None self._databaseLocation = d['databaseLocation'] if 'databaseLocation' in d and d['databaseLocation'] != '' else 'data.db' - self._retryTTL = int(d['retryTTL']) if 'retryTTL' in d and d['retryTTL'].isnumeric( - ) and int(d['retryTTL']) > 0 else 30 + self._retryTTL = RetryTTLList( + d['retryTTL']) if 'retryTTL' in d and d['retryTTL'] != '' else RetryTTLList() self._botOwnerList = BotOwnerList( self._main, d['botOwnerList']) if 'botOwnerList' in d and d['botOwnerList'] != '' else BotOwnerList(self._main) diff --git a/retryTTL.py b/retryTTL.py new file mode 100644 index 0000000..0b1d6e0 --- /dev/null +++ b/retryTTL.py @@ -0,0 +1,29 @@ +# (C) 2021 lifegpc +# This file is part of rssbot. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +class RetryTTLList: + def __init__(self, s: str = None): + self.__list = [] + if s is not None: + l = s.split(',') + for i in l: + if i.isnumeric(): + self.__list.append(int(i)) + if len(self.__list) == 0: + self.__list.append(30) + + def __getitem__(self, index: int) -> int: + index = int(index) + return None if index <= 0 else self.__list[index-1] if index <= len(self.__list) else self.__list[-1] diff --git a/rsschecker.py b/rsschecker.py index f4f0326..0413b06 100644 --- a/rsschecker.py +++ b/rsschecker.py @@ -84,8 +84,8 @@ class RSSCheckerThread(Thread): def __needUpdate(self, rss: RSSEntry): if rss.forceupdate: return True - if rss.lasterrortime is not None and rss.lasterrortime >= rss.lastupdatetime: - return True if int(time()) > rss.lasterrortime + self._main._setting._retryTTL * 60 else False + if rss.lasterrortime is not None and rss.lasterrortime >= rss.lastupdatetime and rss.errorcount > 0: + return True if int(time()) > rss.lasterrortime + self._main._setting._retryTTL[rss.errorcount] * 60 else False if rss.lastupdatetime is None: return True TTL = self._main._setting._minTTL diff --git a/rsslist.py b/rsslist.py index 331dbd3..6459420 100644 --- a/rsslist.py +++ b/rsslist.py @@ -54,6 +54,9 @@ def getTextContentForRSSInList(rssEntry: RSSEntry) -> str: if rssEntry.lasterrortime is not None: temp = f'上次更新失败时间:{timeToStr(rssEntry.lasterrortime)}' text.addtotext(temp) + if rssEntry.errorcount > 0: + temp = f'连续更新失败次数:{rssEntry.errorcount}' + text.addtotext(temp) if len(rssEntry.chatList) > 0: chatEntry: ChatEntry = rssEntry.chatList[0] config = chatEntry.config