rsshub 1.0.0-master.f9003f9 → 1.0.0-master.f917bdc
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 +1 -0
- package/lib/api/category/one.ts +54 -0
- package/lib/api/index.ts +10 -4
- package/lib/app.tsx +2 -0
- package/lib/config.ts +43 -17
- package/lib/errors/index.test.ts +9 -5
- package/lib/errors/index.tsx +11 -4
- package/lib/index.ts +5 -2
- package/lib/middleware/anti-hotlink.test.ts +6 -6
- package/lib/middleware/cache.ts +21 -6
- package/lib/middleware/logger.ts +5 -1
- package/lib/middleware/template.tsx +15 -11
- package/lib/middleware/trace.ts +25 -0
- package/lib/registry.test.ts +8 -0
- package/lib/registry.ts +10 -2
- package/lib/router.js +0 -9
- package/lib/routes/141jav/index.ts +25 -21
- package/lib/routes/141ppv/index.ts +24 -20
- package/lib/routes/2048/index.ts +13 -10
- package/lib/routes/3dmgame/news-center.ts +1 -1
- package/lib/routes/51read/article.ts +82 -0
- package/lib/routes/51read/namespace.ts +6 -0
- package/lib/routes/69shu/article.ts +8 -8
- package/lib/routes/69shu/namespace.ts +1 -1
- package/lib/routes/academia/namespace.ts +6 -0
- package/lib/routes/academia/topics.ts +49 -0
- package/lib/routes/alistapart/utils.ts +2 -2
- package/lib/routes/aljazeera/index.ts +2 -2
- package/lib/routes/alpinelinux/namespace.ts +11 -0
- package/lib/routes/alpinelinux/pkgs.ts +104 -0
- package/lib/routes/apnews/rss.ts +10 -4
- package/lib/routes/apnews/topics.ts +11 -5
- package/lib/routes/apnews/utils.ts +36 -12
- package/lib/routes/apple/apps.ts +30 -8
- package/lib/routes/asmr-200/index.ts +66 -0
- package/lib/routes/asmr-200/namespace.ts +6 -0
- package/lib/routes/asmr-200/templates/work.art +7 -0
- package/lib/routes/asmr-200/type.ts +96 -0
- package/lib/routes/autocentre/index.ts +29 -0
- package/lib/routes/autocentre/namespace.ts +7 -0
- package/lib/routes/bbc/index.ts +3 -1
- package/lib/routes/bc3ts/list.ts +72 -0
- package/lib/routes/bc3ts/namespace.ts +7 -0
- package/lib/routes/bc3ts/templates/media.art +10 -0
- package/lib/routes/bc3ts/types.ts +118 -0
- package/lib/routes/beijingprice/index.ts +193 -0
- package/lib/routes/beijingprice/namespace.ts +8 -0
- package/lib/routes/bilibili/api-interface.d.ts +1 -0
- package/lib/routes/bilibili/dynamic.ts +35 -18
- package/lib/routes/bilibili/namespace.ts +1 -1
- package/lib/routes/bilibili/ranking.ts +99 -8
- package/lib/routes/bilibili/video.ts +3 -5
- package/lib/routes/bing/daily-wallpaper.ts +57 -18
- 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/bjx/fd.ts +63 -0
- package/lib/routes/bjx/namespace.ts +1 -1
- package/lib/routes/bluearchive/namespace.ts +7 -0
- package/lib/routes/bluearchive/news.ts +88 -0
- package/lib/routes/bt0/mv.ts +65 -0
- package/lib/routes/bt0/namespace.ts +9 -0
- package/lib/routes/bt0/tlist.ts +67 -0
- package/lib/routes/bt0/util.ts +51 -0
- package/lib/routes/buaa/jiaowu.ts +124 -0
- package/lib/routes/buaa/lib/space/newbook.ts +171 -0
- package/lib/routes/buaa/lib/space/templates/newbook.art +44 -0
- package/lib/routes/buaa/news/index.ts +15 -13
- package/lib/routes/buaa/sme.ts +5 -3
- package/lib/routes/bugzilla/bug.ts +59 -0
- package/lib/routes/bugzilla/namespace.ts +11 -0
- package/lib/routes/cara/constant.ts +5 -0
- package/lib/routes/cara/likes.ts +56 -0
- package/lib/routes/cara/namespace.ts +6 -0
- package/lib/routes/cara/portfolio.ts +40 -0
- package/lib/routes/cara/templates/post.art +6 -0
- package/lib/routes/cara/timeline.ts +56 -0
- package/lib/routes/cara/types.ts +45 -0
- package/lib/routes/cara/utils.ts +62 -0
- package/lib/routes/cbaigui/utils.ts +1 -1
- package/lib/routes/cccfna/index.ts +82 -0
- package/lib/routes/cccfna/namespace.ts +6 -0
- package/lib/routes/cffex/announcement.ts +73 -0
- package/lib/routes/cffex/namespace.ts +6 -0
- package/lib/routes/cfr/index.ts +58 -0
- package/lib/routes/cfr/namespace.ts +6 -0
- package/lib/routes/cfr/types.ts +30 -0
- package/lib/routes/cfr/utils.ts +284 -0
- package/lib/routes/chaping/newsflash.ts +2 -2
- package/lib/routes/chlinlearn/daily-blog.ts +48 -0
- package/lib/routes/chlinlearn/namespcae.ts +6 -0
- package/lib/routes/cnbc/rss.ts +1 -1
- package/lib/routes/codeforces/contests.ts +2 -2
- package/lib/routes/codeforces/recent-actions.ts +2 -2
- package/lib/routes/copymanga/comic.ts +3 -1
- package/lib/routes/dangdang/namespace.ts +6 -0
- package/lib/routes/dangdang/notice.ts +69 -0
- package/lib/routes/dataguidance/index.ts +66 -0
- package/lib/routes/dataguidance/namespace.ts +7 -0
- package/lib/routes/dblp/publication.ts +4 -6
- package/lib/routes/deadbydaylight/index.ts +69 -0
- package/lib/routes/deadbydaylight/namespace.ts +12 -0
- package/lib/routes/devolverdigital/blog.ts +59 -42
- package/lib/routes/dewu/declaration.ts +86 -0
- package/lib/routes/dewu/namespace.ts +6 -0
- package/lib/routes/dhu/jiaowu/news.ts +53 -24
- package/lib/routes/dhu/namespace.ts +1 -1
- package/lib/routes/dhu/xxgk/news.ts +48 -20
- 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 +4 -2
- package/lib/routes/dlnews/utils.ts +2 -2
- package/lib/routes/dockerhub/build.ts +11 -6
- package/lib/routes/domp4/detail.ts +1 -1
- package/lib/routes/domp4/latest-movie-bt.ts +71 -0
- package/lib/routes/dongqiudi/result.ts +1 -1
- package/lib/routes/douban/other/group.ts +24 -3
- package/lib/routes/duckdb/namespace.ts +6 -0
- package/lib/routes/duckdb/news.ts +65 -0
- package/lib/routes/dushu/fuzhou/index.ts +10 -11
- package/lib/routes/epicgames/index.ts +14 -4
- package/lib/routes/famitsu/category.ts +110 -43
- package/lib/routes/famitsu/templates/description.art +7 -0
- package/lib/routes/famitsu/types.ts +117 -0
- package/lib/routes/fanbox/namespace.ts +1 -1
- package/lib/routes/fanqienovel/namespace.ts +7 -0
- package/lib/routes/fanqienovel/page.ts +100 -0
- package/lib/routes/fansly/post.ts +1 -2
- package/lib/routes/fansly/tag.ts +1 -2
- package/lib/routes/fansly/utils.ts +5 -4
- package/lib/routes/fashionnetwork/index.ts +192 -0
- package/lib/routes/fashionnetwork/namespace.ts +8 -0
- package/lib/routes/fashionnetwork/templates/description.art +17 -0
- package/lib/routes/fediverse/namespace.ts +6 -0
- package/lib/routes/fediverse/timeline.ts +98 -0
- package/lib/routes/finviz/news.ts +4 -4
- package/lib/routes/foresightnews/util.ts +1 -1
- package/lib/routes/fortunechina/index.ts +24 -14
- package/lib/routes/freebuf/index.ts +3 -3
- package/lib/routes/ftchinese/channel.ts +3 -3
- package/lib/routes/gdut/oa-news.ts +12 -17
- package/lib/routes/getitfree/util.ts +1 -1
- package/lib/routes/github/activity.ts +55 -0
- package/lib/routes/github/issue.ts +26 -3
- package/lib/routes/github/search.ts +20 -18
- package/lib/routes/github/star.ts +4 -3
- package/lib/routes/github/trending.ts +27 -5
- package/lib/routes/google/citations.ts +2 -2
- package/lib/routes/google/research.ts +45 -0
- package/lib/routes/google/scholar.ts +2 -2
- package/lib/routes/gov/beijing/bphc/index.ts +3 -3
- package/lib/routes/gov/immiau/news.ts +2 -2
- package/lib/routes/gov/sh/fgw/index.ts +155 -0
- package/lib/routes/gov/sh/fgw/templates/description.art +17 -0
- package/lib/routes/gov/sh/namespace.ts +8 -0
- package/lib/routes/gov/{shanghai → sh}/rsj/ksxm.ts +2 -2
- package/lib/routes/gov/{shanghai → sh}/wgj/wgj.ts +3 -3
- package/lib/routes/gov/{shanghai → sh}/wsjkw/yqtb/index.ts +2 -2
- package/lib/routes/gov/{shanghai → sh}/yjj/index.ts +3 -3
- package/lib/routes/gov/stats/index.ts +8 -8
- package/lib/routes/gov/zhengce/index.ts +3 -6
- 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/grist/utils.ts +2 -2
- package/lib/routes/guokr/utils.ts +1 -1
- package/lib/routes/healthz.ts +8 -0
- package/lib/routes/hitcon/zeroday.ts +1 -1
- package/lib/routes/hket/index.ts +80 -76
- package/lib/routes/hrbeu/job/calendar.ts +8 -6
- package/lib/routes/huxiu/util.ts +2 -2
- package/lib/routes/hypergryph/arknights/arktca.ts +124 -0
- package/lib/routes/ieee/journal.ts +50 -67
- package/lib/routes/ieee/templates/description.art +1 -1
- package/lib/routes/imdb/chart.ts +61 -0
- package/lib/routes/imdb/namespace.ts +6 -0
- package/lib/routes/imdb/templates/chart.art +15 -0
- package/lib/routes/imdb/types.ts +103 -0
- package/lib/routes/imop/namespace.ts +10 -0
- package/lib/routes/imop/tianshu.ts +53 -0
- package/lib/routes/informedainews/docs.ts +78 -0
- package/lib/routes/informedainews/namespace.ts +18 -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/instagram/private-api/index.ts +28 -6
- package/lib/routes/investor/index.ts +213 -0
- package/lib/routes/investor/namespace.ts +8 -0
- package/lib/routes/iplaysoft/index.ts +68 -0
- package/lib/routes/iplaysoft/namespace.ts +6 -0
- package/lib/routes/j-test/namespace.ts +6 -0
- package/lib/routes/j-test/news.ts +64 -0
- package/lib/routes/japanpost/namespace.ts +7 -1
- package/lib/routes/japanpost/router.ts +40 -0
- package/lib/routes/japanpost/track.ts +1 -23
- package/lib/routes/javbus/index.ts +8 -1
- package/lib/routes/javdb/actors.ts +6 -2
- package/lib/routes/javdb/index.ts +4 -3
- package/lib/routes/javdb/series.ts +1 -1
- package/lib/routes/javdb/utils.ts +6 -0
- package/lib/routes/javdb/videocodes.ts +56 -0
- package/lib/routes/jike/topic.ts +1 -1
- package/lib/routes/jike/user.ts +1 -1
- package/lib/routes/jingzhengu/namespace.ts +6 -0
- package/lib/routes/jingzhengu/news.ts +77 -0
- package/lib/routes/jingzhengu/types.ts +39 -0
- package/lib/routes/jingzhengu/utils.ts +35 -0
- package/lib/routes/jinritemai/docs.ts +74 -0
- package/lib/routes/jinritemai/namespace.ts +6 -0
- package/lib/routes/jiuyangongshe/community.ts +147 -0
- package/lib/routes/jiuyangongshe/namespace.ts +7 -0
- package/lib/routes/jiuyangongshe/templates/community-description.art +4 -0
- package/lib/routes/jjwxc/book.ts +4 -3
- package/lib/routes/jlu/ccst/xwzx/index.ts +63 -0
- package/lib/routes/jlu/jwc.ts +55 -0
- package/lib/routes/jlu/namespace.ts +6 -0
- package/lib/routes/juejin/dynamic.ts +114 -0
- package/lib/routes/kadokawa/blog.ts +134 -0
- package/lib/routes/kadokawa/namespace.ts +8 -0
- package/lib/routes/kadokawa/templates/description.art +21 -0
- package/lib/routes/kaopu/news.ts +3 -3
- package/lib/routes/kelownacapnews/namespace.ts +6 -0
- package/lib/routes/kelownacapnews/news.ts +93 -0
- 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/kyodonews/index.ts +1 -1
- package/lib/routes/leetcode/articles.ts +19 -21
- package/lib/routes/line/today.ts +1 -1
- 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/user.ts +2 -1
- package/lib/routes/logclub/index.ts +1 -2
- package/lib/routes/luogu/user-blog.ts +6 -6
- package/lib/routes/luolei/index.ts +1 -2
- package/lib/routes/maccms/index.ts +72 -0
- package/lib/routes/maccms/namespace.ts +9 -0
- package/lib/routes/maccms/templates/vod.art +12 -0
- package/lib/routes/maccms/type.ts +102 -0
- package/lib/routes/mangadex/namespace.ts +1 -1
- package/lib/routes/manyvids/namespace.ts +7 -0
- package/lib/routes/manyvids/templates/video.art +3 -0
- package/lib/routes/manyvids/types.ts +89 -0
- package/lib/routes/manyvids/video.ts +51 -0
- package/lib/routes/matters/author.ts +63 -0
- package/lib/routes/matters/latest.ts +74 -0
- package/lib/routes/matters/namespace.ts +7 -0
- package/lib/routes/matters/tags.ts +85 -0
- package/lib/routes/matters/utils.ts +30 -0
- 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/meituan/namespace.ts +6 -0
- package/lib/routes/meituan/tech.ts +67 -0
- package/lib/routes/metacritic/index.ts +10 -0
- package/lib/routes/metrics.ts +12 -0
- package/lib/routes/microsoft/mcr.ts +63 -0
- package/lib/routes/microsoft/namespace.ts +2 -2
- package/lib/routes/mihoyo/bbs/img-ranking.ts +4 -4
- package/lib/routes/mihoyo/bbs/static-data.ts +7 -0
- package/lib/routes/minecraft/version.ts +1 -1
- package/lib/routes/mirrormedia/category.ts +101 -0
- package/lib/routes/mirrormedia/index.ts +43 -0
- package/lib/routes/mirrormedia/namespace.ts +6 -0
- package/lib/routes/mirrormedia/utils.ts +19 -0
- package/lib/routes/misskey/user-timeline.ts +42 -0
- package/lib/routes/misskey/utils.ts +41 -1
- package/lib/routes/modb/topic.ts +5 -6
- package/lib/routes/my-formosa/index.ts +78 -0
- package/lib/routes/my-formosa/namespace.ts +6 -0
- package/lib/routes/myfans/namespace.ts +6 -0
- package/lib/routes/myfans/post.ts +64 -0
- package/lib/routes/myfans/templates/post.art +8 -0
- package/lib/routes/myfans/types.ts +104 -0
- package/lib/routes/myfans/utils.ts +39 -0
- package/lib/routes/nasa/apod.ts +4 -3
- package/lib/routes/nasa/namespace.ts +1 -1
- package/lib/routes/nationalgeographic/latest-stories.ts +1 -1
- package/lib/routes/nationalgeographic/templates/stories.art +1 -1
- package/lib/routes/neea/index.ts +47 -19
- package/lib/routes/neea/jlpt.ts +12 -15
- package/lib/routes/neea/namespace.ts +2 -2
- package/lib/routes/newrank/utils.ts +1 -1
- package/lib/routes/newzmz/util.ts +1 -1
- package/lib/routes/nextjs/blog.ts +63 -0
- package/lib/routes/nextjs/namespace.ts +6 -0
- package/lib/routes/nga/forum.ts +3 -2
- package/lib/routes/nikkei/asia/index.ts +1 -10
- package/lib/routes/nikkei/cn/index.ts +39 -3
- package/lib/routes/nikkei/index.ts +5 -4
- package/lib/routes/nikkei/namespace.ts +1 -1
- package/lib/routes/nikkei/news.ts +2 -2
- package/lib/routes/nmc/weatheralarm.ts +1 -0
- package/lib/routes/notion/release.ts +81 -0
- package/lib/routes/npm/package.ts +15 -8
- package/lib/routes/nyaa/main.ts +2 -3
- package/lib/routes/nyaa/namespace.ts +10 -0
- package/lib/routes/ollama/blog.ts +39 -0
- package/lib/routes/ollama/models.ts +7 -4
- package/lib/routes/oschina/news.ts +6 -2
- package/lib/routes/people/index.ts +4 -2
- package/lib/routes/picnob/namespace.ts +1 -4
- package/lib/routes/picnob/user.ts +3 -2
- package/lib/routes/picuki/namespace.ts +1 -4
- package/lib/routes/picuki/profile.ts +11 -7
- package/lib/routes/pixiv/ranking.ts +73 -10
- package/lib/routes/pixiv/search.ts +58 -7
- package/lib/routes/pixiv/user.ts +3 -1
- package/lib/routes/pixiv/utils.ts +3 -3
- package/lib/routes/podwise/collections.ts +46 -0
- package/lib/routes/podwise/episodes.ts +119 -0
- package/lib/routes/podwise/namespace.ts +9 -0
- package/lib/routes/ps/monthly-games.ts +3 -2
- package/lib/routes/psyche/namespace.ts +6 -0
- package/lib/routes/psyche/templates/essay.art +3 -0
- package/lib/routes/psyche/templates/video.art +10 -0
- package/lib/routes/psyche/topic.ts +46 -0
- package/lib/routes/psyche/type.ts +53 -0
- package/lib/routes/psyche/utils.ts +107 -0
- package/lib/routes/pubscholar/explore.ts +62 -0
- package/lib/routes/pubscholar/namespace.ts +7 -0
- package/lib/routes/pubscholar/types.ts +41 -0
- package/lib/routes/pubscholar/utils.ts +44 -0
- package/lib/routes/pwc/sustainability.ts +53 -49
- package/lib/routes/qidian/chapter.ts +4 -3
- package/lib/routes/raycast/changelog.ts +54 -0
- package/lib/routes/raycast/namespace.ts +7 -0
- package/lib/routes/react/blog.ts +57 -0
- package/lib/routes/react/namespace.ts +6 -0
- package/lib/routes/readwise/list.ts +152 -0
- package/lib/routes/readwise/namespace.ts +6 -0
- package/lib/routes/reuters/common.ts +3 -2
- package/lib/routes/reuters/namespace.ts +1 -1
- package/lib/routes/rss3/index.ts +148 -0
- package/lib/routes/rss3/namespace.ts +7 -0
- package/lib/routes/rsshub/routes.ts +36 -14
- package/lib/routes/ruc/ai.ts +87 -0
- package/lib/routes/ruc/namespace.ts +5 -2
- package/lib/routes/samd/namespace.ts +6 -0
- package/lib/routes/samd/news.ts +74 -0
- package/lib/routes/sara/index.ts +1 -1
- package/lib/routes/sciencedirect/cf-email.ts +0 -1
- package/lib/routes/sehuatang/index.ts +33 -14
- package/lib/routes/sehuatang/user.ts +1 -1
- 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 +10 -8
- 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/sicau/jiaowu.ts +77 -0
- package/lib/routes/sicau/jk.ts +210 -0
- package/lib/routes/sicau/namespace.ts +1 -1
- package/lib/routes/sjtu/jwc.ts +4 -1
- package/lib/routes/sjtu/yzb/zkxx.ts +36 -16
- package/lib/routes/smzdm/keyword.ts +3 -2
- package/lib/routes/smzdm/ranking.ts +180 -46
- package/lib/routes/spotify/artist.ts +16 -18
- package/lib/routes/spotify/artists-top.ts +7 -8
- package/lib/routes/spotify/playlist.ts +10 -10
- package/lib/routes/spotify/saved.ts +7 -8
- package/lib/routes/spotify/show.ts +8 -9
- package/lib/routes/spotify/tracks-top.ts +7 -8
- package/lib/routes/spotify/utils.ts +22 -22
- package/lib/routes/springer/journal.ts +10 -12
- package/lib/routes/sspai/author.ts +8 -2
- package/lib/routes/sspai/column.ts +1 -1
- package/lib/routes/sspai/index.ts +10 -4
- package/lib/routes/sspai/matrix.ts +8 -2
- package/lib/routes/sspai/prime-community.ts +83 -0
- package/lib/routes/sspai/series-update.ts +1 -1
- package/lib/routes/sspai/tag.ts +8 -2
- package/lib/routes/sspai/topic.ts +8 -2
- package/lib/routes/sspai/topics.ts +1 -1
- package/lib/routes/steam/sharefile-changelog.ts +65 -0
- package/lib/routes/steam/templates/workshop-search-description.art +5 -0
- package/lib/routes/steam/workshop-search.ts +109 -0
- package/lib/routes/stockedge/utils.ts +9 -11
- package/lib/routes/stream-capital/namespace.ts +6 -0
- package/lib/routes/stream-capital/search.ts +79 -0
- package/lib/routes/stream-capital/types.ts +44 -0
- package/lib/routes/stream-capital/utils.ts +18 -0
- package/lib/routes/sustainabilitymag/articles.ts +144 -0
- package/lib/routes/sustainabilitymag/namespace.ts +6 -0
- package/lib/routes/t66y/index.ts +29 -7
- package/lib/routes/techcrunch/news.ts +20 -29
- package/lib/routes/techcrunch/templates/description.art +7 -0
- package/lib/routes/telecompaper/news.ts +1 -1
- package/lib/routes/telegram/channel.ts +37 -31
- package/lib/routes/tencent/cloud/developer/column.ts +81 -0
- package/lib/routes/tencent/namespace.ts +2 -2
- package/lib/routes/tesla/cx.ts +1 -1
- package/lib/routes/test/index.ts +5 -1
- package/lib/routes/test/namespace.ts +1 -1
- package/lib/routes/the/index.ts +210 -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/theinitium/channel.ts +1 -1
- package/lib/routes/theinitium/follow.ts +1 -6
- package/lib/routes/theinitium/utils.ts +2 -18
- package/lib/routes/thoughtworks/index.ts +71 -0
- package/lib/routes/thoughtworks/namespace.ts +6 -0
- package/lib/routes/trending/all-trending.ts +2 -2
- package/lib/routes/tsdm39/bd.ts +101 -0
- package/lib/routes/tsdm39/namespace.ts +7 -0
- package/lib/routes/tvb/news.ts +1 -0
- package/lib/routes/twitter/api/index.ts +1 -1
- package/lib/routes/twitter/api/mobile-api/api.ts +9 -6
- package/lib/routes/twitter/api/mobile-api/login.ts +161 -138
- package/lib/routes/twitter/api/mobile-api/token.ts +16 -22
- package/lib/routes/twitter/api/web-api/api.ts +1 -0
- package/lib/routes/twitter/api/web-api/utils.ts +89 -17
- package/lib/routes/twitter/home.ts +2 -2
- package/lib/routes/twitter/keyword.ts +3 -2
- package/lib/routes/twitter/likes.ts +1 -1
- package/lib/routes/twitter/list.ts +1 -1
- package/lib/routes/twitter/media.ts +4 -3
- package/lib/routes/twitter/namespace.ts +2 -2
- package/lib/routes/twitter/user.ts +5 -4
- package/lib/routes/twitter/utils.ts +14 -5
- package/lib/routes/twreporter/category.ts +67 -22
- package/lib/routes/twreporter/fetch-article.ts +11 -5
- package/lib/routes/twreporter/newest.ts +2 -2
- package/lib/routes/typst/universe.ts +34 -8
- package/lib/routes/udn/breaking-news.ts +9 -0
- package/lib/routes/utgd/category.ts +18 -59
- package/lib/routes/utgd/timeline.ts +9 -45
- package/lib/routes/utgd/topic.ts +9 -51
- package/lib/routes/utgd/utils.ts +41 -0
- package/lib/routes/v2ex/tab.ts +3 -2
- package/lib/routes/v2ex/topics.ts +19 -3
- package/lib/routes/v2ex/xna.ts +55 -0
- package/lib/routes/vice/namespace.ts +6 -0
- package/lib/routes/vice/templates/article.art +19 -0
- package/lib/routes/vice/topic.ts +103 -0
- package/lib/routes/watasuke/blog.ts +1 -1
- package/lib/routes/weibo/friends.ts +1 -0
- package/lib/routes/weibo/group.ts +1 -0
- package/lib/routes/weibo/keyword.ts +3 -2
- package/lib/routes/weibo/namespace.ts +1 -1
- package/lib/routes/weibo/search/hot.ts +12 -7
- package/lib/routes/weibo/user-bookmarks.ts +191 -0
- package/lib/routes/weibo/user.ts +11 -8
- package/lib/routes/weibo/utils.ts +32 -2
- package/lib/routes/wfu/news.ts +1 -1
- package/lib/routes/wired/namespace.ts +7 -0
- package/lib/routes/wired/tag.ts +97 -0
- package/lib/routes/wired/types.ts +81 -0
- package/lib/routes/wordpress/util.ts +1 -1
- package/lib/routes/xiaoyuzhou/podcast.ts +2 -1
- package/lib/routes/ximalaya/album.ts +27 -19
- package/lib/routes/ximalaya/types.ts +68 -0
- package/lib/routes/ximalaya/utils.ts +38 -1
- package/lib/routes/xinhuanet/app.ts +109 -0
- package/lib/routes/xinhuanet/namespace.ts +8 -0
- package/lib/routes/xsijishe/forum.ts +23 -3
- package/lib/routes/xsijishe/rank.ts +23 -3
- package/lib/routes/yahoo/news/index.ts +149 -0
- package/lib/routes/yahoo/news/listid.ts +67 -0
- package/lib/routes/yahoo/news/{tw/provider-helper.ts → provider-helper.ts} +9 -4
- package/lib/routes/yahoo/news/{tw/provider.ts → provider.ts} +21 -6
- package/lib/routes/yahoo/news/{tw/utils.ts → utils.ts} +24 -15
- package/lib/routes/yicai/carousel.ts +48 -0
- package/lib/routes/yicai/utils.ts +23 -17
- package/lib/routes/ymgal/article.ts +1 -1
- package/lib/routes/youtube/channel.ts +1 -0
- package/lib/routes/youtube/custom.ts +2 -0
- package/lib/routes/youtube/live.ts +1 -0
- package/lib/routes/youtube/playlist.ts +1 -0
- package/lib/routes/youtube/subscriptions.ts +2 -0
- package/lib/routes/youtube/user.ts +16 -4
- package/lib/routes/zaobao/interactive.ts +2 -11
- package/lib/routes/zaobao/{index.ts → other.ts} +2 -10
- package/lib/routes/zaobao/realtime.ts +0 -8
- package/lib/routes/zaobao/util.ts +14 -10
- package/lib/routes/zcool/discover.ts +2 -1
- package/lib/routes/zhihu/activities.ts +2 -1
- package/lib/routes/zhihu/execlib/x-zse-96-v3.ts +2 -0
- package/lib/routes/zhihu/hot.ts +56 -7
- package/lib/routes/zhihu/namespace.ts +3 -0
- package/lib/routes/zhihu/posts.ts +20 -15
- package/lib/routes/zhihu/types.ts +104 -0
- package/lib/routes/zhihu/utils.ts +25 -4
- package/lib/routes/zhihu/zhuanlan.ts +8 -2
- package/lib/routes/zhubai/top20.ts +2 -2
- package/lib/routes/zhuwang/index.ts +1 -1
- package/lib/routes/zjgtjy/index.ts +3 -9
- package/lib/routes.test.ts +11 -5
- package/lib/types.ts +34 -2
- package/lib/utils/cache/index.ts +8 -0
- package/lib/utils/ofetch.ts +15 -1
- package/lib/utils/otel/index.ts +2 -0
- package/lib/utils/otel/metric.ts +66 -0
- package/lib/utils/otel/trace.ts +28 -0
- package/lib/utils/request-rewriter/fetch.ts +21 -2
- package/lib/utils/request-rewriter.test.ts +14 -0
- package/lib/views/atom.tsx +2 -2
- package/lib/views/error.tsx +4 -4
- package/lib/views/index.tsx +5 -4
- package/lib/views/json.ts +1 -1
- package/lib/views/layout.tsx +1 -1
- package/lib/views/rss.tsx +3 -2
- package/lib/views/rss3.test.ts +99 -0
- package/package.json +69 -56
- package/lib/routes/ieee/earlyaccess.ts +0 -100
- package/lib/routes/ieee/recent.ts +0 -107
- package/lib/routes/yahoo/news/tw/index.ts +0 -80
- package/lib/routes/yahoo/news/us/index.ts +0 -55
- package/lib/routes/zhihu/hotlist.ts +0 -72
- package/lib/routes-deprecated/bjnews/news.js +0 -44
- package/lib/routes-deprecated/iplay/home.js +0 -26
- package/lib/routes-deprecated/iplay/utils.js +0 -57
- package/lib/routes-deprecated/matters/author.js +0 -49
- package/lib/routes-deprecated/matters/latest.js +0 -69
- package/lib/routes-deprecated/matters/tags.js +0 -56
- /package/lib/routes/gov/{shanghai → sh}/rsj/templates/ksxm.art +0 -0
- /package/lib/routes/gov/{shanghai → sh}/wgj/templates/wgj.art +0 -0
- /package/lib/routes/hypergryph/{announce.ts → arknights/announce.ts} +0 -0
- /package/lib/routes/hypergryph/{japan.ts → arknights/japan.ts} +0 -0
- /package/lib/routes/hypergryph/{news.ts → arknights/news.ts} +0 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import got from '@/utils/got';
|
|
2
|
+
import { load } from 'cheerio';
|
|
3
|
+
|
|
4
|
+
const apiSlug = 'wp-json/wp/v2';
|
|
5
|
+
|
|
6
|
+
interface Filter {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
slug: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const filterKeys: Record<string, string> = {
|
|
13
|
+
search: 's',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const filterApiKeys: Record<string, string | undefined> = {
|
|
17
|
+
category: 'categories',
|
|
18
|
+
tag: 'tags',
|
|
19
|
+
search: undefined,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const filterApiKeysWithNoId = new Set(['search']);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Bake filter search parameters.
|
|
26
|
+
*
|
|
27
|
+
* @param filterPairs - The filter pairs object.
|
|
28
|
+
* e.g. `{ category: [ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ], tag: [ { id: ..., name: ..., slug: ... } ] }`.
|
|
29
|
+
* @param pairKey - The filter pair key.
|
|
30
|
+
* e.g. `{ id: ..., name: ..., slug: ... }`.
|
|
31
|
+
* @param isApi - Indicates if the search parameters are for API.
|
|
32
|
+
* @returns The baked filter search parameters.
|
|
33
|
+
*/
|
|
34
|
+
const bakeFilterSearchParams = (filterPairs: Record<string, Filter[] | string[]>, pairKey: string, isApi: boolean = false): URLSearchParams => {
|
|
35
|
+
/**
|
|
36
|
+
* Bake filters recursively.
|
|
37
|
+
*
|
|
38
|
+
* @param filterPairs - The filter pairs object.
|
|
39
|
+
* e.g. `{ category: [ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ], tag: [ { id: ..., name: ..., slug: ... } ] }`.
|
|
40
|
+
* @param filterSearchParams - The filter search parameters.
|
|
41
|
+
* e.g. `category=a,b&tag=c`.
|
|
42
|
+
* @returns The baked filter search parameters.
|
|
43
|
+
* e.g. `category=a,b&tag=c`.
|
|
44
|
+
*/
|
|
45
|
+
const bakeFilters = (filterPairs: Record<string, Filter[] | string[]>, filterSearchParams: URLSearchParams): URLSearchParams => {
|
|
46
|
+
const keys = Object.keys(filterPairs).filter((key) => filterPairs[key]?.length > 0 && (isApi ? Object.hasOwn(filterApiKeys, key) : Object.hasOwn(filterKeys, key)));
|
|
47
|
+
|
|
48
|
+
if (keys.length === 0) {
|
|
49
|
+
return filterSearchParams;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const key = keys[0];
|
|
53
|
+
const pairs = filterPairs[key];
|
|
54
|
+
|
|
55
|
+
const originalFilters = { ...filterPairs };
|
|
56
|
+
delete originalFilters[key];
|
|
57
|
+
|
|
58
|
+
const filterKey = getFilterKeyForSearchParams(key, isApi);
|
|
59
|
+
const pairValues = pairs.map((pair) => (Object.hasOwn(pair, pairKey) ? pair[pairKey] : pair));
|
|
60
|
+
|
|
61
|
+
if (filterKey) {
|
|
62
|
+
filterSearchParams.append(filterKey, pairValues.join(','));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return bakeFilters(originalFilters, filterSearchParams);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return bakeFilters(filterPairs, new URLSearchParams());
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Bake filters with pair.
|
|
73
|
+
*
|
|
74
|
+
* @param filters - The filters object.
|
|
75
|
+
* e.g. `{ category: [ a, b ], tag: [ c ] }`.
|
|
76
|
+
* @returns The baked filters.
|
|
77
|
+
* e.g. `{ category: [ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ], tag: [ { id: ..., name: ..., slug: ... } ] }`.
|
|
78
|
+
*/
|
|
79
|
+
const bakeFiltersWithPair = async (filters: Record<string, string[]>, rootUrl: string) => {
|
|
80
|
+
/**
|
|
81
|
+
* Bake keywords recursively.
|
|
82
|
+
*
|
|
83
|
+
* @param key - The key.
|
|
84
|
+
* e.g. `category` or `tag`.
|
|
85
|
+
* @param keywords - The keywords.
|
|
86
|
+
* e.g. `[ a, b ]`.
|
|
87
|
+
* @returns The baked keywords.
|
|
88
|
+
* e.g. `[ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ]`.
|
|
89
|
+
*/
|
|
90
|
+
const bakeKeywords = async (key: string, keywords: string[]) => {
|
|
91
|
+
if (keywords.length === 0) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const [keyword, ...rest] = keywords;
|
|
96
|
+
|
|
97
|
+
const filter = await getFilterByKeyAndKeyword(key, keyword, rootUrl);
|
|
98
|
+
|
|
99
|
+
return [
|
|
100
|
+
...(filter?.id && filter?.slug
|
|
101
|
+
? [
|
|
102
|
+
{
|
|
103
|
+
id: filter.id,
|
|
104
|
+
name: filter.name,
|
|
105
|
+
slug: filter.slug,
|
|
106
|
+
},
|
|
107
|
+
]
|
|
108
|
+
: []),
|
|
109
|
+
...(await bakeKeywords(key, rest)),
|
|
110
|
+
];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Bake filters recursively.
|
|
115
|
+
*
|
|
116
|
+
* @param filters - The filters object.
|
|
117
|
+
* e.g. `{ category: [ a, b ], tag: [ c ] }`.
|
|
118
|
+
* @param filtersWithPair - The filters with pairs.
|
|
119
|
+
* e.g. `{ category: [ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ], tag: [ { id: ..., name: ..., slug: ... } ] }`.
|
|
120
|
+
* @returns The baked filters.
|
|
121
|
+
* e.g. `{ category: [ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ], tag: [ { id: ..., name: ..., slug: ... } ] }`.
|
|
122
|
+
*/
|
|
123
|
+
const bakeFilters = async (filters: Record<string, string[]>, filtersWithPair: Record<string, Filter[]>) => {
|
|
124
|
+
const keys = Object.keys(filters);
|
|
125
|
+
|
|
126
|
+
if (keys.length === 0) {
|
|
127
|
+
return filtersWithPair;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const key = keys[0];
|
|
131
|
+
const keywords = filters[key];
|
|
132
|
+
|
|
133
|
+
const originalFilters = { ...filters };
|
|
134
|
+
delete originalFilters[key];
|
|
135
|
+
|
|
136
|
+
return bakeFilters(originalFilters, {
|
|
137
|
+
...filtersWithPair,
|
|
138
|
+
[key]: filterApiKeysWithNoId.has(key) ? keywords : await bakeKeywords(key, keywords),
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return await bakeFilters(filters, {});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Bake URL with search parameters.
|
|
147
|
+
*
|
|
148
|
+
* @param url - The URL.
|
|
149
|
+
* @param rootUrl - The root URL.
|
|
150
|
+
* @param searchParams - The search parameters.
|
|
151
|
+
* @returns The baked URL.
|
|
152
|
+
*/
|
|
153
|
+
const bakeUrl = (url: string, rootUrl: string, searchParams: URLSearchParams = new URLSearchParams()): string => {
|
|
154
|
+
const searchParamsStr = searchParams.toString();
|
|
155
|
+
const searchParamsSuffix = searchParamsStr ? `?${searchParamsStr}` : '';
|
|
156
|
+
|
|
157
|
+
return `${rootUrl}/${url}${searchParamsSuffix}`;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Fetch data from the specified URL.
|
|
162
|
+
*
|
|
163
|
+
* @param url - The URL to fetch data from.
|
|
164
|
+
* @param rootUrl - The root URL.
|
|
165
|
+
* @returns A promise that resolves to an object containing the fetched data to be added into `ctx.state.data`.
|
|
166
|
+
*/
|
|
167
|
+
const fetchData = async (url: string, rootUrl: string): Promise<object> => {
|
|
168
|
+
/**
|
|
169
|
+
* Request URLs recursively.
|
|
170
|
+
*
|
|
171
|
+
* @param urls - The URLs to request.
|
|
172
|
+
* @returns A promise that resolves to the response data or undefined if no response is available.
|
|
173
|
+
*/
|
|
174
|
+
const requestUrls = async (urls: string[]): Promise<string | undefined> => {
|
|
175
|
+
if (urls.length === 0) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const [currentUrl, ...remainingUrls] = urls;
|
|
180
|
+
try {
|
|
181
|
+
const { data: response } = await got.get(currentUrl);
|
|
182
|
+
return response;
|
|
183
|
+
} catch {
|
|
184
|
+
return requestUrls(remainingUrls);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const response = await requestUrls([url, rootUrl]);
|
|
189
|
+
|
|
190
|
+
if (!response) {
|
|
191
|
+
return {};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const $ = load(response);
|
|
195
|
+
|
|
196
|
+
const title = $('title').first().text();
|
|
197
|
+
const image = new URL('wp-content/uploads/site_logo.png', rootUrl).href;
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
title,
|
|
201
|
+
description: $('meta[property="og:description"]').attr('content') || $('meta[name="description"]').attr('content'),
|
|
202
|
+
link: url,
|
|
203
|
+
allowEmpty: true,
|
|
204
|
+
image,
|
|
205
|
+
author: $('meta[property="og:site_name"]').attr('content'),
|
|
206
|
+
language: $('html').attr('lang'),
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get filter by key and keyword.
|
|
212
|
+
*
|
|
213
|
+
* @param key - The key.
|
|
214
|
+
* e.g. `category` or `tag`.
|
|
215
|
+
* @param keyword - The keywords.
|
|
216
|
+
* e.g. `keyword1`.
|
|
217
|
+
* @returns A promise that resolves to the filter object if found, or undefined if not found.
|
|
218
|
+
*/
|
|
219
|
+
const getFilterByKeyAndKeyword = async (key: string, keyword: string, rootUrl: string): Promise<Filter | undefined> => {
|
|
220
|
+
const apiFilterUrl = `${rootUrl}/${apiSlug}/${getFilterKeyForSearchParams(key, true)}`;
|
|
221
|
+
|
|
222
|
+
const { data: response } = await got(apiFilterUrl, {
|
|
223
|
+
searchParams: {
|
|
224
|
+
search: keyword,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return response.length > 0 ? response[0] : undefined;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get filter key for search parameters.
|
|
233
|
+
*
|
|
234
|
+
* @param key - The key. e.g. `category` or `tag`.
|
|
235
|
+
* @param isApi - Indicates whether the key is for the API.
|
|
236
|
+
* @returns The filter key for search parameters, or undefined if not found.
|
|
237
|
+
* e.g. `categories` or `tags`.
|
|
238
|
+
*/
|
|
239
|
+
const getFilterKeyForSearchParams = (key: string, isApi: boolean = false): string | undefined => {
|
|
240
|
+
const keys = isApi ? filterApiKeys : filterKeys;
|
|
241
|
+
|
|
242
|
+
return Object.hasOwn(keys, key) ? (keys[key] ?? key) : undefined;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get filter parameters for URL.
|
|
247
|
+
*
|
|
248
|
+
* @param filterPairs - The filter pairs object.
|
|
249
|
+
* e.g. `{ category: [ { id: ..., name: ..., slug: ... }, { id: ..., name: ..., slug: ... } ], tag: [ { id: ..., name: ..., slug: ... } ] }`.
|
|
250
|
+
* @returns The filter parameters for the URL, or undefined if no filters are available.
|
|
251
|
+
*/
|
|
252
|
+
const getFilterParamsForUrl = (filterPairs: Record<string, Filter[]>): string | undefined => {
|
|
253
|
+
const keys = Object.keys(filterPairs).filter((key) => filterPairs[key].length > 0 && !Object.hasOwn(filterKeys, key));
|
|
254
|
+
|
|
255
|
+
if (keys.length === 0) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const key = keys[0];
|
|
260
|
+
|
|
261
|
+
return filterPairs[key].map((pair) => pair.slug).join('/');
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Parses a filter string into a filters object.
|
|
266
|
+
*
|
|
267
|
+
* @param filterStr - The filter string to parse.
|
|
268
|
+
* e.g. `category/a,b/tag/c`.
|
|
269
|
+
* @returns The parsed filters object.
|
|
270
|
+
* e.g. `{ category: [ 'a', 'b' ], tag: [ 'c' ] }`.
|
|
271
|
+
*/
|
|
272
|
+
const parseFilterStr = (filterStr: string | undefined): Record<string, string[]> => {
|
|
273
|
+
/**
|
|
274
|
+
* Recursively parses a filter string.
|
|
275
|
+
*
|
|
276
|
+
* @param remainingStr - The remaining filter string to parse.
|
|
277
|
+
* e.g. `category/a,b/tag/c`.
|
|
278
|
+
* @param filters - The accumulated filters object.
|
|
279
|
+
* e.g. `{ category: [ a, b ], tag: [ c ] }`.
|
|
280
|
+
* @param currentKey - The current filter key.
|
|
281
|
+
* e.g. `category` or `tag`.
|
|
282
|
+
* @returns The parsed filters object.
|
|
283
|
+
*/
|
|
284
|
+
const parseStr = (remainingStr: string | undefined, filters: Record<string, string[]> = {}, currentKey?: string): Record<string, string[]> => {
|
|
285
|
+
if (!remainingStr) {
|
|
286
|
+
return filters;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const [word, ...rest] = remainingStr.split(/\/|,/);
|
|
290
|
+
|
|
291
|
+
const isKey = Object.hasOwn(filterApiKeys, word);
|
|
292
|
+
const key = isKey ? word : currentKey;
|
|
293
|
+
|
|
294
|
+
const newFilters = key
|
|
295
|
+
? {
|
|
296
|
+
...filters,
|
|
297
|
+
[key]: [...(filters[key] || []), ...(isKey ? [] : [word])],
|
|
298
|
+
}
|
|
299
|
+
: filters;
|
|
300
|
+
|
|
301
|
+
return parseStr(rest.join('/'), newFilters, key);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
return parseStr(filterStr, {});
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
export { apiSlug, bakeFilterSearchParams, bakeFiltersWithPair, bakeUrl, fetchData, getFilterParamsForUrl, parseFilterStr };
|
|
@@ -6,7 +6,7 @@ const handler = (ctx) => processFeed('channel', ctx);
|
|
|
6
6
|
export const route: Route = {
|
|
7
7
|
path: '/channel/:type?/:language?',
|
|
8
8
|
name: '专题・栏目',
|
|
9
|
-
maintainers: ['prnake'],
|
|
9
|
+
maintainers: ['prnake', 'mintyfrankie'],
|
|
10
10
|
parameters: {
|
|
11
11
|
type: '栏目,缺省为最新',
|
|
12
12
|
language: '语言,简体`zh-hans`,繁体`zh-hant`,缺省为简体',
|
|
@@ -20,7 +20,7 @@ export const route: Route = {
|
|
|
20
20
|
handler,
|
|
21
21
|
example: '/theinitium/author/ninghuilulu/zh-hans',
|
|
22
22
|
categories: ['new-media'],
|
|
23
|
-
description: 'Web 版认证 token
|
|
23
|
+
description: '需填入 Web 版认证 token, 也可选择直接在环境设置中填写明文的用户名和密码',
|
|
24
24
|
features: {
|
|
25
25
|
requireConfig: [
|
|
26
26
|
{
|
|
@@ -28,11 +28,6 @@ export const route: Route = {
|
|
|
28
28
|
optional: true,
|
|
29
29
|
description: `端传媒 Web 版认证 token。获取方式:登陆后打开端传媒站内任意页面,打开浏览器开发者工具中 “网络”(Network) 选项卡,筛选 URL 找到任一个地址为 \`api.initium.com\` 开头的请求,点击检查其 “消息头”,在 “请求头” 中找到Authorization字段,将其值复制填入配置即可。你的配置应该形如 \`INITIUM_BEARER_TOKEN: 'Bearer eyJxxxx......xx_U8'\`。使用 token 部署的好处是避免占据登陆设备数的额度,但这个 token 一般有效期为两周,因此只可作临时测试使用。`,
|
|
30
30
|
},
|
|
31
|
-
{
|
|
32
|
-
name: 'INITIUM_IAP_RECEIPT',
|
|
33
|
-
optional: true,
|
|
34
|
-
description: `端传媒 iOS 版内购回执认证 token。获取方式:登陆后打开端传媒 iOS app 内任意页面,打开抓包工具,筛选 URL 找到任一个地址为 \`api.initium.com\` 开头的请求,点击检查其 “消息头”,在 “请求头” 中找到 \`X-IAP-Receipt\` 字段,将其值复制填入配置即可。你的配置应该形如 \`INITIUM_IAP_RECEIPT: ef81dee9e4e2fe084a0af1ea82da2f7b16e75f756db321618a119fa62b52550e\`。`,
|
|
35
|
-
},
|
|
36
31
|
{
|
|
37
32
|
name: 'INITIUM_USERNAME',
|
|
38
33
|
optional: true,
|
|
@@ -39,7 +39,6 @@ export const processFeed = async (model: string, ctx: Context) => {
|
|
|
39
39
|
const key = {
|
|
40
40
|
email: config.initium.username,
|
|
41
41
|
password: config.initium.password,
|
|
42
|
-
iapReceipt: config.initium.iap_receipt,
|
|
43
42
|
};
|
|
44
43
|
const body = JSON.stringify(key);
|
|
45
44
|
|
|
@@ -59,25 +58,11 @@ export const processFeed = async (model: string, ctx: Context) => {
|
|
|
59
58
|
Accept: 'application/json',
|
|
60
59
|
Connection: 'keep-alive',
|
|
61
60
|
Authorization: TOKEN,
|
|
62
|
-
Origin: `https://theinitium.com/`,
|
|
63
|
-
Referer: `https://theinitium.com/`,
|
|
64
|
-
'X-Client-Name': 'Web',
|
|
65
61
|
},
|
|
66
62
|
body,
|
|
67
63
|
});
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
const devices = login.data.access.devices;
|
|
71
|
-
|
|
72
|
-
for (const key in devices) {
|
|
73
|
-
const device = devices[key];
|
|
74
|
-
if (device.status === 'logged_in' && !device.logout_at && device.platform === 'web') {
|
|
75
|
-
token = 'Bearer ' + device.device_id;
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
*/
|
|
80
|
-
token = 'Bearer ' + login.data.token;
|
|
65
|
+
token = 'token ' + login.data.token;
|
|
81
66
|
cache.set('initium:token', token);
|
|
82
67
|
}
|
|
83
68
|
|
|
@@ -85,7 +70,6 @@ export const processFeed = async (model: string, ctx: Context) => {
|
|
|
85
70
|
Accept: '*/*',
|
|
86
71
|
Connection: 'keep-alive',
|
|
87
72
|
Authorization: token,
|
|
88
|
-
'X-IAP-Receipt': key.iapReceipt || '',
|
|
89
73
|
};
|
|
90
74
|
|
|
91
75
|
let response;
|
|
@@ -154,7 +138,7 @@ export const processFeed = async (model: string, ctx: Context) => {
|
|
|
154
138
|
const items = await Promise.all(
|
|
155
139
|
articles
|
|
156
140
|
.filter((a) => a.article)
|
|
157
|
-
.slice(0, token === TOKEN
|
|
141
|
+
.slice(0, token === TOKEN ? 25 : articles.length)
|
|
158
142
|
.map(async (item) => {
|
|
159
143
|
item.article.date = parseDate(item.article.date);
|
|
160
144
|
item.article.updated = parseDate(item.article.updated);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
import ofetch from '@/utils/ofetch'; // 统一使用的请求库
|
|
3
|
+
import { parseDate } from '@/utils/parse-date';
|
|
4
|
+
|
|
5
|
+
export const route: Route = {
|
|
6
|
+
path: '/blog',
|
|
7
|
+
categories: ['programming'],
|
|
8
|
+
example: '/thoughtworks/blog',
|
|
9
|
+
radar: [
|
|
10
|
+
{
|
|
11
|
+
source: ['www.thoughtworks.com/zh-cn/insights/blog'],
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
name: 'Inside Blog',
|
|
15
|
+
maintainers: ['Hyvi'],
|
|
16
|
+
handler,
|
|
17
|
+
};
|
|
18
|
+
async function handler() {
|
|
19
|
+
// https://www.thoughtworks.com/rest/search/config 里的 BLOG_SEARCH_TOKEN
|
|
20
|
+
const tokenData = await ofetch('https://www.thoughtworks.com/rest/search/config', {
|
|
21
|
+
headers: {
|
|
22
|
+
'content-type': 'application/json',
|
|
23
|
+
origin: 'https://www.thoughtworks.com',
|
|
24
|
+
referer: 'https://www.thoughtworks.com/',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// 'Bearer ' + token
|
|
29
|
+
const bearerToken = 'Bearer ' + tokenData.BLOG_SEARCH_TOKEN;
|
|
30
|
+
|
|
31
|
+
const data = await ofetch('https://platform-eu.cloud.coveo.com/rest/search/v2?organizationId=thoughtworksproductionhcqoag0q', {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: {
|
|
34
|
+
authorization: bearerToken,
|
|
35
|
+
'content-type': 'application/json',
|
|
36
|
+
origin: 'https://www.thoughtworks.com',
|
|
37
|
+
referer: 'https://www.thoughtworks.com/',
|
|
38
|
+
},
|
|
39
|
+
body: {
|
|
40
|
+
context: { countryLocale: 'zh-cn' },
|
|
41
|
+
fieldsToInclude: ['author', 'language', 'objecttype', 'collection', 'source', 'tw_content_type', 'tw_topic', 'tw_published_date'],
|
|
42
|
+
sortCriteria: '@tw_published_date descending',
|
|
43
|
+
numberOfResults: 10,
|
|
44
|
+
firstResult: 0,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
// 从 API 响应中提取相关数据
|
|
48
|
+
const items = data.results.map((item) => ({
|
|
49
|
+
// 文章标题
|
|
50
|
+
title: item.title,
|
|
51
|
+
// 文章链接
|
|
52
|
+
link: item.uri,
|
|
53
|
+
// 文章正文
|
|
54
|
+
description: item.excerpt,
|
|
55
|
+
// 文章发布日期
|
|
56
|
+
pubDate: parseDate(item.raw.tw_published_date),
|
|
57
|
+
// 如果有的话,文章作者
|
|
58
|
+
author: item.raw.sysauthor,
|
|
59
|
+
// 如果有的话,文章分类
|
|
60
|
+
// category: item.labels.map((label) => label.name),
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
// 源标题
|
|
65
|
+
title: 'ThoughtWorks Blog',
|
|
66
|
+
// 源链接
|
|
67
|
+
link: 'https://www.thoughtworks.com/zh-cn/insights/blog',
|
|
68
|
+
// 源文章
|
|
69
|
+
item: items,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -8,7 +8,7 @@ import utc from 'dayjs/plugin/utc';
|
|
|
8
8
|
import timezone from 'dayjs/plugin/timezone';
|
|
9
9
|
dayjs.extend(utc);
|
|
10
10
|
dayjs.extend(timezone);
|
|
11
|
-
import
|
|
11
|
+
import ofetch from '@/utils/ofetch';
|
|
12
12
|
import { art } from '@/utils/render';
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { config } from '@/config';
|
|
@@ -75,7 +75,7 @@ const filterKeyword = (keywordList) => (res) => res.filter(({ title }) => hasKey
|
|
|
75
75
|
// Data Fetcher
|
|
76
76
|
// TODO: support channel selection
|
|
77
77
|
const fetchAllData = async (keywordList = [], dateList = [], cache) => {
|
|
78
|
-
const cachedGetData = (url) => cache.tryGet(url, () =>
|
|
78
|
+
const cachedGetData = (url) => cache.tryGet(url, () => ofetch(url), config.cache.contentExpire, false);
|
|
79
79
|
|
|
80
80
|
let data = await Promise.all(
|
|
81
81
|
dateList.map(async (dateTime) => ({
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { DataItem, Route } from '@/types';
|
|
2
|
+
import { config } from '@/config';
|
|
3
|
+
import ofetch from '@/utils/ofetch';
|
|
4
|
+
import { load } from 'cheerio';
|
|
5
|
+
import { parseDate } from '@/utils/parse-date';
|
|
6
|
+
import ConfigNotFoundError from '@/errors/types/config-not-found';
|
|
7
|
+
|
|
8
|
+
// type id => display name
|
|
9
|
+
type Mapping = Record<string, string>;
|
|
10
|
+
|
|
11
|
+
const TYPE: Mapping = {
|
|
12
|
+
'403': '720P',
|
|
13
|
+
'404': '1080P',
|
|
14
|
+
'405': 'BDMV',
|
|
15
|
+
'4130': '4K',
|
|
16
|
+
'5815': 'AV1',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// render into MD table
|
|
20
|
+
const mkTable = (mapping: Mapping): string => {
|
|
21
|
+
const heading: string[] = [],
|
|
22
|
+
separator: string[] = [],
|
|
23
|
+
body: string[] = [];
|
|
24
|
+
|
|
25
|
+
for (const key in mapping) {
|
|
26
|
+
heading.push(mapping[key]);
|
|
27
|
+
separator.push(':--:');
|
|
28
|
+
body.push(key);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return [heading.join(' | '), separator.join(' | '), body.join(' | ')].map((s) => `| ${s} |`).join('\n');
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handler: Route['handler'] = async (ctx) => {
|
|
35
|
+
const { type } = ctx.req.param();
|
|
36
|
+
|
|
37
|
+
const cookie = config.tsdm39.cookie;
|
|
38
|
+
if (!cookie) {
|
|
39
|
+
throw new ConfigNotFoundError('缺少 TSDM39 用户登录后的 Cookie 值 <a href="https://docs.rsshub.app/zh/deploy/config#route-specific-configurations">TSDM 相关路由</a>');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const html = await ofetch(`https://www.tsdm39.com/forum.php?mod=forumdisplay&fid=85${type ? `&filter=typeid&typeid=${type}` : ''}`, {
|
|
43
|
+
headers: {
|
|
44
|
+
Cookie: cookie,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const $ = load(html);
|
|
49
|
+
|
|
50
|
+
const item = $('tbody.tsdm_normalthread')
|
|
51
|
+
.toArray()
|
|
52
|
+
.map<DataItem>((item) => {
|
|
53
|
+
const $ = load(item);
|
|
54
|
+
|
|
55
|
+
const title = $('a.xst').text();
|
|
56
|
+
const price = $('span.xw1').last().text();
|
|
57
|
+
const link = $('a.xst').attr('href');
|
|
58
|
+
const date = $('td.by em').first().text().trim();
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
title,
|
|
62
|
+
description: `价格:${price}`,
|
|
63
|
+
link,
|
|
64
|
+
pubDate: parseDate(date),
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
title: '天使动漫论坛 - BD',
|
|
70
|
+
link: 'https://www.tsdm39.com/forum.php?mod=forumdisplay&fid=85',
|
|
71
|
+
language: 'zh-Hans',
|
|
72
|
+
item,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const route: Route = {
|
|
77
|
+
path: '/bd/:type?',
|
|
78
|
+
name: 'BD',
|
|
79
|
+
categories: ['anime'],
|
|
80
|
+
maintainers: ['equt'],
|
|
81
|
+
example: '/tsdm39/bd',
|
|
82
|
+
parameters: {
|
|
83
|
+
type: 'BD type, checkout the table below for details',
|
|
84
|
+
},
|
|
85
|
+
features: {
|
|
86
|
+
requireConfig: [
|
|
87
|
+
{
|
|
88
|
+
name: 'TSDM39_COOKIES',
|
|
89
|
+
optional: false,
|
|
90
|
+
description: '天使动漫论坛登陆后的 cookie 值,可在浏览器控制台通过 `document.cookie` 获取。',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
requirePuppeteer: false,
|
|
94
|
+
antiCrawler: false,
|
|
95
|
+
supportBT: false,
|
|
96
|
+
supportPodcast: false,
|
|
97
|
+
supportScihub: false,
|
|
98
|
+
},
|
|
99
|
+
handler,
|
|
100
|
+
description: [TYPE].map((el) => mkTable(el)).join('\n\n'),
|
|
101
|
+
};
|
package/lib/routes/tvb/news.ts
CHANGED
|
@@ -4,7 +4,7 @@ import webApi from './web-api/api';
|
|
|
4
4
|
import { config } from '@/config';
|
|
5
5
|
|
|
6
6
|
const enableMobileApi = config.twitter.username && config.twitter.password;
|
|
7
|
-
const enableWebApi = config.twitter.
|
|
7
|
+
const enableWebApi = config.twitter.authToken;
|
|
8
8
|
|
|
9
9
|
type ApiItem = (id: string, params?: Record<string, any>) => Promise<Record<string, any>> | Record<string, any> | null;
|
|
10
10
|
let api: {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { baseUrl, gqlMap, gqlFeatures, consumerKey, consumerSecret } from './constants';
|
|
2
2
|
import { config } from '@/config';
|
|
3
3
|
import logger from '@/utils/logger';
|
|
4
|
-
import got from '@/utils/got';
|
|
5
4
|
import OAuth from 'oauth-1.0a';
|
|
6
5
|
import CryptoJS from 'crypto-js';
|
|
7
6
|
import queryString from 'query-string';
|
|
8
|
-
import {
|
|
7
|
+
import { getToken } from './token';
|
|
9
8
|
import cache from '@/utils/cache';
|
|
10
9
|
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
|
10
|
+
import ofetch from '@/utils/ofetch';
|
|
11
11
|
|
|
12
12
|
const twitterGot = async (url, params) => {
|
|
13
13
|
const token = await getToken();
|
|
14
14
|
|
|
15
|
-
const oauth = OAuth({
|
|
15
|
+
const oauth = new OAuth({
|
|
16
16
|
consumer: {
|
|
17
17
|
key: consumerKey,
|
|
18
18
|
secret: consumerSecret,
|
|
@@ -36,11 +36,14 @@ const twitterGot = async (url, params) => {
|
|
|
36
36
|
},
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const response = await
|
|
39
|
+
const response = await ofetch.raw(requestData.url, {
|
|
40
40
|
headers: oauth.toHeader(oauth.authorize(requestData, token)),
|
|
41
41
|
});
|
|
42
|
+
if (response.status === 401) {
|
|
43
|
+
cache.globalCache.set(token.cacheKey, '');
|
|
44
|
+
}
|
|
42
45
|
|
|
43
|
-
return response.
|
|
46
|
+
return response._data;
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
const paginationTweets = async (endpoint, userId, variables, path) => {
|
|
@@ -279,5 +282,5 @@ export default {
|
|
|
279
282
|
excludeRetweet,
|
|
280
283
|
getSearch,
|
|
281
284
|
getUserTweet,
|
|
282
|
-
init:
|
|
285
|
+
init: () => void 0,
|
|
283
286
|
};
|