rsshub 1.0.0-master.f72af1b → 1.0.0-master.f7347d9
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/lib/config.ts +18 -0
- package/lib/middleware/template.tsx +10 -2
- package/lib/routes/163/music/playlist.ts +2 -1
- package/lib/routes/5eplay/index.ts +1 -51
- package/lib/routes/a9vg/index.ts +214 -0
- package/lib/routes/a9vg/namespace.ts +1 -0
- package/lib/routes/a9vg/templates/description.art +17 -0
- package/lib/routes/aibase/discover.ts +388 -0
- package/lib/routes/aibase/namespace.ts +8 -0
- package/lib/routes/aibase/news.ts +118 -0
- package/lib/routes/aibase/templates/description.art +100 -0
- package/lib/routes/aibase/topic.ts +614 -0
- package/lib/routes/aibase/util.ts +114 -0
- package/lib/routes/apnews/api.ts +18 -3
- package/lib/routes/apnews/rss.ts +1 -1
- package/lib/routes/apnews/topics.ts +4 -3
- package/lib/routes/apple/podcast.ts +19 -15
- package/lib/routes/bangumi/templates/tv/subject.art +6 -0
- package/lib/routes/bangumi/tv/other/followrank.ts +19 -22
- package/lib/routes/bangumi/tv/user/collections.ts +172 -0
- package/lib/routes/bilibili/cache.ts +16 -8
- package/lib/routes/bilibili/utils.ts +85 -3
- package/lib/routes/bilibili/video.ts +7 -9
- package/lib/routes/bilibili/vsearch.ts +1 -1
- package/lib/routes/bjnews/cat.ts +9 -1
- package/lib/routes/cbpanet/index.ts +380 -0
- package/lib/routes/cbpanet/namespace.ts +8 -0
- package/lib/routes/ceph/blog.ts +72 -0
- package/lib/routes/ceph/namespace.ts +7 -0
- package/lib/routes/chinanews/index.ts +1 -1
- package/lib/routes/chinaventure/index.ts +1 -1
- package/lib/routes/cisia/index.ts +264 -0
- package/lib/routes/cisia/namespace.ts +8 -0
- package/lib/routes/cjlu/namespace.ts +10 -0
- package/lib/routes/cjlu/yjsy/index.ts +107 -0
- package/lib/routes/cnki/journals.ts +31 -2
- package/lib/routes/cohere/index.ts +54 -0
- package/lib/routes/cohere/namespace.ts +6 -0
- package/lib/routes/coolapk/dyh.ts +7 -1
- package/lib/routes/coolapk/hot.ts +7 -1
- package/lib/routes/coolapk/huati.ts +7 -1
- package/lib/routes/coolapk/namespace.ts +6 -0
- package/lib/routes/coolapk/toutiao.ts +7 -1
- package/lib/routes/coolapk/tuwen.ts +10 -5
- package/lib/routes/coolapk/user-dynamic.ts +7 -1
- package/lib/routes/damai/activity.ts +3 -2
- package/lib/routes/dcfever/trading.ts +3 -5
- package/lib/routes/dcfever/utils.ts +13 -4
- package/lib/routes/dealstreetasia/home.ts +72 -0
- package/lib/routes/dealstreetasia/namespace.ts +6 -0
- package/lib/routes/dealstreetasia/section.ts +57 -0
- package/lib/routes/dlsite/campaign.ts +1 -2
- package/lib/routes/dlsite/new.ts +1 -2
- package/lib/routes/dlsite/{index.ts → z-index/index.ts} +1 -1
- package/lib/routes/douban/other/topic.ts +10 -4
- package/lib/routes/douyin/types.ts +795 -0
- package/lib/routes/douyin/user.ts +51 -23
- package/lib/routes/douyin/utils.ts +1 -87
- package/lib/routes/dribbble/keyword.ts +1 -1
- package/lib/routes/dribbble/popular.ts +1 -1
- package/lib/routes/dribbble/user.ts +1 -1
- package/lib/routes/dribbble/utils.ts +16 -18
- package/lib/routes/famitsu/category.ts +1 -1
- package/lib/routes/fanbox/index.ts +1 -1
- package/lib/routes/fanbox/types.ts +1 -5
- package/lib/routes/fediverse/timeline.ts +21 -3
- package/lib/routes/follow/profile.ts +4 -2
- package/lib/routes/follow/types.ts +11 -1
- package/lib/routes/github/advisor.ts +97 -0
- package/lib/routes/github/discussions.ts +194 -0
- package/lib/routes/github/issue.ts +1 -1
- package/lib/routes/github/pulls.ts +1 -1
- package/lib/routes/gmcmonline/chinacustoms.ts +130 -0
- package/lib/routes/gmcmonline/namespace.ts +8 -0
- package/lib/routes/gov/csrc/csrc.ts +541 -0
- package/lib/routes/gov/customs/list.ts +5 -2
- package/lib/routes/gov/customs/namespace.ts +7 -0
- package/lib/routes/gov/jgjcndrc/index.ts +95 -66
- package/lib/routes/gov/moa/moa.ts +3 -3
- package/lib/routes/gov/moa/szcpxx.ts +115 -0
- package/lib/routes/gov/moa/zdscxx.ts +71 -21
- package/lib/routes/gov/ndrc/zfxxgk.ts +106 -0
- package/lib/routes/gov/pudong/zwgk.ts +65 -0
- package/lib/routes/gov/zj/search.ts +17 -12
- package/lib/routes/guancha/member.ts +1 -1
- package/lib/routes/hellogithub/index.ts +17 -67
- package/lib/routes/hellogithub/report.ts +1 -1
- package/lib/routes/hex-rays/index.ts +23 -29
- package/lib/routes/hfut/hf/notice.ts +43 -0
- package/lib/routes/hfut/hf/utils.ts +80 -0
- package/lib/routes/hfut/namespace.ts +6 -0
- package/lib/routes/hfut/xc/notice.ts +43 -0
- package/lib/routes/hfut/xc/utils.ts +73 -0
- package/lib/routes/hko/earthquake.ts +56 -0
- package/lib/routes/hko/namespace.ts +8 -0
- package/lib/routes/hko/weather.ts +56 -0
- package/lib/routes/huggingface/blog-zh.ts +1 -1
- package/lib/routes/hust/mse.ts +575 -0
- package/lib/routes/i-cable/namespace.ts +6 -0
- package/lib/routes/i-cable/news.ts +77 -0
- package/lib/routes/i-cable/templates/description.art +8 -0
- package/lib/routes/infoq/presentations.ts +203 -0
- package/lib/routes/infoq/templates/description.art +41 -0
- package/lib/routes/ipsw.dev/index.ts +64 -0
- package/lib/routes/ipsw.dev/namespace.ts +7 -0
- package/lib/routes/ipsw.dev/templates/description.art +20 -0
- package/lib/routes/ixigua/user-video.ts +18 -7
- package/lib/routes/javtiful/actress.ts +37 -0
- package/lib/routes/javtiful/channel.ts +37 -0
- package/lib/routes/javtiful/namespace.ts +6 -0
- package/lib/routes/javtiful/templates/description.art +7 -0
- package/lib/routes/javtiful/utils.ts +18 -0
- package/lib/routes/kisskiss/blog.ts +74 -0
- package/lib/routes/kisskiss/namespace.ts +6 -0
- package/lib/routes/ktown4u/artist-brandlist.ts +61 -0
- package/lib/routes/ktown4u/namespace.ts +6 -0
- package/lib/routes/lorientlejour/index.ts +186 -0
- package/lib/routes/lorientlejour/namespace.ts +7 -0
- package/lib/routes/lorientlejour/templates/description.art +18 -0
- package/lib/routes/lovelive-anime/namespace.ts +1 -1
- package/lib/routes/lovelive-anime/news.ts +56 -26
- package/lib/routes/lovelive-anime/schedules.ts +18 -6
- package/lib/routes/lovelive-anime/templates/description.art +1 -1
- package/lib/routes/lovelive-anime/templates/scheduleDesc.art +0 -1
- package/lib/routes/lovelive-anime/topics.ts +1 -1
- package/lib/routes/manhuagui/comic.ts +1 -1
- package/lib/routes/mi/crowdfunding.ts +43 -22
- package/lib/routes/mi/templates/crowdfunding.art +28 -0
- package/lib/routes/mi/types.ts +40 -0
- package/lib/routes/mi/utils.ts +80 -0
- package/lib/routes/misskey/utils.ts +1 -0
- package/lib/routes/misskon/namespace.ts +6 -0
- package/lib/routes/misskon/posts.ts +33 -0
- package/lib/routes/misskon/tag.ts +38 -0
- package/lib/routes/misskon/top.ts +67 -0
- package/lib/routes/misskon/utils.ts +41 -0
- package/lib/routes/natgeo/dailyphoto.ts +1 -1
- package/lib/routes/natgeo/dailyselection.ts +1 -1
- package/lib/routes/ncku/namespace.ts +1 -1
- package/lib/routes/ncku/phys.ts +95 -0
- package/lib/routes/news/namespace.ts +1 -1
- package/lib/routes/nikkei/cn/index.ts +12 -1
- package/lib/routes/nudt/yjszs.ts +33 -13
- package/lib/routes/nytimes/book.ts +11 -11
- package/lib/routes/nytimes/daily-briefing-chinese.ts +4 -4
- package/lib/routes/nytimes/namespace.ts +1 -1
- package/lib/routes/oncc/templates/article.art +1 -1
- package/lib/routes/papers/index.ts +7 -1
- package/lib/routes/parliament.uk/commonslibrary.ts +55 -0
- package/lib/routes/parliament.uk/lordslibrary.ts +55 -0
- package/lib/routes/parliament.uk/namespace.ts +6 -0
- package/lib/routes/picuki/profile.ts +50 -39
- package/lib/routes/pornhub/model.ts +3 -5
- package/lib/routes/pornhub/pornstar.ts +3 -5
- package/lib/routes/pornhub/users.ts +3 -5
- package/lib/routes/resonac/namespace.ts +6 -0
- package/lib/routes/resonac/products.ts +85 -0
- package/lib/routes/rsshub/transform/html.ts +114 -75
- package/lib/routes/rsshub/transform/json.ts +14 -8
- package/lib/routes/sciencenet/user.ts +3 -1
- package/lib/routes/scmp/utils.ts +2 -2
- package/lib/routes/skeb/following-creators.ts +52 -0
- package/lib/routes/skeb/following-works.ts +52 -0
- package/lib/routes/skeb/friend-works.ts +52 -0
- package/lib/routes/skeb/index.ts +131 -0
- package/lib/routes/skeb/namespace.ts +6 -0
- package/lib/routes/skeb/search.ts +77 -0
- package/lib/routes/skeb/templates/creator.art +8 -0
- package/lib/routes/skeb/templates/work.art +10 -0
- package/lib/routes/skeb/utils.ts +155 -0
- package/lib/routes/skeb/works.ts +88 -0
- package/lib/routes/skebetter/illust.ts +83 -0
- package/lib/routes/skebetter/index.ts +83 -0
- package/lib/routes/skebetter/manga.ts +65 -0
- package/lib/routes/skebetter/namespace.ts +6 -0
- package/lib/routes/skebetter/utils.ts +72 -0
- package/lib/routes/spankbang/namespace.ts +6 -0
- package/lib/routes/spankbang/new-videos.ts +90 -0
- package/lib/routes/spankbang/templates/video.art +7 -0
- package/lib/routes/straitstimes/index.ts +135 -0
- package/lib/routes/straitstimes/namespace.ts +7 -0
- package/lib/routes/straitstimes/templates/description.art +27 -0
- package/lib/routes/szftedu/dongtai.ts +62 -0
- package/lib/routes/szftedu/gonggao.ts +62 -0
- package/lib/routes/szftedu/namespace.ts +6 -0
- package/lib/routes/the/index.ts +1 -1
- package/lib/routes/tkww/index.ts +83 -0
- package/lib/routes/tkww/namespace.ts +6 -0
- package/lib/routes/ttv/index.ts +1 -1
- package/lib/routes/tvb/news.ts +2 -1
- package/lib/routes/twitter/api/mobile-api/login.ts +5 -0
- package/lib/routes/twitter/api/web-api/api.ts +16 -10
- package/lib/routes/twitter/api/web-api/constants.ts +1 -1
- package/lib/routes/twitter/api/web-api/utils.ts +94 -56
- package/lib/routes/twitter/list.ts +4 -12
- package/lib/routes/twitter/media.ts +13 -4
- package/lib/routes/twitter/user.ts +15 -6
- package/lib/routes/udn/breaking-news.ts +2 -2
- package/lib/routes/uestc/gr.ts +65 -37
- package/lib/routes/uestc/jwc.ts +49 -28
- package/lib/routes/wechat/ershcimi.ts +4 -2
- package/lib/routes/weibo/user.ts +10 -2
- package/lib/routes/xaut/index.ts +13 -20
- package/lib/routes/xaut/namespace.ts +1 -1
- package/lib/routes/xbookcn/blog.ts +66 -0
- package/lib/routes/xbookcn/namespace.ts +6 -0
- package/lib/routes/xiaoyuzhou/podcast.ts +35 -7
- package/lib/routes/xueqiu/cookies.ts +5 -3
- package/lib/routes/xueqiu/stock-info.ts +6 -12
- package/lib/routes/yande/namespace.ts +1 -1
- package/lib/routes/yande/post.ts +6 -6
- package/lib/routes/zaobao/util.ts +41 -43
- package/lib/routes/zhihu/activities.ts +2 -1
- package/lib/routes/zhihu/timeline.ts +6 -1
- package/lib/routes/zhihu/utils.ts +1 -1
- package/lib/routes/zjut/cs/index.ts +105 -0
- package/lib/routes/zjut/jwc/index.ts +117 -0
- package/lib/utils/cache/redis.ts +1 -1
- package/package.json +35 -36
- package/lib/routes/a9vg/a9vg.ts +0 -45
- package/lib/routes/gov/ndrc/zfxxgk/articles.ts +0 -73
- package/lib/routes-deprecated/hko/weather.js +0 -44
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Route } from '@/types';
|
|
1
|
+
import { DataItem, Route } from '@/types';
|
|
2
2
|
import { getCurrentPath } from '@/utils/helpers';
|
|
3
3
|
const __dirname = getCurrentPath(import.meta.url);
|
|
4
4
|
|
|
@@ -16,20 +16,29 @@ function deVideo(media) {
|
|
|
16
16
|
let media_deVideo = '';
|
|
17
17
|
$('img,video').each((_, medium) => {
|
|
18
18
|
const tag = medium.name;
|
|
19
|
-
|
|
20
|
-
const poster =
|
|
19
|
+
const mediumElement = $(medium);
|
|
20
|
+
const poster = mediumElement.attr('poster');
|
|
21
21
|
// 如果有 poster 属性,表明它是视频,将它替换为它的 poster;如果不是,就原样返回
|
|
22
|
-
media_deVideo +=
|
|
22
|
+
media_deVideo += (() => {
|
|
23
|
+
if (poster) {
|
|
24
|
+
return `<img src='${poster}' alt='video poster'>`;
|
|
25
|
+
} else if (tag === 'img') {
|
|
26
|
+
return mediumElement.toString();
|
|
27
|
+
} else {
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
23
31
|
});
|
|
24
32
|
return media_deVideo;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
export const route: Route = {
|
|
28
|
-
path: '/profile/:id/:functionalFlag?',
|
|
36
|
+
path: '/profile/:id/:type?/:functionalFlag?',
|
|
29
37
|
categories: ['social-media'],
|
|
30
38
|
example: '/picuki/profile/stefaniejoosten',
|
|
31
39
|
parameters: {
|
|
32
40
|
id: 'Instagram user id',
|
|
41
|
+
type: 'Type of profile page (profile or tagged)',
|
|
33
42
|
functionalFlag: `functional flag, see the table below
|
|
34
43
|
| functionalFlag | Video embedding | Fetching Instagram Stories |
|
|
35
44
|
| -------------- | --------------------------------------- | -------------------------- |
|
|
@@ -51,9 +60,13 @@ export const route: Route = {
|
|
|
51
60
|
source: ['www.picuki.com/profile/:id'],
|
|
52
61
|
target: '/profile/:id',
|
|
53
62
|
},
|
|
63
|
+
{
|
|
64
|
+
source: ['www.picuki.com/profile-tagged/:id'],
|
|
65
|
+
target: '/profile/:id/tagged',
|
|
66
|
+
},
|
|
54
67
|
],
|
|
55
68
|
name: 'User Profile - Picuki',
|
|
56
|
-
maintainers: ['hoilc', 'Rongronggg9', 'devinmugen'],
|
|
69
|
+
maintainers: ['hoilc', 'Rongronggg9', 'devinmugen', 'NekoAria'],
|
|
57
70
|
handler,
|
|
58
71
|
description: `
|
|
59
72
|
:::warning
|
|
@@ -67,61 +80,58 @@ async function handler(ctx) {
|
|
|
67
80
|
const browser = await puppeteer();
|
|
68
81
|
|
|
69
82
|
const id = ctx.req.param('id');
|
|
70
|
-
const
|
|
71
|
-
const
|
|
83
|
+
const type = ctx.req.param('type') ?? 'profile';
|
|
84
|
+
const functionalFlag = ctx.req.param('functionalFlag') ?? '1';
|
|
85
|
+
const displayVideo = functionalFlag !== '0';
|
|
86
|
+
const includeStories = functionalFlag === '10';
|
|
72
87
|
|
|
73
|
-
const profileUrl = `https://www.picuki.com
|
|
88
|
+
const profileUrl = `https://www.picuki.com/${type === 'tagged' ? 'profile-tagged' : 'profile'}/${id}`;
|
|
74
89
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
async () => {
|
|
78
|
-
const _r = await puppeteerGet(profileUrl, browser, includeStories);
|
|
79
|
-
return _r;
|
|
80
|
-
},
|
|
81
|
-
config.cache.routeExpire,
|
|
82
|
-
false
|
|
83
|
-
);
|
|
90
|
+
const key = `picuki-${id}-${type}-${includeStories}`;
|
|
91
|
+
const data = await cache.tryGet(key, () => puppeteerGet(profileUrl, browser, includeStories), config.cache.routeExpire, false);
|
|
84
92
|
const $ = load(data);
|
|
85
93
|
|
|
86
94
|
const profileName = $('.profile-name-bottom').text();
|
|
95
|
+
const profileTitle = type === 'tagged' ? `${profileName} (@${id}) tagged posts - Picuki` : `${profileName} (@${id}) public posts - Picuki`;
|
|
87
96
|
const profileImg = $('.profile-avatar > img').attr('src');
|
|
88
97
|
const profileDescription = $('.profile-description').text();
|
|
89
98
|
|
|
90
|
-
const list = $('ul.box-photos [data-s="media"]').
|
|
99
|
+
const list = $('ul.box-photos [data-s="media"]').toArray();
|
|
100
|
+
|
|
101
|
+
let items: DataItem[] = [];
|
|
91
102
|
|
|
92
|
-
let
|
|
103
|
+
let description: string;
|
|
93
104
|
|
|
94
105
|
if (includeStories) {
|
|
95
106
|
const stories_wrapper = $('.stories_wrapper');
|
|
96
107
|
if (stories_wrapper.length) {
|
|
97
108
|
const storyItems = $(stories_wrapper)
|
|
98
109
|
.find('.item')
|
|
99
|
-
.
|
|
110
|
+
.toArray()
|
|
100
111
|
.map((item) => {
|
|
101
112
|
const $item = $(item);
|
|
102
|
-
|
|
103
|
-
title =
|
|
104
|
-
const pubDate =
|
|
113
|
+
const titleElement = $item.find('.stories_count');
|
|
114
|
+
const title = titleElement.length ? titleElement.text() : '';
|
|
115
|
+
const pubDate = chrono.parseDate(title) || new Date();
|
|
105
116
|
const postBox = $item.find('.launchLightbox');
|
|
106
117
|
const poster = postBox.attr('data-video-poster');
|
|
107
118
|
const href = postBox.attr('href');
|
|
108
119
|
const type = postBox.attr('data-post-type'); // video / image
|
|
109
120
|
const origin = postBox.attr('data-origin');
|
|
110
121
|
const storiesBackground = $item.find('.stories_background');
|
|
111
|
-
const storiesBackgroundUrl = storiesBackground
|
|
112
|
-
const storiesBackgroundUrlSrc = storiesBackgroundUrl
|
|
113
|
-
let description;
|
|
122
|
+
const storiesBackgroundUrl = storiesBackground?.css('background-image')?.match(/url\('?(.*)'?\)/);
|
|
123
|
+
const storiesBackgroundUrlSrc = storiesBackgroundUrl?.[1];
|
|
114
124
|
if (type === 'video') {
|
|
115
125
|
description = art(path.join(__dirname, 'templates/video.art'), {
|
|
116
126
|
videoSrcs: [href, origin].filter(Boolean),
|
|
117
|
-
videoPoster: poster
|
|
127
|
+
videoPoster: poster ?? storiesBackgroundUrlSrc ?? '',
|
|
118
128
|
});
|
|
119
129
|
} else if (type === 'image') {
|
|
120
|
-
description = `<img src="${href
|
|
130
|
+
description = `<img src="${href ?? poster ?? storiesBackgroundUrlSrc ?? ''}" alt="Instagram Story">`;
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
return {
|
|
124
|
-
title:
|
|
134
|
+
title: title ? `Instagram Story: ${title}` : 'Instagram Story',
|
|
125
135
|
author: `@${id}`,
|
|
126
136
|
description,
|
|
127
137
|
link: href,
|
|
@@ -149,8 +159,8 @@ async function handler(ctx) {
|
|
|
149
159
|
$('.single-photo img').each((_, item) => {
|
|
150
160
|
html += $(item).toString();
|
|
151
161
|
});
|
|
152
|
-
$('.single-photo video').each((_,
|
|
153
|
-
item = $(
|
|
162
|
+
$('.single-photo video').each((_, element) => {
|
|
163
|
+
const item = $(element);
|
|
154
164
|
let videoSrc = item.attr('src');
|
|
155
165
|
if (videoSrc === undefined) {
|
|
156
166
|
videoSrc = item.children().attr('src');
|
|
@@ -158,8 +168,9 @@ async function handler(ctx) {
|
|
|
158
168
|
const videoPoster = item.attr('poster');
|
|
159
169
|
let origin = item.parent().attr('onclick');
|
|
160
170
|
if (origin) {
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
const regex = /window\.open\('([^']*)'/;
|
|
172
|
+
const match = regex.exec(origin);
|
|
173
|
+
origin = match?.[1];
|
|
163
174
|
}
|
|
164
175
|
html += art(path.join(__dirname, 'templates/video.art'), {
|
|
165
176
|
videoSrcs: [videoSrc, origin].filter(Boolean),
|
|
@@ -172,15 +183,15 @@ async function handler(ctx) {
|
|
|
172
183
|
items = [
|
|
173
184
|
...items,
|
|
174
185
|
...(await Promise.all(
|
|
175
|
-
list.map(async (
|
|
176
|
-
post = $(
|
|
186
|
+
list.map(async (item) => {
|
|
187
|
+
const post = $(item);
|
|
177
188
|
|
|
178
189
|
const postLink = post.find('.photo > a').attr('href');
|
|
179
190
|
const postTime = post.find('.time');
|
|
180
|
-
const pubDate = postTime ? chrono.parseDate(postTime.text()) : new Date();
|
|
191
|
+
const pubDate = postTime?.text() ? (chrono.parseDate(postTime.text()) ?? new Date()) : new Date();
|
|
181
192
|
const media_displayVideo = await getMedia(postLink);
|
|
182
193
|
const postText = post
|
|
183
|
-
.find('.photo-description')
|
|
194
|
+
.find('.photo-action-description')
|
|
184
195
|
.text()
|
|
185
196
|
.trim()
|
|
186
197
|
.replaceAll(/[^\S\n]+/g, ' ')
|
|
@@ -206,7 +217,7 @@ async function handler(ctx) {
|
|
|
206
217
|
await browser.close();
|
|
207
218
|
|
|
208
219
|
return {
|
|
209
|
-
title:
|
|
220
|
+
title: profileTitle,
|
|
210
221
|
link: profileUrl,
|
|
211
222
|
image: profileImg,
|
|
212
223
|
description: profileDescription,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Route, ViewType } from '@/types';
|
|
1
|
+
import { Route, ViewType, Data } from '@/types';
|
|
2
2
|
import got from '@/utils/got';
|
|
3
3
|
import { load } from 'cheerio';
|
|
4
4
|
import { isValidHost } from '@/utils/valid-host';
|
|
@@ -30,7 +30,7 @@ export const route: Route = {
|
|
|
30
30
|
handler,
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
async function handler(ctx) {
|
|
33
|
+
async function handler(ctx): Promise<Data> {
|
|
34
34
|
const { language = 'www', username, sort = '' } = ctx.req.param();
|
|
35
35
|
const link = `https://${language}.pornhub.com/model/${username}/videos${sort ? `?o=${sort}` : ''}`;
|
|
36
36
|
if (!isValidHost(language)) {
|
|
@@ -47,9 +47,7 @@ async function handler(ctx) {
|
|
|
47
47
|
title: $('h1').first().text(),
|
|
48
48
|
description: $('section.aboutMeSection').text().trim(),
|
|
49
49
|
link,
|
|
50
|
-
image: $('#
|
|
51
|
-
logo: $('#getAvatar').attr('src'),
|
|
52
|
-
icon: $('#getAvatar').attr('src'),
|
|
50
|
+
image: $('#getAvatar').attr('src'),
|
|
53
51
|
language: $('html').attr('lang'),
|
|
54
52
|
item: items,
|
|
55
53
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Route, ViewType } from '@/types';
|
|
1
|
+
import { Route, ViewType, Data } from '@/types';
|
|
2
2
|
import got from '@/utils/got';
|
|
3
3
|
import { load } from 'cheerio';
|
|
4
4
|
import { isValidHost } from '@/utils/valid-host';
|
|
@@ -73,7 +73,7 @@ export const route: Route = {
|
|
|
73
73
|
handler,
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
async function handler(ctx) {
|
|
76
|
+
async function handler(ctx): Promise<Data> {
|
|
77
77
|
const { language = 'www', username, sort = 'mr' } = ctx.req.param();
|
|
78
78
|
let link = `https://${language}.pornhub.com/pornstar/${username}?o=${sort}`;
|
|
79
79
|
if (!isValidHost(language)) {
|
|
@@ -101,9 +101,7 @@ async function handler(ctx) {
|
|
|
101
101
|
title: $('h1').first().text(),
|
|
102
102
|
description: $('section.aboutMeSection').text().trim(),
|
|
103
103
|
link,
|
|
104
|
-
image: $('#
|
|
105
|
-
logo: $('#getAvatar').attr('src'),
|
|
106
|
-
icon: $('#getAvatar').attr('src'),
|
|
104
|
+
image: $('#getAvatar').attr('src'),
|
|
107
105
|
language: $('html').attr('lang'),
|
|
108
106
|
item: items,
|
|
109
107
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Route } from '@/types';
|
|
1
|
+
import { Route, Data } from '@/types';
|
|
2
2
|
import got from '@/utils/got';
|
|
3
3
|
import { load } from 'cheerio';
|
|
4
4
|
import { isValidHost } from '@/utils/valid-host';
|
|
@@ -29,7 +29,7 @@ export const route: Route = {
|
|
|
29
29
|
handler,
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
async function handler(ctx) {
|
|
32
|
+
async function handler(ctx): Promise<Data> {
|
|
33
33
|
const { language = 'www', username } = ctx.req.param();
|
|
34
34
|
const link = `https://${language}.pornhub.com/users/${username}/videos`;
|
|
35
35
|
if (!isValidHost(language)) {
|
|
@@ -46,9 +46,7 @@ async function handler(ctx) {
|
|
|
46
46
|
title: $('.profileUserName a').text(),
|
|
47
47
|
description: $('.aboutMeText').text().trim(),
|
|
48
48
|
link,
|
|
49
|
-
image: $('#
|
|
50
|
-
logo: $('#getAvatar').attr('src'),
|
|
51
|
-
icon: $('#getAvatar').attr('src'),
|
|
49
|
+
image: $('#getAvatar').attr('src'),
|
|
52
50
|
language: $('html').attr('lang'),
|
|
53
51
|
allowEmpty: true,
|
|
54
52
|
item: items,
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
import cache from '@/utils/cache';
|
|
3
|
+
import got from '@/utils/got';
|
|
4
|
+
import { load } from 'cheerio';
|
|
5
|
+
// import { parseDate } from '@/utils/parse-date';
|
|
6
|
+
// import timezone from '@/utils/timezone';
|
|
7
|
+
|
|
8
|
+
const baseUrl = 'https://www.resonac.com';
|
|
9
|
+
const host = 'https://www.resonac.com/products?intcid=glnavi_products';
|
|
10
|
+
|
|
11
|
+
export const route: Route = {
|
|
12
|
+
path: '/products',
|
|
13
|
+
categories: ['other'],
|
|
14
|
+
example: '/resonac/products',
|
|
15
|
+
parameters: {},
|
|
16
|
+
features: {
|
|
17
|
+
requireConfig: false,
|
|
18
|
+
requirePuppeteer: true,
|
|
19
|
+
antiCrawler: false,
|
|
20
|
+
supportBT: false,
|
|
21
|
+
supportPodcast: false,
|
|
22
|
+
supportScihub: false,
|
|
23
|
+
},
|
|
24
|
+
name: 'Products',
|
|
25
|
+
maintainers: ['valuex'],
|
|
26
|
+
handler,
|
|
27
|
+
description: '',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
async function handler() {
|
|
31
|
+
const response = await got(host);
|
|
32
|
+
const pageHtml = response.data;
|
|
33
|
+
const $ = load(pageHtml);
|
|
34
|
+
const groupLists = $('div.m-panel-card-link ul li')
|
|
35
|
+
.toArray()
|
|
36
|
+
.map((el) => ({
|
|
37
|
+
groupName: $('a', el).text().trim(),
|
|
38
|
+
groupURL: baseUrl + $('a', el).attr('href'),
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
const lists = await Promise.all(
|
|
42
|
+
groupLists.map((productGroup) =>
|
|
43
|
+
cache.tryGet(productGroup.groupURL, async () => {
|
|
44
|
+
const strUrl = productGroup.groupURL;
|
|
45
|
+
const response = await got(strUrl);
|
|
46
|
+
const $ = load(response.data);
|
|
47
|
+
const item = $('dt.m-toggle__title div span a')
|
|
48
|
+
.toArray()
|
|
49
|
+
.map((el) => ({
|
|
50
|
+
title: $('b', el).text().trim(),
|
|
51
|
+
link: baseUrl + $(el).attr('href'),
|
|
52
|
+
group: productGroup.groupName,
|
|
53
|
+
}));
|
|
54
|
+
return item;
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const fullList = lists.flat(1); // flatten array
|
|
60
|
+
// fullList = fullList.filter((item) => item.title !== 'Empty');
|
|
61
|
+
|
|
62
|
+
const items = await Promise.all(
|
|
63
|
+
fullList.map((item) =>
|
|
64
|
+
cache.tryGet(item.link, async () => {
|
|
65
|
+
try {
|
|
66
|
+
const response = await got(item.link);
|
|
67
|
+
const $ = load(response.data);
|
|
68
|
+
const thisTitle = item.title + ' | ' + item.group;
|
|
69
|
+
item.title = thisTitle;
|
|
70
|
+
item.description = $('main div.str-section').html();
|
|
71
|
+
return item;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return (error as Error).message;
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
title: 'Resonac_Products',
|
|
81
|
+
link: baseUrl,
|
|
82
|
+
description: 'Resonac_Products',
|
|
83
|
+
item: items,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { Route } from '@/types';
|
|
1
|
+
import { DataItem, Route } from '@/types';
|
|
2
2
|
import got from '@/utils/got';
|
|
3
3
|
import { load } from 'cheerio';
|
|
4
4
|
import { config } from '@/config';
|
|
5
5
|
import ConfigNotFoundError from '@/errors/types/config-not-found';
|
|
6
|
+
import sanitizeHtml from 'sanitize-html';
|
|
7
|
+
import cache from '@/utils/cache';
|
|
6
8
|
|
|
7
9
|
export const route: Route = {
|
|
8
10
|
path: '/transform/html/:url/:routeParams',
|
|
@@ -23,24 +25,25 @@ export const route: Route = {
|
|
|
23
25
|
supportScihub: false,
|
|
24
26
|
},
|
|
25
27
|
name: 'Transformation - HTML',
|
|
26
|
-
maintainers: ['ttttmr'],
|
|
27
|
-
handler,
|
|
28
|
+
maintainers: ['ttttmr', 'hyoban'],
|
|
28
29
|
description: `Pass URL and transformation rules to convert HTML/JSON into RSS.
|
|
29
30
|
|
|
30
31
|
Specify options (in the format of query string) in parameter \`routeParams\` parameter to extract data from HTML.
|
|
31
32
|
|
|
32
|
-
| Key
|
|
33
|
-
|
|
|
34
|
-
| \`title\` | The title of the RSS
|
|
35
|
-
| \`item\` | The HTML elements as \`item\` using CSS selector
|
|
36
|
-
| \`itemTitle\` | The HTML elements as \`title\` in \`item\` using CSS selector
|
|
37
|
-
| \`itemTitleAttr\` | The attributes of \`title\` element as title
|
|
38
|
-
| \`itemLink\` | The HTML elements as \`link\` in \`item\` using CSS selector
|
|
39
|
-
| \`itemLinkAttr\` | The attributes of \`link\` element as link
|
|
40
|
-
| \`itemDesc\` | The HTML elements as \`descrption\` in \`item\` using CSS selector
|
|
41
|
-
| \`itemDescAttr\` | The attributes of \`descrption\` element as description
|
|
42
|
-
| \`itemPubDate\` | The HTML elements as \`pubDate\` in \`item\` using CSS selector
|
|
43
|
-
| \`itemPubDateAttr\` | The attributes of \`pubDate\` element as pubDate
|
|
33
|
+
| Key | Meaning | Accepted Values | Default |
|
|
34
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------ |
|
|
35
|
+
| \`title\` | The title of the RSS | \`string\` | Extract from \`<title>\` |
|
|
36
|
+
| \`item\` | The HTML elements as \`item\` using CSS selector | \`string\` | html |
|
|
37
|
+
| \`itemTitle\` | The HTML elements as \`title\` in \`item\` using CSS selector | \`string\` | \`item\` element |
|
|
38
|
+
| \`itemTitleAttr\` | The attributes of \`title\` element as title | \`string\` | Element text |
|
|
39
|
+
| \`itemLink\` | The HTML elements as \`link\` in \`item\` using CSS selector | \`string\` | \`item\` element |
|
|
40
|
+
| \`itemLinkAttr\` | The attributes of \`link\` element as link | \`string\` | \`href\` |
|
|
41
|
+
| \`itemDesc\` | The HTML elements as \`descrption\` in \`item\` using CSS selector | \`string\` | \`item\` element |
|
|
42
|
+
| \`itemDescAttr\` | The attributes of \`descrption\` element as description | \`string\` | Element html |
|
|
43
|
+
| \`itemPubDate\` | The HTML elements as \`pubDate\` in \`item\` using CSS selector | \`string\` | \`item\` element |
|
|
44
|
+
| \`itemPubDateAttr\` | The attributes of \`pubDate\` element as pubDate | \`string\` | Element html |
|
|
45
|
+
| \`itemContent\` | The HTML elements as \`description\` in \`item\` using CSS selector ( in \`itemLink\` page for full content ) | \`string\` | |
|
|
46
|
+
| \`encoding\` | The encoding of the HTML content | \`string\` | utf-8 |
|
|
44
47
|
|
|
45
48
|
Parameters parsing in the above example:
|
|
46
49
|
|
|
@@ -54,66 +57,102 @@ Specify options (in the format of query string) in parameter \`routeParams\` par
|
|
|
54
57
|
| Parameter | Value |
|
|
55
58
|
| --------- | ------------------------------- |
|
|
56
59
|
| \`item\` | \`div[class='post-content'] p a\` |`,
|
|
57
|
-
|
|
60
|
+
handler: async (ctx) => {
|
|
61
|
+
if (!config.feature.allow_user_supply_unsafe_domain) {
|
|
62
|
+
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
|
63
|
+
}
|
|
64
|
+
const url = ctx.req.param('url');
|
|
65
|
+
const response = await got({
|
|
66
|
+
method: 'get',
|
|
67
|
+
url,
|
|
68
|
+
responseType: 'arrayBuffer',
|
|
69
|
+
});
|
|
58
70
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
link
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
71
|
+
const routeParams = new URLSearchParams(ctx.req.param('routeParams'));
|
|
72
|
+
const encoding = routeParams.get('encoding') || 'utf-8';
|
|
73
|
+
const decoder = new TextDecoder(encoding);
|
|
74
|
+
|
|
75
|
+
const $ = load(decoder.decode(response.data));
|
|
76
|
+
const rssTitle = routeParams.get('title') || $('title').text();
|
|
77
|
+
const item = routeParams.get('item') || 'html';
|
|
78
|
+
let items: DataItem[] = $(item)
|
|
79
|
+
.toArray()
|
|
80
|
+
.slice(0, 20)
|
|
81
|
+
.map((item) => {
|
|
82
|
+
try {
|
|
83
|
+
item = $(item);
|
|
84
|
+
|
|
85
|
+
const titleEle = routeParams.get('itemTitle') ? item.find(routeParams.get('itemTitle')) : item;
|
|
86
|
+
const title = routeParams.get('itemTitleAttr') ? titleEle.attr(routeParams.get('itemTitleAttr')) : titleEle.text();
|
|
87
|
+
|
|
88
|
+
let link;
|
|
89
|
+
const linkEle = routeParams.get('itemLink') ? item.find(routeParams.get('itemLink')) : item;
|
|
90
|
+
if (routeParams.get('itemLinkAttr')) {
|
|
91
|
+
link = linkEle.attr(routeParams.get('itemLinkAttr'));
|
|
92
|
+
} else {
|
|
93
|
+
link = linkEle.is('a') ? linkEle.attr('href') : linkEle.find('a').attr('href');
|
|
94
|
+
}
|
|
95
|
+
// 补全绝对链接
|
|
96
|
+
link = link.trim();
|
|
97
|
+
if (link && !link.startsWith('http')) {
|
|
98
|
+
link = `${new URL(url).origin}${link}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const descEle = routeParams.get('itemDesc') ? item.find(routeParams.get('itemDesc')) : item;
|
|
102
|
+
const desc = routeParams.get('itemDescAttr') ? descEle.attr(routeParams.get('itemDescAttr')) : descEle.html();
|
|
103
|
+
|
|
104
|
+
const pubDateEle = routeParams.get('itemPubDate') ? item.find(routeParams.get('itemPubDate')) : item;
|
|
105
|
+
const pubDate = routeParams.get('itemPubDateAttr') ? pubDateEle.attr(routeParams.get('itemPubDateAttr')) : pubDateEle.html();
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
title,
|
|
109
|
+
link,
|
|
110
|
+
description: desc,
|
|
111
|
+
pubDate,
|
|
112
|
+
};
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
93
115
|
}
|
|
116
|
+
})
|
|
117
|
+
.filter((i) => !!i);
|
|
94
118
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
link,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
119
|
+
const itemContentSelector = routeParams.get('itemContent');
|
|
120
|
+
if (itemContentSelector) {
|
|
121
|
+
items = await Promise.all(
|
|
122
|
+
items.map((item) => {
|
|
123
|
+
if (!item.link) {
|
|
124
|
+
return item;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return cache.tryGet(item.link, async () => {
|
|
128
|
+
const response = await got({
|
|
129
|
+
method: 'get',
|
|
130
|
+
url: item.link,
|
|
131
|
+
responseType: 'arrayBuffer',
|
|
132
|
+
});
|
|
133
|
+
if (!response || typeof response === 'string') {
|
|
134
|
+
return item;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const $ = load(decoder.decode(response.data));
|
|
138
|
+
const content = $(itemContentSelector).html();
|
|
139
|
+
if (!content) {
|
|
140
|
+
return item;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
item.description = sanitizeHtml(content, { allowedTags: [...sanitizeHtml.defaults.allowedTags, 'img'] });
|
|
144
|
+
|
|
145
|
+
return item;
|
|
146
|
+
});
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
title: rssTitle,
|
|
153
|
+
link: url,
|
|
154
|
+
description: `Proxy ${url}`,
|
|
155
|
+
item: items,
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
};
|
|
@@ -39,14 +39,15 @@ export const route: Route = {
|
|
|
39
39
|
handler,
|
|
40
40
|
description: `Specify options (in the format of query string) in parameter \`routeParams\` parameter to extract data from JSON.
|
|
41
41
|
|
|
42
|
-
| Key
|
|
43
|
-
|
|
|
44
|
-
| \`title\`
|
|
45
|
-
| \`item\`
|
|
46
|
-
| \`itemTitle\`
|
|
47
|
-
| \`itemLink\`
|
|
48
|
-
| \`
|
|
49
|
-
| \`
|
|
42
|
+
| Key | Meaning | Accepted Values | Default |
|
|
43
|
+
| ------------------ | -------------------------------------------- | ----------------- | ------------------------------------------ |
|
|
44
|
+
| \`title\` | The title of the RSS | \`string\` | Extracted from home page of current domain |
|
|
45
|
+
| \`item\` | The JSON Path as \`item\` element | \`string\` | Entire JSON response |
|
|
46
|
+
| \`itemTitle\` | The JSON Path as \`title\` in \`item\` | \`string\` | None |
|
|
47
|
+
| \`itemLink\` | The JSON Path as \`link\` in \`item\` | \`string\` | None |
|
|
48
|
+
| \`itemLinkPrefix\` | Optional Prefix for \`itemLink\` value | \`string\` | None |
|
|
49
|
+
| \`itemDesc\` | The JSON Path as \`description\` in \`item\` | \`string\` | None |
|
|
50
|
+
| \`itemPubDate\` | The JSON Path as \`pubDate\` in \`item\` | \`string\` | None |
|
|
50
51
|
|
|
51
52
|
:::tip
|
|
52
53
|
JSON Path only supports format like \`a.b.c\`. if you need to access arrays, like \`a[0].b\`, you can write it as \`a.0.b\`.
|
|
@@ -92,6 +93,11 @@ async function handler(ctx) {
|
|
|
92
93
|
|
|
93
94
|
const items = jsonGet(response.data, routeParams.get('item')).map((item) => {
|
|
94
95
|
let link = jsonGet(item, routeParams.get('itemLink')).trim();
|
|
96
|
+
const linkPrefix = routeParams.get('itemLinkPrefix');
|
|
97
|
+
|
|
98
|
+
if (link && linkPrefix) {
|
|
99
|
+
link = `${linkPrefix}${link}`;
|
|
100
|
+
}
|
|
95
101
|
// 补全绝对链接
|
|
96
102
|
if (link && !link.startsWith('http')) {
|
|
97
103
|
link = `${new URL(url).origin}${link}`;
|
|
@@ -31,6 +31,7 @@ export const route: Route = {
|
|
|
31
31
|
|
|
32
32
|
async function handler(ctx) {
|
|
33
33
|
const id = ctx.req.param('id');
|
|
34
|
+
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50;
|
|
34
35
|
|
|
35
36
|
const rootUrl = 'https://blog.sciencenet.cn';
|
|
36
37
|
const currentUrl = `${rootUrl}/u/${id}`;
|
|
@@ -51,8 +52,9 @@ async function handler(ctx) {
|
|
|
51
52
|
$ = load(response.data);
|
|
52
53
|
|
|
53
54
|
let items = $('item')
|
|
54
|
-
.slice(
|
|
55
|
+
.slice(-limit)
|
|
55
56
|
.toArray()
|
|
57
|
+
.reverse()
|
|
56
58
|
.map((item) => {
|
|
57
59
|
item = $(item);
|
|
58
60
|
|