rsshub 1.0.0-master.f3315cd → 1.0.0-master.f378dab
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -48
- package/lib/api/radar/rules/all.ts +3 -6
- package/lib/api/radar/rules/one.ts +3 -6
- package/lib/config.ts +30 -22
- package/lib/errors/index.test.ts +1 -1
- package/lib/errors/index.tsx +2 -2
- package/lib/index.ts +1 -1
- package/lib/middleware/anti-hotlink.test.ts +191 -6
- package/lib/middleware/anti-hotlink.ts +28 -0
- package/lib/middleware/logger.ts +2 -2
- package/lib/middleware/parameter.test.ts +22 -5
- package/lib/middleware/parameter.ts +47 -17
- package/lib/registry.test.ts +8 -0
- package/lib/registry.ts +2 -0
- package/lib/router.js +1 -4
- package/lib/routes/141jav/index.ts +25 -21
- package/lib/routes/141ppv/index.ts +24 -20
- package/lib/routes/51cto/recommend.ts +45 -7
- package/lib/routes/51read/article.ts +82 -0
- package/lib/routes/51read/namespace.ts +6 -0
- package/lib/routes/5eplay/utils.ts +5 -3
- package/lib/routes/abc/index.ts +2 -2
- package/lib/routes/agri/index.ts +307 -0
- package/lib/routes/agri/namespace.ts +8 -0
- package/lib/routes/agri/templates/description.art +21 -0
- package/lib/routes/aljazeera/index.ts +2 -2
- package/lib/routes/anime1/anime.ts +63 -0
- package/lib/routes/anime1/namespace.ts +6 -0
- package/lib/routes/anime1/search.ts +57 -0
- package/lib/routes/apnews/api.ts +62 -0
- package/lib/routes/apnews/rss.ts +1 -1
- package/lib/routes/apnews/sitemap.ts +99 -0
- package/lib/routes/apnews/topics.ts +2 -2
- package/lib/routes/apnews/utils.ts +7 -5
- package/lib/routes/asus/bios.ts +88 -21
- package/lib/routes/asus/templates/bios.art +13 -6
- package/lib/routes/autocentre/index.ts +29 -0
- package/lib/routes/autocentre/namespace.ts +7 -0
- package/lib/routes/bestblogs/feeds.ts +107 -0
- package/lib/routes/bestblogs/namespace.ts +6 -0
- package/lib/routes/bilibili/api-interface.d.ts +1 -0
- package/lib/routes/bilibili/bilibili-recommend.ts +42 -0
- package/lib/routes/bilibili/cache.ts +25 -1
- package/lib/routes/bilibili/dynamic.ts +103 -101
- package/lib/routes/bilibili/followings-video.ts +9 -3
- package/lib/routes/bilibili/utils.ts +5 -0
- package/lib/routes/bilibili/video.ts +2 -1
- package/lib/routes/binance/announcement.ts +168 -0
- package/lib/routes/binance/types.ts +26 -0
- package/lib/routes/bing/daily-wallpaper.ts +1 -1
- package/lib/routes/bitget/announcement.ts +200 -0
- package/lib/routes/bitget/namespace.ts +6 -0
- package/lib/routes/bitget/type.ts +26 -0
- package/lib/routes/bjnews/cat.ts +43 -0
- package/lib/routes/bjnews/column.ts +43 -0
- package/lib/routes/bjnews/namespace.ts +6 -0
- package/lib/routes/bjnews/utils.ts +19 -0
- package/lib/routes/bjp/apod.ts +4 -2
- package/lib/routes/bjx/fd.ts +35 -26
- package/lib/routes/buaa/jiaowu.ts +1 -1
- package/lib/routes/buaa/lib/space/newbook.ts +171 -0
- package/lib/routes/buaa/lib/space/templates/newbook.art +44 -0
- package/lib/routes/bupt/jwc.ts +130 -0
- package/lib/routes/cccfna/index.ts +2 -2
- package/lib/routes/ccfa/index.ts +216 -0
- package/lib/routes/ccfa/namespace.ts +8 -0
- package/lib/routes/ccfa/templates/description.art +7 -0
- package/lib/routes/cctv/category.ts +16 -12
- package/lib/routes/cctv/xwlb.ts +32 -10
- package/lib/routes/cdu/jwgg.ts +79 -0
- package/lib/routes/cdu/namespace.ts +6 -0
- package/lib/routes/cffex/announcement.ts +73 -0
- package/lib/routes/cffex/namespace.ts +6 -0
- package/lib/routes/chikubi/index.ts +75 -0
- package/lib/routes/chikubi/namespace.ts +6 -0
- package/lib/routes/chikubi/utils.ts +82 -0
- package/lib/routes/chlinlearn/daily-blog.ts +55 -0
- package/lib/routes/chlinlearn/namespcae.ts +6 -0
- package/lib/routes/cls/subject.ts +153 -0
- package/lib/routes/cls/templates/description.art +21 -0
- package/lib/routes/copymanga/comic.ts +3 -1
- package/lib/routes/deeplearning/thebatch.ts +30 -18
- package/lib/routes/devolverdigital/blog.ts +59 -42
- package/lib/routes/devtrium/namespace.ts +6 -0
- package/lib/routes/devtrium/posts.ts +55 -0
- package/lib/routes/digitalcameraworld/news.ts +1 -1
- package/lib/routes/discord/channel.ts +10 -10
- package/lib/routes/discord/discord-api.ts +27 -32
- package/lib/routes/discord/templates/message.art +15 -0
- package/lib/routes/discourse/notifications.ts +2 -1
- package/lib/routes/discourse/official.ts +55 -0
- package/lib/routes/dockerhub/utils.ts +4 -3
- package/lib/routes/dongqiudi/result.ts +1 -1
- package/lib/routes/douban/movie/coming.ts +68 -0
- package/lib/routes/douban/templates/movie_coming.art +27 -0
- package/lib/routes/eastmoney/report/index.ts +63 -15
- package/lib/routes/eastmoney/templates/stock_description.art +36 -0
- package/lib/routes/eastmoney/utils.ts +35 -0
- package/lib/routes/easynomad/joblist.ts +56 -0
- package/lib/routes/easynomad/namespace.ts +6 -0
- package/lib/routes/espn/namespace.ts +6 -0
- package/lib/routes/espn/news.ts +120 -0
- package/lib/routes/espn/templates/media.art +19 -0
- package/lib/routes/fediverse/timeline.ts +35 -18
- package/lib/routes/flashcat/blog.ts +61 -0
- package/lib/routes/flashcat/namespace.ts +6 -0
- package/lib/routes/follow/namespace.ts +6 -0
- package/lib/routes/follow/profile.ts +69 -0
- package/lib/routes/follow/types.ts +38 -0
- package/lib/routes/ftm/index.ts +60 -0
- package/lib/routes/ftm/namespace.ts +6 -0
- package/lib/routes/galxe/index.ts +94 -0
- package/lib/routes/galxe/namespace.ts +9 -0
- package/lib/routes/gamersky/ent.ts +57 -0
- package/lib/routes/gamersky/namespace.ts +10 -0
- package/lib/routes/gamersky/news.ts +91 -0
- package/lib/routes/gamersky/review.ts +80 -0
- package/lib/routes/gamersky/utils.ts +94 -0
- package/lib/routes/gdut/oa-news.ts +12 -17
- package/lib/routes/geekpark/index.ts +219 -0
- package/lib/routes/geekpark/namespace.ts +8 -0
- package/lib/routes/geekpark/templates/description.art +21 -0
- package/lib/routes/gisreportsonline/index.ts +60 -0
- package/lib/routes/gisreportsonline/namespace.ts +6 -0
- package/lib/routes/github/activity.ts +4 -3
- package/lib/routes/github/comments.ts +32 -30
- package/lib/routes/github/search.ts +20 -18
- package/lib/routes/go/mhlw/pdf.ts +87 -0
- package/lib/routes/go/namespace.ts +8 -0
- package/lib/routes/go/niid/idwr-dl.ts +104 -0
- package/lib/routes/google/research.ts +45 -0
- package/lib/routes/gov/cbirc/index.ts +371 -0
- package/lib/routes/gov/chongqing/sydwgkzp.ts +4 -4
- package/lib/routes/gov/cn/namespace.ts +8 -0
- package/lib/routes/gov/{news → cn/news}/index.ts +11 -7
- package/lib/routes/gov/lswz/index.ts +289 -0
- package/lib/routes/gov/ndrc/fggz.ts +637 -2
- package/lib/routes/gov/ndrc/namespace.ts +8 -0
- package/lib/routes/gov/ndrc/xwdt.ts +28 -8
- package/lib/routes/gov/ndrc/zfxxgk/articles.ts +73 -0
- package/lib/routes/gov/zj/ningbogzw-notice.ts +50 -0
- package/lib/routes/gov/zj/ningborsjnotice.ts +50 -0
- package/lib/routes/gq/news.ts +1 -1
- package/lib/routes/gs/developer/blog.ts +58 -0
- package/lib/routes/gs/namespace.ts +9 -0
- package/lib/routes/healthz.ts +8 -0
- package/lib/routes/hket/index.ts +80 -76
- package/lib/routes/hottoys/index.ts +63 -0
- package/lib/routes/hottoys/namespace.ts +6 -0
- package/lib/routes/hpoi/all.ts +3 -2
- package/lib/routes/hpoi/character.ts +3 -2
- package/lib/routes/hpoi/work.ts +3 -2
- package/lib/routes/hust/gs.ts +281 -0
- package/lib/routes/hust/namespace.ts +1 -1
- package/lib/routes/imhcg/blog.ts +47 -0
- package/lib/routes/imhcg/namespace.ts +7 -0
- package/lib/routes/imop/namespace.ts +10 -0
- package/lib/routes/imop/tianshu.ts +53 -0
- package/lib/routes/infzm/hot.ts +39 -0
- package/lib/routes/infzm/index.ts +3 -30
- package/lib/routes/infzm/utils.ts +34 -0
- package/lib/routes/inspirehep/author.ts +46 -0
- package/lib/routes/inspirehep/literature.ts +42 -0
- package/lib/routes/inspirehep/namespace.ts +7 -0
- package/lib/routes/inspirehep/types.ts +210 -0
- package/lib/routes/inspirehep/utils.ts +15 -0
- package/lib/routes/iwara/subscriptions.ts +1 -1
- package/lib/routes/javdb/actors.ts +6 -2
- package/lib/routes/jjwxc/book.ts +18 -14
- package/lib/routes/joins/chinese.ts +218 -0
- package/lib/routes/joins/namespace.ts +8 -0
- package/lib/routes/joins/templates/description.art +17 -0
- package/lib/routes/juejin/dynamic.ts +114 -0
- package/lib/routes/kakuyomu/namespace.ts +6 -0
- package/lib/routes/kakuyomu/types.ts +6 -0
- package/lib/routes/kakuyomu/works.ts +73 -0
- package/lib/routes/kaopu/news.ts +3 -3
- package/lib/routes/kemono/index.ts +21 -0
- package/lib/routes/keylol/index.ts +56 -11
- package/lib/routes/kurogames/namespace.ts +7 -0
- package/lib/routes/kurogames/wutheringwaves/news.ts +59 -0
- package/lib/routes/link3/events.ts +86 -0
- package/lib/routes/link3/namespace.ts +6 -0
- package/lib/routes/link3/profile.ts +143 -0
- package/lib/routes/linkedin/cn/renderer.ts +1 -1
- package/lib/routes/lmu/jobs.ts +96 -0
- package/lib/routes/lmu/namespace.ts +17 -0
- package/lib/routes/lmu/templates/jobPosting.art +11 -0
- package/lib/routes/lofter/collection.ts +87 -0
- package/lib/routes/lofter/user.ts +1 -1
- package/lib/routes/luma/index.ts +92 -0
- package/lib/routes/luma/namespace.ts +6 -0
- package/lib/routes/malaysiakini/index.ts +179 -0
- package/lib/routes/malaysiakini/namespace.ts +11 -0
- package/lib/routes/mastodon/acct.ts +4 -3
- package/lib/routes/mastodon/timeline-local.ts +3 -2
- package/lib/routes/mastodon/timeline-remote.ts +3 -2
- package/lib/routes/mcmod/index.ts +105 -0
- package/lib/routes/mcmod/namespace.ts +6 -0
- package/lib/routes/mcmod/templates/mod.art +13 -0
- package/lib/routes/meishichina/index.ts +1997 -0
- package/lib/routes/meishichina/namespace.ts +8 -0
- package/lib/routes/misskey/user-timeline.ts +42 -0
- package/lib/routes/misskey/utils.ts +41 -1
- package/lib/routes/nationalgeographic/latest-stories.ts +1 -1
- package/lib/routes/nationalgeographic/templates/stories.art +1 -1
- package/lib/routes/newyorker/news.ts +24 -17
- package/lib/routes/nicovideo/namespace.ts +7 -0
- package/lib/routes/nicovideo/templates/video.art +7 -0
- package/lib/routes/nicovideo/types.ts +54 -0
- package/lib/routes/nicovideo/utils.ts +37 -0
- package/lib/routes/nicovideo/video.ts +47 -0
- package/lib/routes/oct0pu5/namespace.ts +10 -0
- package/lib/routes/oct0pu5/rss.ts +48 -0
- package/lib/routes/oschina/news.ts +2 -0
- package/lib/routes/pconline/focus.ts +143 -0
- package/lib/routes/pconline/namespace.ts +10 -0
- package/lib/routes/people/index.ts +8 -2
- package/lib/routes/picnob/user.ts +11 -3
- package/lib/routes/pixiv/search.ts +20 -1
- package/lib/routes/pixiv/utils.ts +3 -3
- package/lib/routes/pixivision/index.ts +84 -0
- package/lib/routes/pixivision/namespace.ts +6 -0
- package/lib/routes/pixivision/utils.ts +86 -0
- package/lib/routes/pku/bbs/hot.ts +1 -1
- package/lib/routes/pornhub/category.ts +3 -2
- package/lib/routes/pornhub/model.ts +4 -3
- package/lib/routes/pornhub/pornstar.ts +20 -8
- package/lib/routes/pornhub/search.ts +3 -2
- package/lib/routes/psyche/topic.ts +1 -1
- package/lib/routes/psyche/type.ts +1 -1
- package/lib/routes/psyche/utils.ts +1 -1
- package/lib/routes/qiche365/namespace.ts +5 -0
- package/lib/routes/qiche365/recall.ts +53 -0
- package/lib/routes/questn/community.ts +76 -0
- package/lib/routes/questn/events.ts +101 -0
- package/lib/routes/questn/namespace.ts +6 -0
- package/lib/routes/questn/util.ts +16 -0
- package/lib/routes/rebase/geekdaily.ts +35 -0
- package/lib/routes/rebase/namespace.ts +6 -0
- package/lib/routes/rss3/index.ts +22 -13
- package/lib/routes/rss3/interfaces/metadata.ts +67 -0
- package/lib/routes/rsshub/routes.ts +18 -12
- package/lib/routes/samd/news.ts +2 -2
- package/lib/routes/sara/index.ts +1 -1
- package/lib/routes/scut/gzic/media.ts +71 -0
- package/lib/routes/scut/gzic/news.ts +65 -0
- package/lib/routes/scut/gzic/notice.ts +88 -0
- package/lib/routes/sdu/{cs.ts → cs/index.ts} +46 -12
- package/lib/routes/sdu/cs/yjsgz.ts +85 -0
- package/lib/routes/sdu/gjsw.ts +80 -0
- package/lib/routes/sdu/namespace.ts +2 -2
- package/lib/routes/sdu/qd/xszxqd.ts +98 -0
- package/lib/routes/sdu/qd/xyb.ts +82 -0
- package/lib/routes/sdu/ygb.ts +90 -0
- package/lib/routes/shiep/config.ts +4 -10
- package/lib/routes/shiep/index.ts +9 -9
- package/lib/routes/showstart/artist.ts +5 -4
- package/lib/routes/showstart/brand.ts +5 -4
- package/lib/routes/showstart/event.ts +8 -7
- package/lib/routes/showstart/search.ts +43 -9
- package/lib/routes/showstart/service.ts +81 -53
- package/lib/routes/showstart/site.ts +41 -0
- package/lib/routes/showstart/utils.ts +9 -8
- package/lib/routes/sis001/author.ts +52 -0
- package/lib/routes/sis001/common.ts +38 -0
- package/lib/routes/sis001/forum.ts +2 -29
- package/lib/routes/sjtu/jwc.ts +4 -1
- package/lib/routes/sjtu/namespace.ts +1 -1
- package/lib/routes/sjtu/seiee/index.ts +97 -0
- package/lib/routes/smzdm/product.ts +86 -0
- package/lib/routes/soundon/namespace.ts +6 -0
- package/lib/routes/soundon/podcast.ts +80 -0
- package/lib/routes/soundon/types.ts +67 -0
- package/lib/routes/spotify/show.ts +1 -1
- package/lib/routes/springer/journal.ts +10 -12
- package/lib/routes/sse/sselawsrules.ts +370 -0
- package/lib/routes/sspai/author.ts +1 -1
- package/lib/routes/sspai/column.ts +1 -1
- package/lib/routes/sspai/index.ts +3 -3
- package/lib/routes/sspai/matrix.ts +1 -1
- package/lib/routes/sspai/series-update.ts +1 -1
- package/lib/routes/sspai/tag.ts +1 -1
- package/lib/routes/sspai/topic.ts +1 -1
- package/lib/routes/sustainabilitymag/articles.ts +2 -0
- package/lib/routes/swjtu/scai/bks.ts +80 -0
- package/lib/routes/szse/rule.ts +315 -42
- package/lib/routes/t66y/index.ts +29 -7
- package/lib/routes/taoguba/blog.ts +1 -1
- package/lib/routes/taoguba/index.ts +1 -1
- package/lib/routes/techcrunch/news.ts +20 -29
- package/lib/routes/techcrunch/templates/description.art +7 -0
- package/lib/routes/telegram/blog.ts +3 -2
- package/lib/routes/telegram/channel.ts +34 -1
- package/lib/routes/telegram/stickerpack.ts +3 -2
- package/lib/routes/tencent/news/author.ts +2 -1
- package/lib/routes/test/index.ts +50 -43
- package/lib/routes/the/index.ts +214 -0
- package/lib/routes/the/namespace.ts +8 -0
- package/lib/routes/the/templates/description.art +27 -0
- package/lib/routes/the/util.ts +307 -0
- package/lib/routes/theblockbeats/index.ts +10 -5
- package/lib/routes/theinitium/app.ts +137 -0
- package/lib/routes/theinitium/templates/description.art +17 -0
- package/lib/routes/threads/index.ts +26 -20
- package/lib/routes/tju/cic/index.ts +2 -2
- package/lib/routes/tju/news/index.ts +2 -2
- package/lib/routes/tju/oaa/index.ts +2 -2
- package/lib/routes/towardsdatascience/latest.ts +67 -0
- package/lib/routes/towardsdatascience/namespace.ts +6 -0
- package/lib/routes/tvb/news.ts +1 -0
- package/lib/routes/twitch/live.ts +3 -2
- package/lib/routes/twitch/video.ts +3 -2
- package/lib/routes/twitter/api/index.ts +2 -0
- package/lib/routes/twitter/api/mobile-api/login.ts +1 -1
- package/lib/routes/twitter/api/web-api/api.ts +18 -0
- package/lib/routes/twitter/api/web-api/constants.ts +17 -14
- package/lib/routes/twitter/api/web-api/login.ts +68 -0
- package/lib/routes/twitter/api/web-api/utils.ts +57 -32
- package/lib/routes/twitter/home-latest.ts +60 -0
- package/lib/routes/twitter/home.ts +1 -1
- package/lib/routes/twitter/list.ts +5 -2
- package/lib/routes/twitter/tweet.ts +1 -0
- package/lib/routes/twitter/user.ts +1 -1
- package/lib/routes/twitter/utils.ts +4 -1
- package/lib/routes/uber/blog.ts +1 -1
- package/lib/routes/ustc/scms.ts +97 -0
- package/lib/routes/v2ex/xna.ts +55 -0
- package/lib/routes/wchscu/namespace.ts +6 -0
- package/lib/routes/wchscu/recruit.ts +73 -0
- package/lib/routes/weibo/namespace.ts +1 -0
- package/lib/routes/weibo/oasis/user.ts +1 -1
- package/lib/routes/weibo/super-index.ts +23 -11
- package/lib/routes/weibo/user.ts +13 -2
- package/lib/routes/weibo/utils.ts +20 -4
- package/lib/routes/whu/cs.ts +11 -3
- package/lib/routes/whu/gs/index.ts +2 -1
- package/lib/routes/whu/news.ts +27 -2
- package/lib/routes/withgoogle/explorables.ts +54 -0
- package/lib/routes/withgoogle/namespace.ts +6 -0
- package/lib/routes/xiaohongshu/notes.ts +10 -2
- package/lib/routes/xiaohongshu/user.ts +27 -5
- package/lib/routes/xiaohongshu/util.ts +3 -1
- package/lib/routes/xidian/cs.ts +143 -0
- package/lib/routes/xidian/gr.ts +289 -0
- package/lib/routes/xidian/jwc.ts +1 -0
- package/lib/routes/xidian/namespace.ts +1 -1
- package/lib/routes/xueqiu/cookies.ts +14 -1
- package/lib/routes/xueqiu/favorite.ts +16 -2
- package/lib/routes/yahoo/news/index.ts +1 -0
- package/lib/routes/yahoo/news/listid.ts +67 -0
- package/lib/routes/yahoo/news/utils.ts +8 -2
- package/lib/routes/yicai/carousel.ts +48 -0
- package/lib/routes/yicai/utils.ts +23 -17
- package/lib/routes/yilinzazhi/index.ts +58 -0
- package/lib/routes/yilinzazhi/latest.ts +103 -0
- package/lib/routes/yilinzazhi/namespace.ts +8 -0
- package/lib/routes/youtube/subscriptions.ts +1 -0
- package/lib/routes/yystv/docs.ts +28 -19
- package/lib/routes/zaobao/util.ts +1 -1
- package/lib/routes/zhihu/answers.ts +5 -1
- package/lib/routes/zhihu/execlib/x-zse-96-v3.ts +2 -0
- package/lib/routes/zhihu/namespace.ts +3 -0
- package/lib/routes/zhihu/utils.ts +21 -4
- package/lib/routes/zhihu/zhuanlan.ts +8 -7
- package/lib/routes/zsxq/types.ts +9 -0
- package/lib/routes/zsxq/utils.ts +4 -3
- package/lib/routes.test.ts +11 -5
- package/lib/setup.test.ts +1 -1
- package/lib/types.ts +6 -0
- package/lib/utils/cache/index.ts +8 -0
- package/lib/utils/camelcase-keys.spec.ts +127 -0
- package/lib/utils/camelcase-keys.ts +27 -0
- package/lib/utils/common-utils.ts +1 -0
- package/lib/utils/otel/metric.ts +3 -2
- package/lib/views/error.tsx +3 -3
- package/lib/views/index.tsx +7 -9
- package/lib/views/json.ts +1 -1
- package/lib/views/layout.tsx +1 -1
- package/lib/views/rss.tsx +7 -0
- package/package.json +50 -48
- package/lib/routes/sse/lawandrules.ts +0 -68
- package/lib/routes-deprecated/anime1/anime.js +0 -25
- package/lib/routes-deprecated/anime1/search.js +0 -25
- package/lib/routes-deprecated/bjnews/news.js +0 -44
- package/lib/routes-deprecated/gamersky/ent.js +0 -89
- package/lib/routes-deprecated/gamersky/news.js +0 -34
- package/lib/routes-deprecated/geekpark/breakingnews.js +0 -25
package/README.md
CHANGED
|
@@ -12,29 +12,15 @@
|
|
|
12
12
|
[](https://app.codecov.io/gh/DIYgod/RSSHub/branch/master)
|
|
13
13
|
[](https://github.com/DIYgod/RSSHub)
|
|
14
14
|
|
|
15
|
-
[](https://t.me/rsshub) [](https://t.me/awesomeRSSHub) [](https://t.me/rsshub) [](https://t.me/awesomeRSSHub) [](https://x.com/intent/follow?screen_name=_RSSHub)
|
|
16
16
|
|
|
17
17
|
## Introduction
|
|
18
18
|
|
|
19
|
-
RSSHub is
|
|
19
|
+
RSSHub is the world's largest RSS network, consisting of over 5,000 global instances.
|
|
20
20
|
|
|
21
21
|
RSSHub delivers millions of contents aggregated from all kinds of sources, our vibrant open source community is ensuring the deliver of RSSHub's new routes, new features and bug fixes.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
[English docs](https://docs.rsshub.app) | [Telegram Group](https://t.me/rsshub) | [Telegram Channel](https://t.me/awesomeRSSHub) | [Twitter](https://x.com/intent/follow?screen_name=_RSSHub) | [中文文档](https://docs.rsshub.app/zh/)
|
|
26
|
-
|
|
27
|
-
## Special Thanks
|
|
28
|
-
|
|
29
|
-
### Contributors
|
|
30
|
-
|
|
31
|
-
[](https://github.com/DIYgod/RSSHub/graphs/contributors)
|
|
32
|
-
|
|
33
|
-
Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr)
|
|
34
|
-
|
|
35
|
-
### Backers
|
|
36
|
-
|
|
37
|
-
<a href="https://www.cloudflare.com" target="_blank"><img height="50px" src="https://i.imgur.com/7Ph27Fq.png"></a> <a href="https://www.netlify.com" target="_blank"><img height="40px" src="https://i.imgur.com/cU01915.png"></a> <a href="https://1password.com" target="_blank"><img height="40px" src="https://i.imgur.com/a2XjflO.png"></a>
|
|
23
|
+
[Documentation](https://docs.rsshub.app) | [Telegram Group](https://t.me/rsshub) | [Telegram Channel](https://t.me/awesomeRSSHub) | [X (Twitter)](https://x.com/intent/follow?screen_name=_RSSHub)
|
|
38
24
|
|
|
39
25
|
## Related Projects
|
|
40
26
|
|
|
@@ -43,53 +29,32 @@ Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr)
|
|
|
43
29
|
- [RSSAid](https://github.com/LeetaoGoooo/RSSAid) | RSSHub Radar for Android platform built with Flutter.
|
|
44
30
|
- [DocSearch](https://github.com/Fatpandac/DocSearch) | Link RSSHub DocSearch into Raycast
|
|
45
31
|
|
|
46
|
-
##
|
|
32
|
+
## Contribute
|
|
47
33
|
|
|
48
34
|
We welcome all pull requests. Suggestions and feedback are also welcomed [here](https://github.com/DIYgod/RSSHub/issues).
|
|
49
35
|
|
|
50
|
-
Refer to [
|
|
36
|
+
Refer to [Quick Start](https://docs.rsshub.app/joinus/)
|
|
51
37
|
|
|
52
38
|
## Deployment
|
|
53
39
|
|
|
54
40
|
Refer to [Deployment](https://docs.rsshub.app/deploy/)
|
|
55
41
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
Refer to [Support RSSHub](https://docs.rsshub.app/sponsor/)
|
|
59
|
-
|
|
60
|
-
RSSHub is open source and completely free under the MIT license. However, just like any other open source project, as the project grows, the hosting, development and maintenance requires funding support.
|
|
61
|
-
|
|
62
|
-
You can support RSSHub via donations.
|
|
63
|
-
|
|
64
|
-
### Recurring Donation
|
|
65
|
-
|
|
66
|
-
Recurring donors will be rewarded via express issue response, or even have your name displayed on our GitHub page and website.
|
|
67
|
-
|
|
68
|
-
- Become a Sponser on [GitHub](https://github.com/sponsors/DIYgod)
|
|
69
|
-
- Become a Sponser on [Patreon](https://www.patreon.com/DIYgod)
|
|
70
|
-
- Become a Sponser on [Open Collective](https://opencollective.com/RSSHub)
|
|
71
|
-
- Become a Sponser on [爱发电](https://afdian.net/@diygod)
|
|
72
|
-
- Contact us directly: <i@diygod.me>
|
|
42
|
+
## Special Thanks
|
|
73
43
|
|
|
74
|
-
|
|
44
|
+
<div align="center">
|
|
75
45
|
|
|
76
|
-
|
|
46
|
+
[](https://github.com/DIYgod/RSSHub/graphs/contributors)
|
|
77
47
|
|
|
78
|
-
|
|
79
|
-
- [Alipay](https://archive.diygod.me/images/zfb.jpg)
|
|
80
|
-
- [Paypal](https://www.paypal.me/DIYgod)
|
|
48
|
+
Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr)
|
|
81
49
|
|
|
82
|
-
|
|
50
|
+
[](https://github.com/DIYgod/sponsors)
|
|
83
51
|
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
<img src="https://raw.githubusercontent.com/DIYgod/sponsors/main/sponsors.wide.svg" />
|
|
87
|
-
</a>
|
|
88
|
-
</p>
|
|
52
|
+
<a href="https://www.cloudflare.com" target="_blank"><img height="50px" src="https://i.imgur.com/7Ph27Fq.png"></a> <a href="https://www.netlify.com" target="_blank"><img height="40px" src="https://i.imgur.com/cU01915.png"></a> <a href="https://1password.com" target="_blank"><img height="40px" src="https://i.imgur.com/a2XjflO.png"></a>
|
|
53
|
+
</div>
|
|
89
54
|
|
|
90
55
|
## Author
|
|
91
56
|
|
|
92
57
|
**RSSHub** © [DIYgod](https://github.com/DIYgod), Released under the [MIT](./LICENSE) License.<br>
|
|
93
58
|
Authored and maintained by DIYgod with help from contributors ([list](https://github.com/DIYgod/RSSHub/contributors)).
|
|
94
59
|
|
|
95
|
-
> Blog [@DIYgod](https://diygod.cc) · GitHub [@DIYgod](https://github.com/DIYgod) · Twitter [@DIYgod](https://x.com/DIYgod) · Telegram Channel [@awesomeDIYgod](https://t.me/awesomeDIYgod)
|
|
60
|
+
> Blog [@DIYgod](https://diygod.cc) · GitHub [@DIYgod](https://github.com/DIYgod) · X (Twitter) [@DIYgod](https://x.com/DIYgod) · Telegram Channel [@awesomeDIYgod](https://t.me/awesomeDIYgod)
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { namespaces } from '@/registry';
|
|
2
2
|
import { parse } from 'tldts';
|
|
3
|
-
import {
|
|
3
|
+
import { RadarDomain } from '@/types';
|
|
4
4
|
import { createRoute, RouteHandler } from '@hono/zod-openapi';
|
|
5
5
|
|
|
6
6
|
const radar: {
|
|
7
|
-
[domain: string]:
|
|
8
|
-
_name: string;
|
|
9
|
-
[subdomain: string]: RadarItem[] | string;
|
|
10
|
-
};
|
|
7
|
+
[domain: string]: RadarDomain;
|
|
11
8
|
} = {};
|
|
12
9
|
|
|
13
10
|
for (const namespace in namespaces) {
|
|
@@ -23,7 +20,7 @@ for (const namespace in namespaces) {
|
|
|
23
20
|
if (!radar[domain]) {
|
|
24
21
|
radar[domain] = {
|
|
25
22
|
_name: namespaces[namespace].name,
|
|
26
|
-
};
|
|
23
|
+
} as RadarDomain;
|
|
27
24
|
}
|
|
28
25
|
if (!radar[domain][subdomain]) {
|
|
29
26
|
radar[domain][subdomain] = [];
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { namespaces } from '@/registry';
|
|
2
2
|
import { parse } from 'tldts';
|
|
3
|
-
import {
|
|
3
|
+
import { RadarDomain } from '@/types';
|
|
4
4
|
import { z, createRoute, RouteHandler } from '@hono/zod-openapi';
|
|
5
5
|
|
|
6
6
|
const radar: {
|
|
7
|
-
[domain: string]:
|
|
8
|
-
_name: string;
|
|
9
|
-
[subdomain: string]: RadarItem[] | string;
|
|
10
|
-
};
|
|
7
|
+
[domain: string]: RadarDomain;
|
|
11
8
|
} = {};
|
|
12
9
|
|
|
13
10
|
for (const namespace in namespaces) {
|
|
@@ -23,7 +20,7 @@ for (const namespace in namespaces) {
|
|
|
23
20
|
if (!radar[domain]) {
|
|
24
21
|
radar[domain] = {
|
|
25
22
|
_name: namespaces[namespace].name,
|
|
26
|
-
};
|
|
23
|
+
} as RadarDomain;
|
|
27
24
|
}
|
|
28
25
|
if (!radar[domain][subdomain]) {
|
|
29
26
|
radar[domain][subdomain] = [];
|
package/lib/config.ts
CHANGED
|
@@ -47,6 +47,10 @@ export type Config = {
|
|
|
47
47
|
debugInfo: string;
|
|
48
48
|
loggerLevel: string;
|
|
49
49
|
noLogfiles?: boolean;
|
|
50
|
+
otel: {
|
|
51
|
+
seconds_bucket?: string;
|
|
52
|
+
milliseconds_bucket?: string;
|
|
53
|
+
};
|
|
50
54
|
showLoggerTimestamp?: boolean;
|
|
51
55
|
sentry: {
|
|
52
56
|
dsn?: string;
|
|
@@ -70,7 +74,9 @@ export type Config = {
|
|
|
70
74
|
temperature?: number;
|
|
71
75
|
maxTokens?: number;
|
|
72
76
|
endpoint: string;
|
|
73
|
-
|
|
77
|
+
inputOption: string;
|
|
78
|
+
promptTitle: string;
|
|
79
|
+
promptDescription: string;
|
|
74
80
|
};
|
|
75
81
|
bilibili: {
|
|
76
82
|
cookies: Record<string, string | undefined>;
|
|
@@ -168,12 +174,20 @@ export type Config = {
|
|
|
168
174
|
javdb: {
|
|
169
175
|
session?: string;
|
|
170
176
|
};
|
|
177
|
+
keylol: {
|
|
178
|
+
cookie?: string;
|
|
179
|
+
};
|
|
171
180
|
lastfm: {
|
|
172
181
|
api_key?: string;
|
|
173
182
|
};
|
|
174
183
|
lightnovel: {
|
|
175
184
|
cookie?: string;
|
|
176
185
|
};
|
|
186
|
+
malaysiakini: {
|
|
187
|
+
email?: string;
|
|
188
|
+
password?: string;
|
|
189
|
+
refreshToken?: string;
|
|
190
|
+
};
|
|
177
191
|
manhuagui: {
|
|
178
192
|
cookie?: string;
|
|
179
193
|
};
|
|
@@ -409,6 +423,10 @@ const calculateValue = () => {
|
|
|
409
423
|
debugInfo: envs.DEBUG_INFO || 'true',
|
|
410
424
|
loggerLevel: envs.LOGGER_LEVEL || 'info',
|
|
411
425
|
noLogfiles: toBoolean(envs.NO_LOGFILES, false),
|
|
426
|
+
otel: {
|
|
427
|
+
seconds_bucket: envs.OTEL_SECONDS_BUCKET || '0.01,0.1,1,2,5,15,30,60',
|
|
428
|
+
milliseconds_bucket: envs.OTEL_MILLISECONDS_BUCKET || '10,20,50,100,250,500,1000,5000,15000',
|
|
429
|
+
},
|
|
412
430
|
showLoggerTimestamp: toBoolean(envs.SHOW_LOGGER_TIMESTAMP, false),
|
|
413
431
|
sentry: {
|
|
414
432
|
dsn: envs.SENTRY,
|
|
@@ -433,7 +451,9 @@ const calculateValue = () => {
|
|
|
433
451
|
temperature: toInt(envs.OPENAI_TEMPERATURE, 0.2),
|
|
434
452
|
maxTokens: toInt(envs.OPENAI_MAX_TOKENS, 0) || undefined,
|
|
435
453
|
endpoint: envs.OPENAI_API_ENDPOINT || 'https://api.openai.com/v1',
|
|
436
|
-
|
|
454
|
+
inputOption: envs.OPENAI_INPUT_OPTION || 'description',
|
|
455
|
+
promptDescription: envs.OPENAI_PROMPT || 'Please summarize the following article and reply with markdown format.',
|
|
456
|
+
promptTitle: envs.OPENAI_PROMPT_TITLE || 'Please translate the following title into Simplified Chinese and reply only translated text.',
|
|
437
457
|
},
|
|
438
458
|
|
|
439
459
|
// Route-specific Configurations
|
|
@@ -534,12 +554,20 @@ const calculateValue = () => {
|
|
|
534
554
|
javdb: {
|
|
535
555
|
session: envs.JAVDB_SESSION,
|
|
536
556
|
},
|
|
557
|
+
keylol: {
|
|
558
|
+
cookie: envs.KEYLOL_COOKIE,
|
|
559
|
+
},
|
|
537
560
|
lastfm: {
|
|
538
561
|
api_key: envs.LASTFM_API_KEY,
|
|
539
562
|
},
|
|
540
563
|
lightnovel: {
|
|
541
564
|
cookie: envs.SECURITY_KEY,
|
|
542
565
|
},
|
|
566
|
+
malaysiakini: {
|
|
567
|
+
email: envs.MALAYSIAKINI_EMAIL,
|
|
568
|
+
password: envs.MALAYSIAKINI_PASSWORD,
|
|
569
|
+
refreshToken: envs.MALAYSIAKINI_REFRESHTOKEN,
|
|
570
|
+
},
|
|
543
571
|
manhuagui: {
|
|
544
572
|
cookie: envs.MHGUI_COOKIE,
|
|
545
573
|
},
|
|
@@ -713,26 +741,6 @@ calculateValue();
|
|
|
713
741
|
logger.error('Remote config load failed.', error);
|
|
714
742
|
}
|
|
715
743
|
}
|
|
716
|
-
|
|
717
|
-
if (!envs.DISABLE_UMAMI && envs.NODE_ENV === 'production') {
|
|
718
|
-
ofetch(`https://umami.rss3.io/api/send`, {
|
|
719
|
-
method: 'POST',
|
|
720
|
-
headers: {
|
|
721
|
-
'content-type': 'application/json',
|
|
722
|
-
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
|
|
723
|
-
},
|
|
724
|
-
body: JSON.stringify({
|
|
725
|
-
payload: {
|
|
726
|
-
hostname: 'rsshub.app',
|
|
727
|
-
language: 'en-US',
|
|
728
|
-
referrer: 'rsshub.app',
|
|
729
|
-
url: 'rsshub.app',
|
|
730
|
-
website: '239067cd-231f-4a3f-a478-cced11a84876',
|
|
731
|
-
},
|
|
732
|
-
type: 'event',
|
|
733
|
-
}),
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
744
|
})();
|
|
737
745
|
|
|
738
746
|
// @ts-expect-error value is set
|
package/lib/errors/index.test.ts
CHANGED
|
@@ -22,7 +22,7 @@ describe('httperror', () => {
|
|
|
22
22
|
it(`httperror`, async () => {
|
|
23
23
|
const response = await request.get('/test/httperror');
|
|
24
24
|
expect(response.status).toBe(503);
|
|
25
|
-
expect(response.text).
|
|
25
|
+
expect(response.text).toContain('FetchError: [GET] "https://httpbingo.org/status/404": 404 Not Found');
|
|
26
26
|
}, 20000);
|
|
27
27
|
});
|
|
28
28
|
|
package/lib/errors/index.tsx
CHANGED
|
@@ -67,9 +67,9 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
|
|
|
67
67
|
const message = `${error.name}: ${errorMessage}`;
|
|
68
68
|
|
|
69
69
|
logger.error(`Error in ${requestPath}: ${message}`);
|
|
70
|
-
requestMetric.error({ path:
|
|
70
|
+
requestMetric.error({ path: matchedRoute, method: ctx.req.method, status: ctx.res.status });
|
|
71
71
|
|
|
72
|
-
return config.isPackage
|
|
72
|
+
return config.isPackage || ctx.req.query('format') === 'json'
|
|
73
73
|
? ctx.json({
|
|
74
74
|
error: {
|
|
75
75
|
message: error.message ?? error,
|
package/lib/index.ts
CHANGED
|
@@ -116,6 +116,148 @@ const expects = {
|
|
|
116
116
|
desc: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
|
|
117
117
|
},
|
|
118
118
|
},
|
|
119
|
+
extraComplicated: {
|
|
120
|
+
origin: {
|
|
121
|
+
items: [
|
|
122
|
+
{
|
|
123
|
+
content:
|
|
124
|
+
'<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n\n<a href="http://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">\n<img data-src="/DIYgod/RSSHub.jpg" src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img data-mock="/DIYgod/RSSHub.png" src="https://mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">\n<img mock="/DIYgod/RSSHub.gif" src="https://mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">\n<img src="http://mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
|
|
125
|
+
itunes: {},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
content: '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">',
|
|
129
|
+
itunes: {},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
content:
|
|
133
|
+
'<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
|
|
134
|
+
enclosure: {
|
|
135
|
+
url: 'https://mock.com/DIYgod/RSSHub.png',
|
|
136
|
+
type: 'image/png',
|
|
137
|
+
},
|
|
138
|
+
itunes: {
|
|
139
|
+
image: 'https://mock.com/DIYgod/RSSHub.gif',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
image: {
|
|
144
|
+
link: 'https://github.com/DIYgod/RSSHub',
|
|
145
|
+
url: 'https://mock.com/DIYgod/RSSHub.png',
|
|
146
|
+
title: 'Test complicated',
|
|
147
|
+
},
|
|
148
|
+
description: '<img src="http://mock.com/DIYgod/DIYgod/RSSHub"> - Powered by RSSHub',
|
|
149
|
+
},
|
|
150
|
+
processed: {
|
|
151
|
+
items: [
|
|
152
|
+
{
|
|
153
|
+
content:
|
|
154
|
+
'<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n\n<a href="http://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">\n<img data-src="/DIYgod/RSSHub.jpg" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img data-mock="/DIYgod/RSSHub.png" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">\n<img mock="/DIYgod/RSSHub.gif" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">\n<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
|
|
155
|
+
itunes: {},
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
content: '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">',
|
|
159
|
+
itunes: {},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
content:
|
|
163
|
+
'<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
|
|
164
|
+
enclosure: {
|
|
165
|
+
url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.png',
|
|
166
|
+
type: 'image/png',
|
|
167
|
+
},
|
|
168
|
+
itunes: {
|
|
169
|
+
image: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.gif',
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
image: {
|
|
174
|
+
link: 'https://github.com/DIYgod/RSSHub',
|
|
175
|
+
url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.png',
|
|
176
|
+
title: 'Test complicated',
|
|
177
|
+
},
|
|
178
|
+
description: '<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"> - Powered by RSSHub',
|
|
179
|
+
},
|
|
180
|
+
urlencoded: {
|
|
181
|
+
items: [
|
|
182
|
+
{
|
|
183
|
+
content:
|
|
184
|
+
'<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n\n<a href="http://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">\n<img data-src="/DIYgod/RSSHub.jpg" src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n<img data-mock="/DIYgod/RSSHub.png" src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.png" referrerpolicy="no-referrer">\n<img mock="/DIYgod/RSSHub.gif" src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.gif" referrerpolicy="no-referrer">\n<img src="https://images.weserv.nl?url=http%3A%2F%2Fmock.com%2FDIYgod%2FDIYgod%2FRSSHub" referrerpolicy="no-referrer">\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
|
|
185
|
+
itunes: {},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
content: '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">',
|
|
189
|
+
itunes: {},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
content:
|
|
193
|
+
'<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
|
|
194
|
+
enclosure: {
|
|
195
|
+
url: 'https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.png',
|
|
196
|
+
type: 'image/png',
|
|
197
|
+
},
|
|
198
|
+
itunes: {
|
|
199
|
+
image: 'https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.gif',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
image: {
|
|
204
|
+
link: 'https://github.com/DIYgod/RSSHub',
|
|
205
|
+
url: 'https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.png',
|
|
206
|
+
title: 'Test complicated',
|
|
207
|
+
},
|
|
208
|
+
description: '<img src="https://images.weserv.nl?url=http%3A%2F%2Fmock.com%2FDIYgod%2FDIYgod%2FRSSHub"> - Powered by RSSHub',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
extraMultimedia: {
|
|
212
|
+
origin: {
|
|
213
|
+
items: [
|
|
214
|
+
{
|
|
215
|
+
content:
|
|
216
|
+
'<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://mock.com/DIYgod/RSSHub.mp4"></video>\n<video poster="https://mock.com/DIYgod/RSSHub.jpg">\n<source src="https://mock.com/DIYgod/RSSHub.mp4" type="video/mp4">\n<source src="https://mock.com/DIYgod/RSSHub.webm" type="video/webm">\n</video>\n<audio src="https://mock.com/DIYgod/RSSHub.mp3"></audio>\n<iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>',
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
content: '<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://mock.com/DIYgod/RSSHub.mp4"></video>',
|
|
220
|
+
enclosure: {
|
|
221
|
+
url: 'https://mock.com/DIYgod/RSSHub.mp4',
|
|
222
|
+
type: 'video/mp4',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
description: '<video src="http://mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
|
|
227
|
+
},
|
|
228
|
+
relayed: {
|
|
229
|
+
items: [
|
|
230
|
+
{
|
|
231
|
+
content:
|
|
232
|
+
'<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>\n<video poster="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4" type="video/mp4">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.webm" type="video/webm">\n</video>\n<audio src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp3"></audio>\n<iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>',
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
content: '<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>',
|
|
236
|
+
enclosure: {
|
|
237
|
+
url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4',
|
|
238
|
+
type: 'video/mp4',
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
description: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
|
|
243
|
+
},
|
|
244
|
+
partlyRelayed: {
|
|
245
|
+
items: [
|
|
246
|
+
{
|
|
247
|
+
content:
|
|
248
|
+
'<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>\n<video poster="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4" type="video/mp4">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.webm" type="video/webm">\n</video>\n<audio src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp3"></audio>\n<iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>',
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
content: '<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>',
|
|
252
|
+
enclosure: {
|
|
253
|
+
url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4',
|
|
254
|
+
type: 'video/mp4',
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
description: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
|
|
259
|
+
},
|
|
260
|
+
},
|
|
119
261
|
};
|
|
120
262
|
|
|
121
263
|
const testAntiHotlink = async (path, expectObj, query?: string | Record<string, any>) => {
|
|
@@ -142,12 +284,55 @@ const testAntiHotlink = async (path, expectObj, query?: string | Record<string,
|
|
|
142
284
|
return parsed;
|
|
143
285
|
};
|
|
144
286
|
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
287
|
+
const testAntiHotlinkExtra = async (path, expectObj, query?: string | Record<string, any>) => {
|
|
288
|
+
const app = (await import('@/app')).default;
|
|
289
|
+
|
|
290
|
+
path += query ? `?${new URLSearchParams(query).toString()}` : '';
|
|
291
|
+
|
|
292
|
+
const response = await app.request(path);
|
|
293
|
+
const parsed = await parser.parseString(await response.text());
|
|
294
|
+
const obj = {
|
|
295
|
+
description: parsed.description,
|
|
296
|
+
image: parsed.image,
|
|
297
|
+
items: parsed.items.slice(0, expectObj.items.length).map((e) => ({
|
|
298
|
+
content: e.content,
|
|
299
|
+
enclosure: e.enclosure,
|
|
300
|
+
itunes: e.itunes,
|
|
301
|
+
})),
|
|
302
|
+
};
|
|
303
|
+
expect(obj).toEqual(expectObj);
|
|
304
|
+
|
|
305
|
+
return parsed;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const expectImgOrigin = async (query?: string | Record<string, any>) => {
|
|
309
|
+
await testAntiHotlink('/test/complicated', expects.complicated.origin, query);
|
|
310
|
+
await testAntiHotlinkExtra('/test/complicated', expects.extraComplicated.origin, query);
|
|
311
|
+
};
|
|
312
|
+
const expectImgProcessed = async (query?: string | Record<string, any>) => {
|
|
313
|
+
await testAntiHotlink('/test/complicated', expects.complicated.processed, query);
|
|
314
|
+
await testAntiHotlinkExtra('/test/complicated', expects.extraComplicated.processed, query);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const expectImgUrlencoded = async (query?: string | Record<string, any>) => {
|
|
318
|
+
await testAntiHotlink('/test/complicated', expects.complicated.urlencoded, query);
|
|
319
|
+
await testAntiHotlinkExtra('/test/complicated', expects.extraComplicated.urlencoded, query);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const expectMultimediaOrigin = async (query?: string | Record<string, any>) => {
|
|
323
|
+
await testAntiHotlink('/test/multimedia', expects.multimedia.origin, query);
|
|
324
|
+
await testAntiHotlinkExtra('/test/multimedia', expects.extraMultimedia.origin, query);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const expectMultimediaRelayed = async (query?: string | Record<string, any>) => {
|
|
328
|
+
await testAntiHotlink('/test/multimedia', expects.multimedia.relayed, query);
|
|
329
|
+
await testAntiHotlinkExtra('/test/multimedia', expects.extraMultimedia.relayed, query);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const expectMultimediaPartlyRelayed = async (query?: string | Record<string, any>) => {
|
|
333
|
+
await testAntiHotlink('/test/multimedia', expects.multimedia.partlyRelayed, query);
|
|
334
|
+
await testAntiHotlinkExtra('/test/multimedia', expects.extraMultimedia.partlyRelayed, query);
|
|
335
|
+
};
|
|
151
336
|
|
|
152
337
|
describe('anti-hotlink', () => {
|
|
153
338
|
it('template-legacy', async () => {
|
|
@@ -44,6 +44,18 @@ const parseUrl = (str: string) => {
|
|
|
44
44
|
|
|
45
45
|
return url;
|
|
46
46
|
};
|
|
47
|
+
|
|
48
|
+
const replaceUrl = (template?: string, url?: string) => {
|
|
49
|
+
if (!template || !url) {
|
|
50
|
+
return url;
|
|
51
|
+
}
|
|
52
|
+
const oldUrl = parseUrl(url);
|
|
53
|
+
if (oldUrl && oldUrl.protocol !== 'data:') {
|
|
54
|
+
return interpolate(template, oldUrl);
|
|
55
|
+
}
|
|
56
|
+
return url;
|
|
57
|
+
};
|
|
58
|
+
|
|
47
59
|
const replaceUrls = ($: CheerioAPI, selector: string, template: string, attribute = 'src') => {
|
|
48
60
|
$(selector).each(function () {
|
|
49
61
|
const oldSrc = $(this).attr(attribute);
|
|
@@ -120,6 +132,9 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|
|
120
132
|
// image link
|
|
121
133
|
const data: Data = ctx.get('data');
|
|
122
134
|
if (data) {
|
|
135
|
+
if (data.image) {
|
|
136
|
+
data.image = replaceUrl(imageHotlinkTemplate, data.image);
|
|
137
|
+
}
|
|
123
138
|
if (data.description) {
|
|
124
139
|
data.description = process(data.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
|
|
125
140
|
}
|
|
@@ -129,6 +144,19 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|
|
129
144
|
if (item.description) {
|
|
130
145
|
item.description = process(item.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
|
|
131
146
|
}
|
|
147
|
+
if (item.enclosure_url && item.enclosure_type) {
|
|
148
|
+
if (item.enclosure_type.startsWith('image/')) {
|
|
149
|
+
item.enclosure_url = replaceUrl(imageHotlinkTemplate, item.enclosure_url);
|
|
150
|
+
} else if (/^(video|audio)\//.test(item.enclosure_type)) {
|
|
151
|
+
item.enclosure_url = replaceUrl(multimediaHotlinkTemplate, item.enclosure_url);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (item.image) {
|
|
155
|
+
item.image = replaceUrl(imageHotlinkTemplate, item.image);
|
|
156
|
+
}
|
|
157
|
+
if (item.itunes_item_image) {
|
|
158
|
+
item.itunes_item_image = replaceUrl(imageHotlinkTemplate, item.itunes_item_image);
|
|
159
|
+
}
|
|
132
160
|
}
|
|
133
161
|
}
|
|
134
162
|
|
package/lib/middleware/logger.ts
CHANGED
|
@@ -26,7 +26,7 @@ const colorStatus = (status: number) => {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
const middleware: MiddlewareHandler = async (ctx, next) => {
|
|
29
|
-
const { method, raw } = ctx.req;
|
|
29
|
+
const { method, raw, routePath } = ctx.req;
|
|
30
30
|
const path = getPath(raw);
|
|
31
31
|
|
|
32
32
|
logger.info(`${LogPrefix.Incoming} ${method} ${path}`);
|
|
@@ -38,7 +38,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|
|
38
38
|
const status = ctx.res.status;
|
|
39
39
|
|
|
40
40
|
logger.info(`${LogPrefix.Outgoing} ${method} ${path} ${colorStatus(status)} ${time(start)}`);
|
|
41
|
-
requestMetric.success(Date.now() - start, { path, method, status });
|
|
41
|
+
requestMetric.success(Date.now() - start, { path: routePath, method, status });
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
export default middleware;
|
|
@@ -427,7 +427,8 @@ describe('multi parameter', () => {
|
|
|
427
427
|
});
|
|
428
428
|
|
|
429
429
|
describe('openai', () => {
|
|
430
|
-
it(
|
|
430
|
+
it('processes both title and description', async () => {
|
|
431
|
+
config.openai.inputOption = 'both';
|
|
431
432
|
const responseWithGpt = await app.request('/test/gpt?chatgpt=true');
|
|
432
433
|
const responseNormal = await app.request('/test/gpt');
|
|
433
434
|
|
|
@@ -437,9 +438,25 @@ describe('openai', () => {
|
|
|
437
438
|
const parsedGpt = await parser.parseString(await responseWithGpt.text());
|
|
438
439
|
const parsedNormal = await parser.parseString(await responseNormal.text());
|
|
439
440
|
|
|
440
|
-
expect(parsedGpt.items[0].
|
|
441
|
-
expect(parsedGpt.items[0].
|
|
442
|
-
expect(parsedGpt.items[
|
|
443
|
-
expect(parsedGpt.items[
|
|
441
|
+
expect(parsedGpt.items[0].title).not.toBe(parsedNormal.items[0].title);
|
|
442
|
+
expect(parsedGpt.items[0].title).toContain('AI processed content.');
|
|
443
|
+
expect(parsedGpt.items[0].content).not.toBe(parsedNormal.items[0].content);
|
|
444
|
+
expect(parsedGpt.items[0].content).toContain('AI processed content.');
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('processes title or description', async () => {
|
|
448
|
+
// test title
|
|
449
|
+
config.openai.inputOption = 'title';
|
|
450
|
+
const responseTitleOnly = await app.request('/test/gpt?chatgpt=true');
|
|
451
|
+
const parsedTitleOnly = await parser.parseString(await responseTitleOnly.text());
|
|
452
|
+
expect(parsedTitleOnly.items[0].title).toContain('AI processed content.');
|
|
453
|
+
expect(parsedTitleOnly.items[0].content).not.toContain('AI processed content.');
|
|
454
|
+
|
|
455
|
+
// test description
|
|
456
|
+
config.openai.inputOption = 'description';
|
|
457
|
+
const responseDescriptionOnly = await app.request('/test/gpt?chatgpt=true');
|
|
458
|
+
const parsedDescriptionOnly = await parser.parseString(await responseDescriptionOnly.text());
|
|
459
|
+
expect(parsedDescriptionOnly.items[0].title).not.toContain('AI processed content.');
|
|
460
|
+
expect(parsedDescriptionOnly.items[0].content).toContain('AI processed content.');
|
|
444
461
|
});
|
|
445
462
|
});
|