mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-10 16:04:37 +08:00
fix: deduplicate SunnyPT site messages
This commit is contained in:
@@ -78,23 +78,7 @@ class SiteChain(ChainBase):
|
||||
eventmanager.send_event(EventType.SiteRefreshed, {
|
||||
"site_id": site.get("id")
|
||||
})
|
||||
# 发送站点消息
|
||||
if userdata.message_unread:
|
||||
if userdata.message_unread_contents and len(userdata.message_unread_contents) > 0:
|
||||
for head, date, content in userdata.message_unread_contents:
|
||||
msg_title = f"【站点 {site.get('name')} 消息】"
|
||||
msg_text = f"时间:{date}\n标题:{head}\n内容:\n{content}"
|
||||
self.post_message(Notification(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=msg_title, text=msg_text, link=site.get("url")
|
||||
))
|
||||
else:
|
||||
self.post_message(Notification(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"站点 {site.get('name')} 收到 "
|
||||
f"{userdata.message_unread} 条新消息,请登陆查看",
|
||||
link=site.get("url")
|
||||
))
|
||||
self._post_site_messages(site=site, userdata=userdata)
|
||||
# 低分享率警告
|
||||
if userdata.ratio and float(userdata.ratio) < 1 and not bool(
|
||||
re.search(r"(贵宾|VIP?)", userdata.user_level or "", re.IGNORECASE)):
|
||||
@@ -105,6 +89,38 @@ class SiteChain(ChainBase):
|
||||
))
|
||||
return userdata
|
||||
|
||||
def _post_site_messages(self, site: dict, userdata: SiteUserData) -> None:
|
||||
"""
|
||||
发送站点未读消息,并按解析器提供的来源标识做持久化去重。
|
||||
|
||||
:param site: 站点索引配置
|
||||
:param userdata: 本次刷新的站点用户数据
|
||||
"""
|
||||
if not userdata.message_unread:
|
||||
return
|
||||
if not userdata.message_unread_contents:
|
||||
self.post_message(Notification(
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=f"站点 {site.get('name')} 收到 "
|
||||
f"{userdata.message_unread} 条新消息,请登陆查看",
|
||||
link=site.get("url")
|
||||
))
|
||||
return
|
||||
for message in userdata.message_unread_contents:
|
||||
head, date, content, *metadata = message
|
||||
message_source = metadata[0] if metadata else None
|
||||
if message_source and self.messageoper.exists_by_source(message_source):
|
||||
continue
|
||||
msg_title = f"【站点 {site.get('name')} 消息】"
|
||||
msg_text = f"时间:{date}\n标题:{head}\n内容:\n{content}"
|
||||
self.post_message(Notification(
|
||||
source=message_source,
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title=msg_title,
|
||||
text=msg_text,
|
||||
link=site.get("url")
|
||||
))
|
||||
|
||||
def refresh_userdatas(
|
||||
self,
|
||||
progress_callback: Optional[Callable[..., None]] = None,
|
||||
|
||||
@@ -105,6 +105,15 @@ class MessageOper(DbOper):
|
||||
"""
|
||||
return Message.list_by_page(self._db, page, count)
|
||||
|
||||
def exists_by_source(self, source: str) -> bool:
|
||||
"""
|
||||
判断指定来源标识的消息记录是否存在。
|
||||
|
||||
:param source: 消息来源唯一标识
|
||||
:return: 是否存在匹配记录
|
||||
"""
|
||||
return Message.exists_by_source(self._db, source)
|
||||
|
||||
async def async_list_by_page(
|
||||
self, page: Optional[int] = 1, count: Optional[int] = 30
|
||||
) -> list[Message]:
|
||||
|
||||
@@ -62,6 +62,18 @@ class Message(Base):
|
||||
.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@db_query
|
||||
def exists_by_source(cls, db: Session, source: str) -> bool:
|
||||
"""
|
||||
判断指定来源标识的消息记录是否存在。
|
||||
|
||||
:param db: 数据库会话
|
||||
:param source: 消息来源唯一标识
|
||||
:return: 是否存在匹配记录
|
||||
"""
|
||||
return db.query(cls.id).filter(cls.source == source).first() is not None
|
||||
|
||||
@classmethod
|
||||
@async_db_query
|
||||
async def async_list_by_page(
|
||||
|
||||
@@ -123,8 +123,12 @@ class SunnyPTSiteUserInfo(SiteParserBase):
|
||||
title = message.get("title")
|
||||
content = message.get("content")
|
||||
created_at = StringUtils.unify_datetime_str(message.get("created_at"))
|
||||
message_id = message.get("id")
|
||||
if title and content and created_at:
|
||||
self.message_unread_contents.append((title, created_at, content))
|
||||
message_source = f"sunnypt-message:{message_id}" if message_id is not None else None
|
||||
self.message_unread_contents.append(
|
||||
(title, created_at, content, message_source)
|
||||
)
|
||||
return "next" if messages_data.get("has_more") else None
|
||||
|
||||
def _parse_user_traffic_info(self, html_text: str) -> None:
|
||||
|
||||
@@ -9,10 +9,11 @@ from app.chain.download import DownloadChain
|
||||
from app.chain.site import SiteChain
|
||||
from app.core.config import settings
|
||||
from app.core.context import TorrentInfo
|
||||
from app.db.message_oper import MessageOper
|
||||
from app.modules.indexer import IndexerModule
|
||||
from app.modules.indexer.parser.sunnypt import SunnyPTSiteUserInfo
|
||||
from app.modules.indexer.spider.sunnypt import SunnyPTSpider
|
||||
from app.schemas import MediaType
|
||||
from app.schemas import MediaType, NotificationType
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
@@ -286,11 +287,47 @@ def test_sunnypt_user_parser_reads_profile_and_messages_without_marking_read(mon
|
||||
assert parser.leeching_size == 10737418240
|
||||
assert parser.message_unread == 1
|
||||
assert parser.message_unread_contents == [
|
||||
("种子审核通过", "2026-07-21 16:30:00", "你发布的种子已审核通过。")
|
||||
(
|
||||
"种子审核通过",
|
||||
"2026-07-21 16:30:00",
|
||||
"你发布的种子已审核通过。",
|
||||
"sunnypt-message:9001",
|
||||
)
|
||||
]
|
||||
assert not any(url.endswith("/read") or url.endswith("/read-all") for url in requested_urls)
|
||||
|
||||
|
||||
def test_site_messages_are_deduplicated_by_persisted_source(monkeypatch):
|
||||
"""站点消息应使用解析器保留的消息 ID 来源标识做持久化去重。"""
|
||||
duplicate_source = "sunnypt-message:9001-dedup-test"
|
||||
MessageOper().add(
|
||||
source=duplicate_source,
|
||||
mtype=NotificationType.SiteMessage,
|
||||
title="existing",
|
||||
text="existing",
|
||||
)
|
||||
sent_messages = []
|
||||
chain = object.__new__(SiteChain)
|
||||
chain.messageoper = MessageOper()
|
||||
monkeypatch.setattr(chain, "post_message", sent_messages.append)
|
||||
userdata = SimpleNamespace(
|
||||
message_unread=2,
|
||||
message_unread_contents=[
|
||||
("重复消息", "2026-07-21 16:30:00", "旧内容", duplicate_source),
|
||||
("新消息", "2026-07-22 16:30:00", "新内容", "sunnypt-message:9002-dedup-test"),
|
||||
],
|
||||
)
|
||||
|
||||
chain._post_site_messages(
|
||||
site={"name": "Sunny", "url": "https://sunnypt.top/"},
|
||||
userdata=userdata,
|
||||
)
|
||||
|
||||
assert len(sent_messages) == 1
|
||||
assert sent_messages[0].source == "sunnypt-message:9002-dedup-test"
|
||||
assert sent_messages[0].title == "【站点 Sunny 消息】"
|
||||
|
||||
|
||||
def test_indexer_module_dispatches_sunnypt_search(monkeypatch):
|
||||
"""IndexerModule 应把 SunnyPT 同步搜索参数交给专用 API Spider。"""
|
||||
captured = {}
|
||||
|
||||
Reference in New Issue
Block a user