🎈优化RSS推送的内容 (#259)

* 🧪 test(tests): 添加了RSS的单元测试

* 🎈 perf(rss and test): 优化了RSS部分源标题正文重复的问题

部分RSS源(RSSHub的Twitter)存在正文当标题用的情况,导致推送的时候呈现为两段重复的文字,现通过Jaccard相似系数来判断是否需要去重

* Update nonebot_bison/platform/rss.py

Co-authored-by: AzideCupric <57004769+AzideCupric@users.noreply.github.com>

* Update nonebot_bison/platform/rss.py

Co-authored-by: AzideCupric <57004769+AzideCupric@users.noreply.github.com>

* 🐞 fix(platform/rss): 修复了漏掉相似文本在后端位置的问题

* 🐞 fix(rss): 修正一些feed无法正确识别时间的bug

一些feed时间只有updated标签或者没有,原先的代码只能解析用published标签的时间

felinae98#275

* 🎈 perf(rss): 更改字符串相似度比较方法

从Jaccard相似系数比较相似度改为通过最长公共子序列来比较

* 🦄 refactor(rss): 重构实现字符串相似度比较的方法

使用标准库difflib代替原先手搓的LCS

* Update nonebot_bison/utils/__init__.py

Co-authored-by: felinae98 <731499577@qq.com>

* Update nonebot_bison/platform/rss.py

* Update nonebot_bison/platform/rss.py

---------

Co-authored-by: AzideCupric <57004769+AzideCupric@users.noreply.github.com>
Co-authored-by: felinae98 <731499577@qq.com>
This commit is contained in:
UKM 2023-07-18 11:54:49 +08:00 committed by GitHub
parent 1db15ffc75
commit 9838e25bad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 843 additions and 5 deletions

View File

@ -1,4 +1,5 @@
import calendar
import time
from typing import Any, Optional
import feedparser
@ -7,10 +8,17 @@ from httpx import AsyncClient
from ..post import Post
from ..types import RawPost, Target
from ..utils import scheduler
from ..utils import SchedulerConfig, text_similarity
from .platform import NewMessage
class RssSchedConf(SchedulerConfig):
name = "rss"
schedule_type = "interval"
schedule_setting = {"seconds": 30}
class Rss(NewMessage):
categories = {}
@ -19,7 +27,7 @@ class Rss(NewMessage):
name = "Rss"
enabled = True
is_common = True
scheduler = scheduler("interval", {"seconds": 30})
scheduler = RssSchedConf
has_target = True
@classmethod
@ -31,7 +39,12 @@ class Rss(NewMessage):
return feed["feed"]["title"]
def get_date(self, post: RawPost) -> int:
return calendar.timegm(post.published_parsed)
if hasattr(post, "published_parsed"):
return calendar.timegm(post.published_parsed)
elif hasattr(post, "updated_parsed"):
return calendar.timegm(post.updated_parsed)
else:
return calendar.timegm(time.gmtime())
def get_id(self, post: RawPost) -> Any:
return post.id
@ -45,9 +58,17 @@ class Rss(NewMessage):
return feed.entries
async def parse(self, raw_post: RawPost) -> Post:
text = raw_post.get("title", "") + "\n" if raw_post.get("title") else ""
title = raw_post.get("title", "")
soup = bs(raw_post.description, "html.parser")
text += soup.text.strip()
desc = soup.text.strip()
if not title or not desc:
text = title or desc
else:
if text_similarity(desc, title) > 0.8:
text = desc if len(desc) > len(title) else title
else:
text = f"{title}\n\n{desc}"
pics = list(map(lambda x: x.attrs["src"], soup("img")))
if raw_post.get("media_content"):
for media in raw_post["media_content"]:

View File

@ -1,3 +1,4 @@
import difflib
import re
import sys
from typing import Union
@ -109,3 +110,9 @@ def jaccard_text_similarity(str1: str, str2: str) -> float:
set1 = set(str1)
set2 = set(str2)
return len(set1 & set2) / len(set1 | set2)
def text_similarity(str1, str2) -> float:
matcher = difflib.SequenceMatcher(None, str1, str2)
t = sum(temp.size for temp in matcher.get_matching_blocks())
return t / min(len(str1), len(str2))

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
<id>tag:github.com,2008:https://github.com/R3nzTheCodeGOD/R3nzSkin/releases</id>
<link type="text/html" rel="alternate" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases"/>
<link type="application/atom+xml" rel="self" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases.atom"/>
<title>Release notes from R3nzSkin</title>
<updated>2023-06-29T00:46:26+08:00</updated>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.8</id>
<updated>2023-06-25T22:19:30+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.8"/>
<title>R3nzSkin</title>
<content>No content.</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.7</id>
<updated>2023-06-25T08:38:52+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.7"/>
<title>R3nzSkin</title>
<content>No content.</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.6</id>
<updated>2023-06-06T23:05:38+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.6"/>
<title>R3nzSkin</title>
<content type="html">&lt;p&gt;Added update available information&lt;/p&gt;</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.5</id>
<updated>2023-06-03T19:53:30+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.5"/>
<title>R3nzSkin</title>
<content type="html">&lt;p&gt;Added &quot;Hide to tray&quot; option to the injector&lt;/p&gt;</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
</feed>

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
<id>tag:github.com,2008:https://github.com/R3nzTheCodeGOD/R3nzSkin/releases</id>
<link type="text/html" rel="alternate" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases"/>
<link type="application/atom+xml" rel="self" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases.atom"/>
<title>Release notes from R3nzSkin</title>
<updated>2023-06-29T00:46:26+08:00</updated>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.9</id>
<updated>2023-06-29T00:46:57+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.9"/>
<title>R3nzSkin</title>
<content>No content.</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.8</id>
<updated>2023-06-25T22:19:30+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.8"/>
<title>R3nzSkin</title>
<content>No content.</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.7</id>
<updated>2023-06-25T08:38:52+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.7"/>
<title>R3nzSkin</title>
<content>No content.</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.6</id>
<updated>2023-06-06T23:05:38+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.6"/>
<title>R3nzSkin</title>
<content type="html">&lt;p&gt;Added update available information&lt;/p&gt;</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
<entry>
<id>tag:github.com,2008:Repository/410126695/v3.0.5</id>
<updated>2023-06-03T19:53:30+08:00</updated>
<link rel="alternate" type="text/html" href="https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.5"/>
<title>R3nzSkin</title>
<content type="html">&lt;p&gt;Added &quot;Hide to tray&quot; option to the injector&lt;/p&gt;</content>
<author>
<name>hotline1337</name>
</author>
<media:thumbnail height="30" width="30" url="https://avatars.githubusercontent.com/u/32012110?s=60&amp;v=4"/>
</entry>
</feed>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

57
tests/platforms/static/rss-top5-new.xml vendored Normal file
View File

@ -0,0 +1,57 @@
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>
<![CDATA[ Hot Wallpapers - wallhaven.cc ]]>
</title>
<link>https://wallhaven.cc/hot</link>
<atom:link href="https://rsshub.app/wallhaven/hot?limit=5" rel="self" type="application/rss+xml"/>
<description>
<![CDATA[ Hot Wallpapers - wallhaven.cc - Made with love by RSSHub(https://github.com/DIYgod/RSSHub) ]]>
</description>
<generator>RSSHub</generator>
<webMaster>i@diygod.me (DIYgod)</webMaster>
<language>zh-cn</language>
<lastBuildDate>Tue, 04 Jul 2023 06:23:09 GMT</lastBuildDate>
<ttl>120</ttl>
<item>
<title>
<![CDATA[ 85rjej.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/85/85rjej.jpg" src="https://th.wallhaven.cc/small/85/85rjej.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/85rjej</guid>
<link>https://wallhaven.cc/w/85rjej</link>
</item>
<item>
<title>
<![CDATA[ 2y322g.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/2y/2y322g.jpg" src="https://th.wallhaven.cc/small/2y/2y322g.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/2y322g</guid>
<link>https://wallhaven.cc/w/2y322g</link>
</item>
<item>
<title>
<![CDATA[ rrj6qw.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/rr/rrj6qw.jpg" src="https://th.wallhaven.cc/small/rr/rrj6qw.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/rrj6qw</guid>
<link>https://wallhaven.cc/w/rrj6qw</link>
</item>
<item>
<title>
<![CDATA[ 9drg1d.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/9d/9drg1d.jpg" src="https://th.wallhaven.cc/small/9d/9drg1d.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/9drg1d</guid>
<link>https://wallhaven.cc/w/9drg1d</link>
</item>
</channel>
</rss>

57
tests/platforms/static/rss-top5-old.xml vendored Normal file
View File

@ -0,0 +1,57 @@
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>
<![CDATA[ Hot Wallpapers - wallhaven.cc ]]>
</title>
<link>https://wallhaven.cc/hot</link>
<atom:link href="https://rsshub.app/wallhaven/hot?limit=5" rel="self" type="application/rss+xml"/>
<description>
<![CDATA[ Hot Wallpapers - wallhaven.cc - Made with love by RSSHub(https://github.com/DIYgod/RSSHub) ]]>
</description>
<generator>RSSHub</generator>
<webMaster>i@diygod.me (DIYgod)</webMaster>
<language>zh-cn</language>
<lastBuildDate>Tue, 04 Jul 2023 06:23:09 GMT</lastBuildDate>
<ttl>120</ttl>
<item>
<title>
<![CDATA[ 2y322g.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/2y/2y322g.jpg" src="https://th.wallhaven.cc/small/2y/2y322g.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/2y322g</guid>
<link>https://wallhaven.cc/w/2y322g</link>
</item>
<item>
<title>
<![CDATA[ rrj6qw.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/rr/rrj6qw.jpg" src="https://th.wallhaven.cc/small/rr/rrj6qw.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/rrj6qw</guid>
<link>https://wallhaven.cc/w/rrj6qw</link>
</item>
<item>
<title>
<![CDATA[ 9drg1d.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/9d/9drg1d.jpg" src="https://th.wallhaven.cc/small/9d/9drg1d.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/9drg1d</guid>
<link>https://wallhaven.cc/w/9drg1d</link>
</item>
<item>
<title>
<![CDATA[ vq5eem.jpg ]]>
</title>
<description>
<![CDATA[ <img alt="loading" class="lazyload" data-src="https://th.wallhaven.cc/small/vq/vq5eem.jpg" src="https://th.wallhaven.cc/small/vq/vq5eem.jpg" referrerpolicy="no-referrer"> ]]>
</description>
<guid isPermaLink="false">https://wallhaven.cc/w/vq5eem</guid>
<link>https://wallhaven.cc/w/vq5eem</link>
</item>
</channel>
</rss>

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
>
<channel>
<title><![CDATA[Twitter @アークナイツ公式]]></title>
<link>https://twitter.com/ArknightsStaff</link>
<atom:link href="https://rsshub.app/twitter/user/ArknightsStaff" rel="self" type="application/rss+xml" />
<description><![CDATA[YostarとHyperGryphが贈るスマートフォン向け新作ゲーム「#アークナイツ」の公式アカウントです。お問い合わせ⇛ https://t.co/wbdyNLoUaf
TVアニメ アークナイツ【冬隠帰路/PERISH IN FROST】鋭意制作中 - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)]]></description>
<generator>RSSHub</generator>
<webMaster>i@diygod.me (DIYgod)</webMaster>
<language>zh-cn</language>
<image>
<url>https://pbs.twimg.com/profile_images/1260264885771890689/2KcWaF8a.jpg</url>
<title><![CDATA[Twitter @アークナイツ公式]]></title>
<link>https://twitter.com/ArknightsStaff</link>
</image>
<lastBuildDate>Thu, 18 May 2023 11:56:00 GMT</lastBuildDate>
<ttl>1</ttl>
<item>
<title><![CDATA[【#統合戦略】 新テーマ「ミヅキと紺碧の樹」は5月23日16:00より開催 本日は新要素及びシステムの変更点を一部ご紹介します! 詳細は添付の画像をご確認...]]></title>
<description><![CDATA[【#統合戦略】<br>新テーマ「ミヅキと紺碧の樹」は5月23日16:00より開催<br><br>本日は新要素及びシステムの変更点を一部ご紹介します!<br>詳細は添付の画像をご確認ください。<br><br>#アークナイツ https://t.co/o2uULEpA5x<br><img style="" src="https://pbs.twimg.com/media/FwYdt9XaIAEU4gH?format=jpg&amp;name=orig" referrerpolicy="no-referrer"><br><img style="" src="https://pbs.twimg.com/media/FwYdt7LaEAIPntw?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Thu, 18 May 2023 04:00:10 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1659046193090134016</guid>
<link>https://twitter.com/ArknightsStaff/status/1659046193090134016</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【リマインド】 下記コーデの販売期限は、5月18日3:59までです。ご注意ください。 ・リー · お目を拝借 ・アイリス · 鏡からの来訪者 ・カゼマル · 軽...]]></title>
<description><![CDATA[【リマインド】<br>下記コーデの販売期限は、5月18日3:59までです。ご注意ください。<br><br>・リー · お目を拝借<br>・アイリス · 鏡からの来訪者<br>・カゼマル · 軽やかな幻影<br><br>#アークナイツ]]></description>
<pubDate>Wed, 17 May 2023 10:00:23 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658774457123733505</guid>
<link>https://twitter.com/ArknightsStaff/status/1658774457123733505</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【コーデ紹介】 ハニーベリー専用、EPOQUEサブブランドPasseシリーズ「荒野のあとに」。 学生時代の彼女が、臥せる母に語った想像上の未来の自分。 歳に見合わぬ...]]></title>
<description><![CDATA[【コーデ紹介】<br>ハニーベリー専用、EPOQUEサブブランドPasseシリーズ「荒野のあとに」。<br>学生時代の彼女が、臥せる母に語った想像上の未来の自分。<br><br>歳に見合わぬ少女の夢には、残酷な現実が影を落とす。<br>それでも母は娘の心になおも勇気が息づくのを嬉しく思っていた。<br><br>近日入荷予定!<br>#アークナイツ https://t.co/R8eGG1b9r3<br><img style="" src="https://pbs.twimg.com/media/FwT9U0dagAAr_P6?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Wed, 17 May 2023 07:00:10 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658729101069541377</guid>
<link>https://twitter.com/ArknightsStaff/status/1658729101069541377</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【オペレーター紹介】 カニパラートCV: #佐藤元) サーミ地方からやってきたヴァルポの少年。元救助隊員。 外の大地の物事に興味津々で、部族の医療環境を向上...]]></title>
<description><![CDATA[【オペレーター紹介】<br>カニパラートCV: #佐藤元)<br>サーミ地方からやってきたヴァルポの少年。元救助隊員。<br>外の大地の物事に興味津々で、部族の医療環境を向上させるという目的もあってか、特に機械系の扱いには積極的に取り組んでいる。<br><br>「救助開始!」<br><br>#アークナイツ https://t.co/4lmdg5guMy<br><img style="" src="https://pbs.twimg.com/media/FwTUH49aIAAt0Ww?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Wed, 17 May 2023 04:00:09 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658683798253608960</guid>
<link>https://twitter.com/ArknightsStaff/status/1658683798253608960</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【コーデ紹介】 ソラ専用、EPOQUEシリーズ「メロディオーソ」。 シラクーザのミラノ劇場で、ソラが舞台に立つ際に着る衣装。 普段はポップスターだからといって...]]></title>
<description><![CDATA[【コーデ紹介】<br>ソラ専用、EPOQUEシリーズ「メロディオーソ」。<br>シラクーザのミラノ劇場で、ソラが舞台に立つ際に着る衣装。<br><br>普段はポップスターだからといって、由緒正しき異国のクラシックをマスターできないわけではない。<br><br>近日入荷予定!<br>#アークナイツ https://t.co/2zGzighNxk<br><img style="" src="https://pbs.twimg.com/media/FwOzuPEacAA02zd?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Tue, 16 May 2023 07:00:06 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658366698179956736</guid>
<link>https://twitter.com/ArknightsStaff/status/1658366698179956736</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【オペレーター紹介】 クォーツCV: #逢田梨香子) クルビア出身の傭兵。 常日頃から懐中時計を持ち歩き、時間厳守を信条とする彼女は、規則正しい生活を自分に...]]></title>
<description><![CDATA[【オペレーター紹介】<br>クォーツCV: #逢田梨香子)<br>クルビア出身の傭兵。<br>常日頃から懐中時計を持ち歩き、時間厳守を信条とする彼女は、規則正しい生活を自分に課している。しかし、ロドスに来てからは少し心にゆとりが生まれたようだ。<br><br>「力よりも、攻撃のタイミングが重要だ。」<br><br>#アークナイツ https://t.co/cX8kLz8oQh<br><img style="" src="https://pbs.twimg.com/media/FwOYRGQaQAAdGOS?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Tue, 16 May 2023 05:00:09 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658336510670954497</guid>
<link>https://twitter.com/ArknightsStaff/status/1658336510670954497</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【アップデートのお知らせ】 下記日時にメンテナンスとアップデートをあわせて実施します。 ▼実施期間 5月23日10:00 ~ 16:00 ▼詳細内容 https://arknigh...]]></title>
<description><![CDATA[【アップデートのお知らせ】<br>下記日時にメンテナンスとアップデートをあわせて実施します。<br><br>▼実施期間<br>5月23日10:00 ~ 16:00<br><br>▼詳細内容<br>https://arknights.jp/news/328<br><br>アプリの更新が必要なため、あらかじめデータ連携をお済ませいただきますようお願いします。<br><br>#アークナイツ https://t.co/XEqAzM0XOu<br><img style="" src="https://pbs.twimg.com/media/FwN9RmZacAEQ599?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Tue, 16 May 2023 03:02:13 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658306831960412166</guid>
<link>https://twitter.com/ArknightsStaff/status/1658306831960412166</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
</channel>
</rss>

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
>
<channel>
<title><![CDATA[Twitter @アークナイツ公式]]></title>
<link>https://twitter.com/ArknightsStaff</link>
<atom:link href="https://rsshub.app/twitter/user/ArknightsStaff" rel="self" type="application/rss+xml" />
<description><![CDATA[YostarとHyperGryphが贈るスマートフォン向け新作ゲーム「#アークナイツ」の公式アカウントです。お問い合わせ⇛ https://t.co/wbdyNLoUaf
TVアニメ アークナイツ【冬隠帰路/PERISH IN FROST】鋭意制作中 - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)]]></description>
<generator>RSSHub</generator>
<webMaster>i@diygod.me (DIYgod)</webMaster>
<language>zh-cn</language>
<image>
<url>https://pbs.twimg.com/profile_images/1260264885771890689/2KcWaF8a.jpg</url>
<title><![CDATA[Twitter @アークナイツ公式]]></title>
<link>https://twitter.com/ArknightsStaff</link>
</image>
<lastBuildDate>Thu, 18 May 2023 11:56:00 GMT</lastBuildDate>
<ttl>1</ttl>
<item>
<title><![CDATA[【#統合戦略】 引き続き新テーマ「ミヅキと紺碧の樹」の新要素及びシステムの変更点を一部ご紹介します! 今回は「灯火」、「ダイス」、「記号認識」...]]></title>
<description><![CDATA[【#統合戦略】 <br>引き続き新テーマ「ミヅキと紺碧の樹」の新要素及びシステムの変更点を一部ご紹介します! <br><br>今回は「灯火」、「ダイス」、「記号認識」、「鍵」についてです。<br>詳細は添付の画像をご確認ください。<br><br>#アークナイツ https://t.co/ARmptV0Zvu<br><img style="" src="https://pbs.twimg.com/media/FwZG9YAacAIXDw2?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Thu, 18 May 2023 07:00:21 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1659091539023282178</guid>
<link>https://twitter.com/ArknightsStaff/status/1659091539023282178</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【#統合戦略】 新テーマ「ミヅキと紺碧の樹」は5月23日16:00より開催 本日は新要素及びシステムの変更点を一部ご紹介します! 詳細は添付の画像をご確認...]]></title>
<description><![CDATA[【#統合戦略】<br>新テーマ「ミヅキと紺碧の樹」は5月23日16:00より開催<br><br>本日は新要素及びシステムの変更点を一部ご紹介します!<br>詳細は添付の画像をご確認ください。<br><br>#アークナイツ https://t.co/o2uULEpA5x<br><img style="" src="https://pbs.twimg.com/media/FwYdt9XaIAEU4gH?format=jpg&amp;name=orig" referrerpolicy="no-referrer"><br><img style="" src="https://pbs.twimg.com/media/FwYdt7LaEAIPntw?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Thu, 18 May 2023 04:00:10 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1659046193090134016</guid>
<link>https://twitter.com/ArknightsStaff/status/1659046193090134016</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【リマインド】 下記コーデの販売期限は、5月18日3:59までです。ご注意ください。 ・リー · お目を拝借 ・アイリス · 鏡からの来訪者 ・カゼマル · 軽...]]></title>
<description><![CDATA[【リマインド】<br>下記コーデの販売期限は、5月18日3:59までです。ご注意ください。<br><br>・リー · お目を拝借<br>・アイリス · 鏡からの来訪者<br>・カゼマル · 軽やかな幻影<br><br>#アークナイツ]]></description>
<pubDate>Wed, 17 May 2023 10:00:23 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658774457123733505</guid>
<link>https://twitter.com/ArknightsStaff/status/1658774457123733505</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【コーデ紹介】 ハニーベリー専用、EPOQUEサブブランドPasseシリーズ「荒野のあとに」。 学生時代の彼女が、臥せる母に語った想像上の未来の自分。 歳に見合わぬ...]]></title>
<description><![CDATA[【コーデ紹介】<br>ハニーベリー専用、EPOQUEサブブランドPasseシリーズ「荒野のあとに」。<br>学生時代の彼女が、臥せる母に語った想像上の未来の自分。<br><br>歳に見合わぬ少女の夢には、残酷な現実が影を落とす。<br>それでも母は娘の心になおも勇気が息づくのを嬉しく思っていた。<br><br>近日入荷予定!<br>#アークナイツ https://t.co/R8eGG1b9r3<br><img style="" src="https://pbs.twimg.com/media/FwT9U0dagAAr_P6?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Wed, 17 May 2023 07:00:10 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658729101069541377</guid>
<link>https://twitter.com/ArknightsStaff/status/1658729101069541377</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【オペレーター紹介】 カニパラートCV: #佐藤元) サーミ地方からやってきたヴァルポの少年。元救助隊員。 外の大地の物事に興味津々で、部族の医療環境を向上...]]></title>
<description><![CDATA[【オペレーター紹介】<br>カニパラートCV: #佐藤元)<br>サーミ地方からやってきたヴァルポの少年。元救助隊員。<br>外の大地の物事に興味津々で、部族の医療環境を向上させるという目的もあってか、特に機械系の扱いには積極的に取り組んでいる。<br><br>「救助開始!」<br><br>#アークナイツ https://t.co/4lmdg5guMy<br><img style="" src="https://pbs.twimg.com/media/FwTUH49aIAAt0Ww?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Wed, 17 May 2023 04:00:09 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658683798253608960</guid>
<link>https://twitter.com/ArknightsStaff/status/1658683798253608960</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【コーデ紹介】 ソラ専用、EPOQUEシリーズ「メロディオーソ」。 シラクーザのミラノ劇場で、ソラが舞台に立つ際に着る衣装。 普段はポップスターだからといって...]]></title>
<description><![CDATA[【コーデ紹介】<br>ソラ専用、EPOQUEシリーズ「メロディオーソ」。<br>シラクーザのミラノ劇場で、ソラが舞台に立つ際に着る衣装。<br><br>普段はポップスターだからといって、由緒正しき異国のクラシックをマスターできないわけではない。<br><br>近日入荷予定!<br>#アークナイツ https://t.co/2zGzighNxk<br><img style="" src="https://pbs.twimg.com/media/FwOzuPEacAA02zd?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Tue, 16 May 2023 07:00:06 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658366698179956736</guid>
<link>https://twitter.com/ArknightsStaff/status/1658366698179956736</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【オペレーター紹介】 クォーツCV: #逢田梨香子) クルビア出身の傭兵。 常日頃から懐中時計を持ち歩き、時間厳守を信条とする彼女は、規則正しい生活を自分に...]]></title>
<description><![CDATA[【オペレーター紹介】<br>クォーツCV: #逢田梨香子)<br>クルビア出身の傭兵。<br>常日頃から懐中時計を持ち歩き、時間厳守を信条とする彼女は、規則正しい生活を自分に課している。しかし、ロドスに来てからは少し心にゆとりが生まれたようだ。<br><br>「力よりも、攻撃のタイミングが重要だ。」<br><br>#アークナイツ https://t.co/cX8kLz8oQh<br><img style="" src="https://pbs.twimg.com/media/FwOYRGQaQAAdGOS?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Tue, 16 May 2023 05:00:09 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658336510670954497</guid>
<link>https://twitter.com/ArknightsStaff/status/1658336510670954497</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
<item>
<title><![CDATA[【アップデートのお知らせ】 下記日時にメンテナンスとアップデートをあわせて実施します。 ▼実施期間 5月23日10:00 ~ 16:00 ▼詳細内容 https://arknigh...]]></title>
<description><![CDATA[【アップデートのお知らせ】<br>下記日時にメンテナンスとアップデートをあわせて実施します。<br><br>▼実施期間<br>5月23日10:00 ~ 16:00<br><br>▼詳細内容<br>https://arknights.jp/news/328<br><br>アプリの更新が必要なため、あらかじめデータ連携をお済ませいただきますようお願いします。<br><br>#アークナイツ https://t.co/XEqAzM0XOu<br><img style="" src="https://pbs.twimg.com/media/FwN9RmZacAEQ599?format=jpg&amp;name=orig" referrerpolicy="no-referrer">]]></description>
<pubDate>Tue, 16 May 2023 03:02:13 GMT</pubDate>
<guid isPermaLink="false">https://twitter.com/ArknightsStaff/status/1658306831960412166</guid>
<link>https://twitter.com/ArknightsStaff/status/1658306831960412166</link>
<author><![CDATA[アークナイツ公式]]></author>
</item>
</channel>
</rss>

169
tests/platforms/test_rss.py Normal file
View File

@ -0,0 +1,169 @@
import typing
import xml.etree.ElementTree as ET
from datetime import datetime
import pytest
import pytz
import respx
from httpx import AsyncClient, Response
from nonebug.app import App
from .utils import get_file
if typing.TYPE_CHECKING:
from nonebot_bison.platform.rss import Rss
@pytest.fixture
def dummy_user(app: App):
from nonebot_bison.types import User
user = User(123, "group")
return user
@pytest.fixture
def user_info_factory(app: App, dummy_user):
from nonebot_bison.types import UserSubInfo
def _user_info(category_getter, tag_getter):
return UserSubInfo(dummy_user, category_getter, tag_getter)
return _user_info
@pytest.fixture
def rss(app: App):
from nonebot_bison.platform import platform_manager
from nonebot_bison.utils import ProcessContext
return platform_manager["rss"](ProcessContext(), AsyncClient())
@pytest.fixture
def update_time_feed_1():
file = get_file("rss-twitter-ArknightsStaff.xml")
root = ET.fromstring(file)
item = root.find("channel/item")
current_time = datetime.now(pytz.timezone("GMT")).strftime(
"%a, %d %b %Y %H:%M:%S %Z"
)
pubdate_elem = item.find("pubDate")
pubdate_elem.text = current_time
return ET.tostring(root, encoding="unicode")
@pytest.fixture
def update_time_feed_2():
file = get_file("rss-ruanyifeng.xml")
root = ET.fromstring(file)
current_time = datetime.now(pytz.timezone("GMT")).strftime(
"%a, %d %b %Y %H:%M:%S %Z"
)
published_element = root.find(".//{*}published")
published_element.text = current_time
return ET.tostring(root, encoding="unicode")
@pytest.mark.asyncio
@respx.mock
async def test_fetch_new_1(
rss,
user_info_factory,
update_time_feed_1,
):
## 标题重复的情况
rss_router = respx.get("https://rsshub.app/twitter/user/ArknightsStaff")
rss_router.mock(
return_value=Response(200, text=get_file("rss-twitter-ArknightsStaff-0.xml"))
)
target = "https://rsshub.app/twitter/user/ArknightsStaff"
res1 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res1) == 0
rss_router.mock(return_value=Response(200, text=update_time_feed_1))
res2 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res2[0][1]) == 1
post1 = res2[0][1][0]
assert post1.url == "https://twitter.com/ArknightsStaff/status/1659091539023282178"
assert (
post1.text
== "【#統合戦略】 引き続き新テーマ「ミヅキと紺碧の樹」の新要素及びシステムの変更点を一部ご紹介します! 今回は「灯火」、「ダイス」、「記号認識」、「鍵」についてです。詳細は添付の画像をご確認ください。#アークナイツ https://t.co/ARmptV0Zvu"
)
@pytest.mark.asyncio
@respx.mock
async def test_fetch_new_2(
rss,
user_info_factory,
update_time_feed_2,
):
## 标题与正文不重复的情况
rss_router = respx.get("https://www.ruanyifeng.com/blog/atom.xml")
rss_router.mock(return_value=Response(200, text=get_file("rss-ruanyifeng-0.xml")))
target = "https://www.ruanyifeng.com/blog/atom.xml"
res1 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res1) == 0
rss_router.mock(return_value=Response(200, text=update_time_feed_2))
res2 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res2[0][1]) == 1
post1 = res2[0][1][0]
assert post1.url == "http://www.ruanyifeng.com/blog/2023/05/weekly-issue-255.html"
assert post1.text == "科技爱好者周刊(第 255 期):对待 AI 的正确态度\n\n这里记录每周值得分享的科技内容,周五发布。..."
@pytest.fixture
def update_time_feed_3():
file = get_file("rss-github-atom.xml")
root = ET.fromstring(file)
current_time = datetime.now(pytz.timezone("GMT")).strftime(
"%a, %d %b %Y %H:%M:%S %Z"
)
published_element = root.findall(".//{*}updated")[1]
published_element.text = current_time
return ET.tostring(root, encoding="unicode")
@pytest.mark.asyncio
@respx.mock
async def test_fetch_new_3(
rss,
user_info_factory,
update_time_feed_3,
):
## 只有<updated>没有<published>
rss_router = respx.get("https://github.com/R3nzTheCodeGOD/R3nzSkin/releases.atom")
rss_router.mock(return_value=Response(200, text=get_file("rss-github-atom-0.xml")))
target = "https://github.com/R3nzTheCodeGOD/R3nzSkin/releases.atom"
res1 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res1) == 0
rss_router.mock(return_value=Response(200, text=update_time_feed_3))
res2 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res2[0][1]) == 1
post1 = res2[0][1][0]
assert post1.url == "https://github.com/R3nzTheCodeGOD/R3nzSkin/releases/tag/v3.0.9"
assert post1.text == "R3nzSkin\n\nNo content."
@pytest.mark.asyncio
@respx.mock
async def test_fetch_new_4(
rss,
user_info_factory,
):
## 没有日期信息的情况
rss_router = respx.get("https://rsshub.app/wallhaven/hot?limit=5")
rss_router.mock(return_value=Response(200, text=get_file("rss-top5-old.xml")))
target = "https://rsshub.app/wallhaven/hot?limit=5"
res1 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res1) == 0
rss_router.mock(return_value=Response(200, text=get_file("rss-top5-new.xml")))
res2 = await rss.fetch_new_post(target, [user_info_factory([], [])])
assert len(res2[0][1]) == 1
post1 = res2[0][1][0]
assert post1.url == "https://wallhaven.cc/w/85rjej"
assert post1.text == "85rjej.jpg"