diff --git a/app/api/endpoints/site.py b/app/api/endpoints/site.py index 052f7bcc..fd847fbd 100644 --- a/app/api/endpoints/site.py +++ b/app/api/endpoints/site.py @@ -12,6 +12,7 @@ from app.core.security import verify_token from app.db import get_db from app.db.models.site import Site from app.db.models.siteicon import SiteIcon +from app.db.models.sitestatistic import SiteStatistic from app.db.systemconfig_oper import SystemConfigOper from app.helper.sites import SitesHelper from app.scheduler import Scheduler @@ -239,6 +240,22 @@ def read_site_by_domain( return site +@router.get("/statistic/{site_url}", summary="站点统计信息", response_model=schemas.SiteStatistic) +def read_site_by_domain( + site_url: str, + db: Session = Depends(get_db), + _: schemas.TokenPayload = Depends(verify_token) +) -> Any: + """ + 通过域名获取站点统计信息 + """ + domain = StringUtils.get_url_domain(site_url) + sitestatistic = SiteStatistic.get_by_domain(db, domain) + if sitestatistic: + return sitestatistic + return schemas.SiteStatistic(domain=domain) + + @router.get("/rss", summary="所有订阅站点", response_model=List[schemas.Site]) def read_rss_sites(db: Session = Depends(get_db)) -> List[dict]: """ diff --git a/app/chain/site.py b/app/chain/site.py index 94c0c741..5bf422dd 100644 --- a/app/chain/site.py +++ b/app/chain/site.py @@ -1,5 +1,6 @@ import base64 import re +from datetime import datetime from typing import Tuple, Optional from typing import Union from urllib.parse import urljoin @@ -13,6 +14,7 @@ from app.db.models.site import Site from app.db.site_oper import SiteOper from app.db.siteicon_oper import SiteIconOper from app.db.systemconfig_oper import SystemConfigOper +from app.db.sytestatistic_oper import SiteStatisticOper from app.helper.browser import PlaywrightHelper from app.helper.cloudflare import under_challenge from app.helper.cookie import CookieHelper @@ -43,6 +45,7 @@ class SiteChain(ChainBase): self.message = MessageHelper() self.cookiecloud = CookieCloudHelper() self.systemconfig = SystemConfigOper() + self.sitestatistic = SiteStatisticOper() # 特殊站点登录验证 self.special_site_test = { @@ -350,12 +353,21 @@ class SiteChain(ChainBase): # 模拟登录 try: + # 开始记时 + start_time = datetime.now() # 特殊站点测试 if self.special_site_test.get(domain): - return self.special_site_test[domain](site_info) - - # 通用站点测试 - return self.__test(site_info) + state, message = self.special_site_test[domain](site_info) + else: + # 通用站点测试 + state, message = self.__test(site_info) + # 统计 + seconds = (datetime.now() - start_time).seconds + if state: + self.sitestatistic.success(domain=domain, seconds=seconds) + else: + self.sitestatistic.fail(domain) + return state, message except Exception as e: return False, f"{str(e)}!" diff --git a/app/db/models/sitestatistic.py b/app/db/models/sitestatistic.py index e4bbd54c..44a27b1d 100644 --- a/app/db/models/sitestatistic.py +++ b/app/db/models/sitestatistic.py @@ -13,20 +13,18 @@ class SiteStatistic(Base): id = Column(Integer, Sequence('id'), primary_key=True, index=True) # 域名Key domain = Column(String, index=True) - # 站点名 - name = Column(String, nullable=False) # 成功次数 success = Column(Integer) # 失败次数 fail = Column(Integer) # 平均耗时 秒 seconds = Column(Integer) - # 耗时记录 Json - note = Column(String) # 最后一次访问状态 0-成功 1-失败 lst_state = Column(Integer) # 最后访问时间 lst_mod_date = Column(String, default=datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + # 耗时记录 Json + note = Column(String) @staticmethod @db_query diff --git a/app/db/sytestatistic_oper.py b/app/db/sytestatistic_oper.py new file mode 100644 index 00000000..202d516f --- /dev/null +++ b/app/db/sytestatistic_oper.py @@ -0,0 +1,68 @@ +import json +from datetime import datetime + +from app.db import DbOper +from app.db.models.sitestatistic import SiteStatistic + + +class SiteStatisticOper(DbOper): + """ + 站点统计管理 + """ + + def success(self, domain: str, seconds: int = None): + """ + 站点访问成功 + """ + lst_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + sta = SiteStatistic.get_by_domain(self._db, domain) + if sta: + avg_seconds, note = None, {} + if seconds: + note: dict = json.loads(sta.note or "{}") + note[lst_date] = seconds + avg_times = len(note.keys()) + avg_seconds = sum([v for v in note.values()]) // avg_times + sta.update(self._db, { + "success": sta.success + 1, + "seconds": avg_seconds or sta.seconds, + "lst_state": 0, + "lst_mod_date": lst_date, + "note": json.dumps(note) if note else sta.note + }) + else: + note = {} + if seconds: + note = { + lst_date: seconds + } + SiteStatistic( + domain=domain, + success=1, + fail=0, + seconds=seconds, + lst_state=0, + lst_mod_date=lst_date, + note=json.dumps(note) + ).create(self._db) + + def fail(self, domain: str): + """ + 站点访问失败 + """ + lst_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + sta = SiteStatistic.get_by_domain(self._db, domain) + if sta: + sta.update(self._db, { + "fail": sta.fail + 1, + "lst_state": 1, + "lst_mod_date": lst_date + }) + else: + SiteStatistic( + domain=domain, + success=0, + fail=1, + lst_state=1, + lst_mod_date=lst_date + ).create(self._db) diff --git a/app/helper/rss.py b/app/helper/rss.py index 36eba104..2470c95b 100644 --- a/app/helper/rss.py +++ b/app/helper/rss.py @@ -225,7 +225,7 @@ class RssHelper: } @staticmethod - def parse(url, proxy: bool = False, timeout: int = 30) -> Union[List[dict], None]: + def parse(url, proxy: bool = False, timeout: int = 15) -> Union[List[dict], None]: """ 解析RSS订阅URL,获取RSS中的种子信息 :param url: RSS地址 diff --git a/app/modules/indexer/__init__.py b/app/modules/indexer/__init__.py index b96a48d5..0a85853e 100644 --- a/app/modules/indexer/__init__.py +++ b/app/modules/indexer/__init__.py @@ -5,6 +5,7 @@ from ruamel.yaml import CommentedMap from app.core.config import settings from app.core.context import TorrentInfo +from app.db.sytestatistic_oper import SiteStatisticOper from app.helper.sites import SitesHelper from app.log import logger from app.modules import _ModuleBase @@ -70,10 +71,12 @@ class IndexerModule(_ModuleBase): # 开始索引 result_array = [] + # 开始计时 start_time = datetime.now() # 搜索多个关键字 + error_flag = False for search_word in keywords: # 可能为关键字或ttxxxx if search_word \ @@ -126,7 +129,14 @@ class IndexerModule(_ModuleBase): logger.error(f"{site.get('name')} 搜索出错:{str(err)}") # 索引花费的时间 - seconds = round((datetime.now() - start_time).seconds, 1) + seconds = (datetime.now() - start_time).seconds + + # 统计索引情况 + domain = StringUtils.get_url_domain(site.get("domain")) + if error_flag: + SiteStatisticOper().fail(domain) + else: + SiteStatisticOper().success(domain=domain, seconds=seconds) # 返回结果 if not result_array or len(result_array) == 0: diff --git a/app/schemas/site.py b/app/schemas/site.py index 6ced92da..a7d63479 100644 --- a/app/schemas/site.py +++ b/app/schemas/site.py @@ -41,3 +41,23 @@ class Site(BaseModel): class Config: orm_mode = True + + +class SiteStatistic(BaseModel): + # 站点ID + domain: Optional[int] + # 成功次数 + success: Optional[int] = 0 + # 失败次数 + fail: Optional[int] = 0 + # 平均响应时间 + seconds: Optional[int] = 0 + # 最后状态 + lst_state: Optional[int] = 0 + # 最后修改时间 + lst_mod_date: Optional[str] + # 备注 + note: Optional[str] = None + + class Config: + orm_mode = True