rsshub 1.0.0-master.f6cb490 → 1.0.0-master.f6f0273
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/api/index.ts +1 -6
- package/lib/routes/2048/index.ts +24 -23
- package/lib/routes/anthropic/news.ts +27 -13
- package/lib/routes/asianfanfics/namespace.ts +7 -0
- package/lib/routes/asianfanfics/tag.ts +89 -0
- package/lib/routes/asianfanfics/text-search.ts +68 -0
- package/lib/routes/blockworks/index.ts +128 -0
- package/lib/routes/blockworks/namespace.ts +7 -0
- package/lib/routes/cmu/andypavlo/blog.ts +55 -0
- package/lib/routes/cmu/namespace.ts +7 -0
- package/lib/routes/coindesk/{index.ts → consensus-magazine.ts} +17 -21
- package/lib/routes/coindesk/namespace.ts +2 -1
- package/lib/routes/coindesk/news.ts +47 -0
- package/lib/routes/coindesk/utils.ts +26 -0
- package/lib/routes/cointelegraph/index.ts +106 -0
- package/lib/routes/cointelegraph/namespace.ts +7 -0
- package/lib/routes/collabo-cafe/category.ts +37 -0
- package/lib/routes/collabo-cafe/index.ts +35 -0
- package/lib/routes/collabo-cafe/namespace.ts +9 -0
- package/lib/routes/collabo-cafe/parser.ts +29 -0
- package/lib/routes/collabo-cafe/tag.ts +37 -0
- package/lib/routes/cryptoslate/index.ts +98 -0
- package/lib/routes/cryptoslate/namespace.ts +7 -0
- package/lib/routes/decrypt/index.ts +115 -0
- package/lib/routes/decrypt/namespace.ts +7 -0
- package/lib/routes/discuz/discuz.ts +7 -9
- package/lib/routes/fangchan/list.ts +224 -0
- package/lib/routes/fangchan/namespace.ts +9 -0
- package/lib/routes/fangchan/templates/description.art +7 -0
- package/lib/routes/foreignaffairs/namespace.ts +7 -0
- package/lib/routes/foreignaffairs/rss.ts +55 -0
- package/lib/routes/forklog/index.ts +72 -0
- package/lib/routes/forklog/namespace.ts +7 -0
- package/lib/routes/gcores/categories.ts +129 -0
- package/lib/routes/gcores/collections.ts +129 -0
- package/lib/routes/gcores/topics.ts +63 -0
- package/lib/routes/gov/moa/gjs.ts +210 -0
- package/lib/routes/gov/tianjin/tjftz.ts +53 -0
- package/lib/routes/gov/tianjin/tjrcgzw.ts +51 -0
- package/lib/routes/grainoil/category.ts +207 -0
- package/lib/routes/grainoil/namespace.ts +9 -0
- package/lib/routes/huxiu/util.ts +11 -9
- package/lib/routes/ifanr/category.ts +7 -2
- package/lib/routes/ifanr/digest.ts +1 -1
- package/lib/routes/ifanr/index.ts +1 -1
- package/lib/routes/instructables/projects.ts +20 -15
- package/lib/routes/juejin/collections.ts +1 -1
- package/lib/routes/komiic/comic.ts +88 -0
- package/lib/routes/komiic/namespace.ts +7 -0
- package/lib/routes/leagueoflegends/namespace.ts +8 -0
- package/lib/routes/leagueoflegends/patch-notes.ts +76 -0
- package/lib/routes/likeshop/index.ts +43 -0
- package/lib/routes/likeshop/namespace.ts +7 -0
- package/lib/routes/ltaaa/article.ts +180 -0
- package/lib/routes/ltaaa/namespace.ts +9 -0
- package/lib/routes/ltaaa/templates/description.art +7 -0
- package/lib/routes/mashiro/index.ts +1 -0
- package/lib/routes/nhentai/util.ts +4 -1
- package/lib/routes/pinterest/user.ts +9 -0
- package/lib/routes/sohu/mp.ts +3 -2
- package/lib/routes/spotify/show.ts +1 -1
- package/lib/routes/stcn/index.ts +241 -136
- package/lib/routes/stcn/kx.ts +144 -0
- package/lib/routes/swjtu/namespace.ts +1 -1
- package/lib/routes/swjtu/{scai/bks.ts → scai.ts} +34 -20
- package/lib/routes/swjtu/sports.ts +77 -0
- package/lib/routes/theblock/index.ts +142 -0
- package/lib/routes/theblock/namespace.ts +7 -0
- package/lib/routes/theverge/index.ts +73 -62
- package/lib/routes/theverge/templates/header.art +19 -0
- package/lib/routes/threads/index.ts +73 -54
- package/lib/routes/threads/utils.ts +60 -78
- package/lib/routes/tmtpost/column.ts +298 -0
- package/lib/routes/tmtpost/new.ts +4 -199
- package/lib/routes/tmtpost/util.ts +207 -0
- package/lib/routes/toranoana/namespace.ts +7 -0
- package/lib/routes/toranoana/news.ts +110 -0
- package/lib/routes/wainao/templates/description.art +9 -0
- package/lib/routes/wainao/topics.ts +214 -0
- package/lib/routes/xiaoyuzhou/podcast.ts +27 -27
- package/lib/routes/xjtu/yz.ts +74 -0
- package/lib/routes/youmemark/index.ts +6 -6
- package/lib/routes/zaobao/util.ts +11 -3
- package/lib/routes/zhihu/answers.ts +26 -54
- package/package.json +36 -35
- package/lib/routes/gcores/category.ts +0 -171
- package/lib/routes/gcores/collection.ts +0 -161
- package/lib/routes-deprecated/ltaaa/index.js +0 -69
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Route } from '@/types';
|
|
2
|
-
import
|
|
2
|
+
import ofetch from '@/utils/ofetch';
|
|
3
|
+
import { load } from 'cheerio';
|
|
4
|
+
import { parseDate } from '@/utils/parse-date';
|
|
3
5
|
|
|
4
6
|
export const route: Route = {
|
|
5
7
|
path: '/projects/:category?',
|
|
@@ -30,10 +32,10 @@ export const route: Route = {
|
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
async function handler(ctx) {
|
|
33
|
-
const category = ctx.req.param(
|
|
35
|
+
const { category = 'all' } = ctx.req.param();
|
|
36
|
+
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 50;
|
|
34
37
|
|
|
35
|
-
const siteDomain = '
|
|
36
|
-
const apiKey = 'NU5CdGwyRDdMVnVmM3l4cWNqQzFSVzJNZU5jaUxFU3dGK3J2L203MkVmVT02ZWFYeyJleGNsdWRlX2ZpZWxkcyI6WyJvdXRfb2YiLCJzZWFyY2hfdGltZV9tcyIsInN0ZXBCb2R5Il0sInBlcl9wYWdlIjo1MH0=';
|
|
38
|
+
const siteDomain = 'instructables.com';
|
|
37
39
|
|
|
38
40
|
let pathPrefix, projectFilter;
|
|
39
41
|
if (category === 'all') {
|
|
@@ -45,32 +47,35 @@ async function handler(ctx) {
|
|
|
45
47
|
projectFilter = category === 'teachers' ? `&& teachers:=${filterValue}` : ` && category:=${filterValue}`;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
const
|
|
50
|
+
const pageLink = `https://${siteDomain}/${pathPrefix}projects`;
|
|
49
51
|
|
|
50
|
-
const
|
|
52
|
+
const pageResponse = await ofetch(pageLink);
|
|
53
|
+
const $ = load(pageResponse);
|
|
54
|
+
const { typesenseProxy, typesenseApiKey } = JSON.parse($('script#js-page-context').text());
|
|
55
|
+
|
|
56
|
+
const data = await ofetch(`${typesenseProxy}/collections/projects/documents/search`, {
|
|
51
57
|
method: 'get',
|
|
52
|
-
|
|
58
|
+
baseURL: `https://${siteDomain}`,
|
|
53
59
|
headers: {
|
|
54
|
-
Referer:
|
|
60
|
+
Referer: pageLink,
|
|
55
61
|
Host: siteDomain,
|
|
56
|
-
'x-typesense-api-key':
|
|
62
|
+
'x-typesense-api-key': typesenseApiKey,
|
|
57
63
|
},
|
|
58
|
-
|
|
64
|
+
query: {
|
|
59
65
|
q: '*',
|
|
60
66
|
query_by: 'title,stepBody,screenName',
|
|
61
67
|
page: 1,
|
|
62
|
-
per_page:
|
|
68
|
+
per_page: limit,
|
|
63
69
|
sort_by: 'publishDate:desc',
|
|
64
70
|
include_fields: 'title,urlString,coverImageUrl,screenName,publishDate,favorites,views,primaryClassification,featureFlag,prizeLevel,IMadeItCount',
|
|
65
71
|
filter_by: `featureFlag:=true${projectFilter}`,
|
|
66
72
|
},
|
|
73
|
+
parseResponse: JSON.parse,
|
|
67
74
|
});
|
|
68
75
|
|
|
69
|
-
const data = response.data;
|
|
70
|
-
|
|
71
76
|
return {
|
|
72
77
|
title: 'Instructables Projects', // 项目的标题
|
|
73
|
-
link
|
|
78
|
+
link: `https://${siteDomain}/projects`, // 指向项目的链接
|
|
74
79
|
description: 'Instructables Projects', // 描述项目
|
|
75
80
|
language: 'en', // 频道语言
|
|
76
81
|
item: data.hits.map((item) => ({
|
|
@@ -78,7 +83,7 @@ async function handler(ctx) {
|
|
|
78
83
|
link: `https://${siteDomain}/${item.document.urlString}`,
|
|
79
84
|
author: item.document.screenName,
|
|
80
85
|
description: `<img src="${item.document.coverImageUrl}?auto=webp&crop=1.2%3A1&frame=1&width=500" width="500">`,
|
|
81
|
-
pubDate:
|
|
86
|
+
pubDate: parseDate(item.document.publishDate),
|
|
82
87
|
category: item.document.primaryClassification,
|
|
83
88
|
})),
|
|
84
89
|
};
|
|
@@ -42,7 +42,7 @@ async function handler(ctx) {
|
|
|
42
42
|
const collectionId = response.data.map((item) => item.tag_id);
|
|
43
43
|
|
|
44
44
|
const temp = (await Promise.all(collectionId.map((id) => getArticleList(id)))) as Article[][];
|
|
45
|
-
const posts = temp.flat();
|
|
45
|
+
const posts = temp.flat().filter(Boolean);
|
|
46
46
|
const list = parseList(posts);
|
|
47
47
|
|
|
48
48
|
const result = await ProcessFeed(list);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
import { parseDate } from '@/utils/parse-date';
|
|
3
|
+
import got from '@/utils/got';
|
|
4
|
+
|
|
5
|
+
export const route: Route = {
|
|
6
|
+
path: '/comic/:id',
|
|
7
|
+
categories: ['anime'],
|
|
8
|
+
example: '/komiic/comic/533',
|
|
9
|
+
parameters: { id: '漫画 ID' },
|
|
10
|
+
features: {
|
|
11
|
+
requireConfig: false,
|
|
12
|
+
requirePuppeteer: false,
|
|
13
|
+
antiCrawler: false,
|
|
14
|
+
supportBT: false,
|
|
15
|
+
supportPodcast: false,
|
|
16
|
+
supportScihub: false,
|
|
17
|
+
},
|
|
18
|
+
radar: [
|
|
19
|
+
{
|
|
20
|
+
source: ['komiic.com/comic/:id'],
|
|
21
|
+
target: '/comic/:id',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
name: '漫画更新',
|
|
25
|
+
maintainers: ['NekoAria'],
|
|
26
|
+
handler,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async function handler(ctx) {
|
|
30
|
+
const { id } = ctx.req.param();
|
|
31
|
+
const { limit = 0 } = ctx.req.query();
|
|
32
|
+
const baseUrl = 'https://komiic.com';
|
|
33
|
+
|
|
34
|
+
const { data: comicInfo } = await got.post(`${baseUrl}/api/query`, {
|
|
35
|
+
json: {
|
|
36
|
+
operationName: 'comicById',
|
|
37
|
+
variables: { comicId: id },
|
|
38
|
+
query: `query comicById($comicId: ID!) {
|
|
39
|
+
comicById(comicId: $comicId) {
|
|
40
|
+
title
|
|
41
|
+
imageUrl
|
|
42
|
+
}
|
|
43
|
+
}`,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const { title, imageUrl } = comicInfo.data.comicById;
|
|
48
|
+
|
|
49
|
+
const { data: chapterData } = await got.post(`${baseUrl}/api/query`, {
|
|
50
|
+
json: {
|
|
51
|
+
operationName: 'chapterByComicId',
|
|
52
|
+
variables: { comicId: id },
|
|
53
|
+
query: `query chapterByComicId($comicId: ID!) {
|
|
54
|
+
chaptersByComicId(comicId: $comicId) {
|
|
55
|
+
id
|
|
56
|
+
serial
|
|
57
|
+
type
|
|
58
|
+
dateUpdated
|
|
59
|
+
size
|
|
60
|
+
}
|
|
61
|
+
}`,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const sortedChapters = chapterData.data.chaptersByComicId.sort((a, b) => Date.parse(b.dateUpdated) - Date.parse(a.dateUpdated));
|
|
66
|
+
|
|
67
|
+
const chapterLimit = Number(limit) || sortedChapters.length;
|
|
68
|
+
const filteredChapters = sortedChapters.slice(0, chapterLimit);
|
|
69
|
+
|
|
70
|
+
const generateChapterDescription = (chapter) =>
|
|
71
|
+
`
|
|
72
|
+
<h1>${chapter.size}p</h1>
|
|
73
|
+
<img src="${imageUrl}" />
|
|
74
|
+
`.trim();
|
|
75
|
+
|
|
76
|
+
const items = filteredChapters.map((chapter) => ({
|
|
77
|
+
title: chapter.type === 'book' ? `第 ${chapter.serial} 卷` : `第 ${chapter.serial} 话`,
|
|
78
|
+
link: `${baseUrl}/comic/${id}/chapter/${chapter.id}/images/all`,
|
|
79
|
+
pubDate: parseDate(chapter.dateUpdated),
|
|
80
|
+
description: generateChapterDescription(chapter),
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
title: `Komiic - ${title}`,
|
|
85
|
+
link: `${baseUrl}/comic/${id}`,
|
|
86
|
+
item: items,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { DataItem, Route } from '@/types';
|
|
2
|
+
import got from '@/utils/got';
|
|
3
|
+
import { load } from 'cheerio';
|
|
4
|
+
import { parseDate } from '@/utils/parse-date';
|
|
5
|
+
|
|
6
|
+
export const route: Route = {
|
|
7
|
+
path: '/patch-notes',
|
|
8
|
+
categories: ['game'],
|
|
9
|
+
example: '/leagueoflegends/patch-notes',
|
|
10
|
+
radar: [
|
|
11
|
+
{
|
|
12
|
+
source: ['www.leagueoflegends.com/en-us/news/tags/patch-notes/', 'www.leagueoflegends.com/en-us/news/game-updates/:postSlug'],
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
name: 'Patch Notes',
|
|
16
|
+
maintainers: ['noahm'],
|
|
17
|
+
async handler() {
|
|
18
|
+
const url = 'https://www.leagueoflegends.com/en-us/news/tags/patch-notes/';
|
|
19
|
+
const response = await got({
|
|
20
|
+
method: 'get',
|
|
21
|
+
url,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const data = response.data;
|
|
25
|
+
|
|
26
|
+
const $ = load(data);
|
|
27
|
+
const nextData = $('script[id="__NEXT_DATA__"]').text();
|
|
28
|
+
if (!nextData) {
|
|
29
|
+
throw new Error('missing next data');
|
|
30
|
+
}
|
|
31
|
+
const list: PatchNotesItem[] = JSON.parse(nextData).props.pageProps.page.blades[2].items;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
title: 'League of Legends Patch Notes',
|
|
35
|
+
link: url,
|
|
36
|
+
item: list.map(
|
|
37
|
+
(item): DataItem => ({
|
|
38
|
+
title: item.title,
|
|
39
|
+
description: item.description.body,
|
|
40
|
+
pubDate: parseDate(item.publishedAt),
|
|
41
|
+
link: item.action.payload.url,
|
|
42
|
+
guid: item.analytics.contentId,
|
|
43
|
+
image: item.media.url,
|
|
44
|
+
itunes_item_image: item.media.url,
|
|
45
|
+
})
|
|
46
|
+
),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// partial type definition of JSON data pre-filled on the page
|
|
52
|
+
interface PatchNotesItem {
|
|
53
|
+
title: string;
|
|
54
|
+
publishedAt: string;
|
|
55
|
+
description: {
|
|
56
|
+
type: 'html';
|
|
57
|
+
body: string;
|
|
58
|
+
};
|
|
59
|
+
media: {
|
|
60
|
+
dimensions: {
|
|
61
|
+
height: number;
|
|
62
|
+
width: number;
|
|
63
|
+
};
|
|
64
|
+
mimeType: string;
|
|
65
|
+
url: string;
|
|
66
|
+
};
|
|
67
|
+
action: {
|
|
68
|
+
payload: {
|
|
69
|
+
url: string;
|
|
70
|
+
};
|
|
71
|
+
type: 'weblink';
|
|
72
|
+
};
|
|
73
|
+
analytics: {
|
|
74
|
+
contentId: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
import ofetch from '@/utils/ofetch';
|
|
3
|
+
|
|
4
|
+
export const route: Route = {
|
|
5
|
+
path: '/:site',
|
|
6
|
+
categories: ['social-media'],
|
|
7
|
+
example: '/likeshop/bloombergpursuits',
|
|
8
|
+
parameters: { site: 'the site attached to likeshop.me/' },
|
|
9
|
+
radar: [
|
|
10
|
+
{
|
|
11
|
+
source: ['likeshop.me/'],
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
features: {
|
|
15
|
+
requireConfig: false,
|
|
16
|
+
requirePuppeteer: false,
|
|
17
|
+
antiCrawler: false,
|
|
18
|
+
supportBT: false,
|
|
19
|
+
supportPodcast: false,
|
|
20
|
+
supportScihub: false,
|
|
21
|
+
},
|
|
22
|
+
name: 'Posts',
|
|
23
|
+
maintainers: ['nickyfoto'],
|
|
24
|
+
handler,
|
|
25
|
+
description: 'LikeShop link in bio takes your audience from Instagram and TikTok to your website in one easy step.',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
async function handler(ctx) {
|
|
29
|
+
const site = ctx.req.param('site');
|
|
30
|
+
const link = `https://api.likeshop.me/api/accounts/${site}/galleries/likeshop`;
|
|
31
|
+
const data = await ofetch(link);
|
|
32
|
+
const items = data.data.media.map((item) => ({
|
|
33
|
+
title: item.comment,
|
|
34
|
+
link: item.product_url.split('?')[0],
|
|
35
|
+
description: `<p><img src="${item.image_url.split('?')[0]}"></p>`,
|
|
36
|
+
guid: item.id,
|
|
37
|
+
}));
|
|
38
|
+
return {
|
|
39
|
+
title: `@${site} Likeshop`,
|
|
40
|
+
link: `https://likeshop.me/${site}`,
|
|
41
|
+
item: items,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { type Data, type DataItem, type Route, ViewType } from '@/types';
|
|
2
|
+
|
|
3
|
+
import { art } from '@/utils/render';
|
|
4
|
+
import cache from '@/utils/cache';
|
|
5
|
+
import { getCurrentPath } from '@/utils/helpers';
|
|
6
|
+
import ofetch from '@/utils/ofetch';
|
|
7
|
+
import { parseDate } from '@/utils/parse-date';
|
|
8
|
+
|
|
9
|
+
import { type CheerioAPI, type Cheerio, type Element, load } from 'cheerio';
|
|
10
|
+
import { type Context } from 'hono';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
|
|
13
|
+
const __dirname = getCurrentPath(import.meta.url);
|
|
14
|
+
|
|
15
|
+
export const handler = async (ctx: Context): Promise<Data> => {
|
|
16
|
+
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
|
|
17
|
+
|
|
18
|
+
const baseUrl: string = 'https://www.ltaaa.cn';
|
|
19
|
+
const targetUrl: string = new URL('article', baseUrl).href;
|
|
20
|
+
|
|
21
|
+
const response = await ofetch(targetUrl);
|
|
22
|
+
const $: CheerioAPI = load(response);
|
|
23
|
+
const language = $('html').attr('lang') ?? 'zh-CN';
|
|
24
|
+
|
|
25
|
+
let items: DataItem[] = [];
|
|
26
|
+
|
|
27
|
+
items = $('ul.wlist li')
|
|
28
|
+
.slice(0, limit)
|
|
29
|
+
.toArray()
|
|
30
|
+
.map((el): Element => {
|
|
31
|
+
const $el: Cheerio<Element> = $(el);
|
|
32
|
+
|
|
33
|
+
const $aEl: Cheerio<Element> = $el.find('div.li-title a');
|
|
34
|
+
|
|
35
|
+
const title: string = $aEl.text();
|
|
36
|
+
const description: string = art(path.join(__dirname, 'templates/description.art'), {
|
|
37
|
+
intro: $el.find('div.dbody p').first().text(),
|
|
38
|
+
});
|
|
39
|
+
const pubDateStr: string | undefined = $el.find('i.icon-time').next().text().trim();
|
|
40
|
+
const linkUrl: string | undefined = $aEl.attr('href');
|
|
41
|
+
const authorEls: Element[] = $el.find('i.icon-user').parent().find('a').toArray();
|
|
42
|
+
const authors: DataItem['author'] = authorEls.map((authorEl) => {
|
|
43
|
+
const $authorEl: Cheerio<Element> = $(authorEl);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
name: $authorEl.text(),
|
|
47
|
+
url: new URL($authorEl.attr('href') ?? '', baseUrl).href,
|
|
48
|
+
avatar: undefined,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
const image: string | undefined = $el.find('div.li-thumb img').attr('src');
|
|
52
|
+
const upDatedStr: string | undefined = pubDateStr;
|
|
53
|
+
|
|
54
|
+
const processedItem: DataItem = {
|
|
55
|
+
title,
|
|
56
|
+
description,
|
|
57
|
+
pubDate: pubDateStr ? parseDate(pubDateStr) : undefined,
|
|
58
|
+
link: linkUrl ? new URL(linkUrl, baseUrl).href : undefined,
|
|
59
|
+
author: authors,
|
|
60
|
+
content: {
|
|
61
|
+
html: description,
|
|
62
|
+
text: description,
|
|
63
|
+
},
|
|
64
|
+
image,
|
|
65
|
+
banner: image,
|
|
66
|
+
updated: upDatedStr ? parseDate(upDatedStr) : undefined,
|
|
67
|
+
language,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return processedItem;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
items = (
|
|
74
|
+
await Promise.all(
|
|
75
|
+
items.map((item) => {
|
|
76
|
+
if (!item.link) {
|
|
77
|
+
return item;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
|
81
|
+
const detailResponse = await ofetch(item.link);
|
|
82
|
+
const $$: CheerioAPI = load(detailResponse);
|
|
83
|
+
|
|
84
|
+
const title: string = $$('div.post-title').text();
|
|
85
|
+
|
|
86
|
+
const pubDateStr: string | undefined = $$('i.icon-time').next().text().trim();
|
|
87
|
+
const categoryEls: Element[] = $$('span.keywords a').toArray();
|
|
88
|
+
const categories: string[] = [...new Set(categoryEls.map((el) => $$(el).text()).filter(Boolean))];
|
|
89
|
+
const authorEls: Element[] = $$('i.icon-user').first().nextAll('a').toArray();
|
|
90
|
+
const authors: DataItem['author'] = authorEls.map((authorEl) => {
|
|
91
|
+
const $$authorEl: Cheerio<Element> = $$(authorEl);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
name: $$authorEl.text(),
|
|
95
|
+
url: new URL($$authorEl.attr('href') ?? '', baseUrl).href,
|
|
96
|
+
avatar: undefined,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
const upDatedStr: string | undefined = pubDateStr;
|
|
100
|
+
|
|
101
|
+
$$('div.post-tip').each((_, el) => {
|
|
102
|
+
const $$el: Cheerio<Element> = $$(el);
|
|
103
|
+
const content: string = $$el.html() ?? '';
|
|
104
|
+
|
|
105
|
+
if (content) {
|
|
106
|
+
$$el.replaceWith(`<h1>${content}</h1>`);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
$$('div.post-param, div.post-title, div.post-keywords').remove();
|
|
110
|
+
$$('div.attitude, div.clear').remove();
|
|
111
|
+
|
|
112
|
+
const description: string = art(path.join(__dirname, 'templates/description.art'), {
|
|
113
|
+
description: $$('div.post-body').html(),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const processedItem: DataItem = {
|
|
117
|
+
title,
|
|
118
|
+
description,
|
|
119
|
+
pubDate: pubDateStr ? parseDate(pubDateStr) : item.pubDate,
|
|
120
|
+
category: categories,
|
|
121
|
+
author: authors,
|
|
122
|
+
content: {
|
|
123
|
+
html: description,
|
|
124
|
+
text: description,
|
|
125
|
+
},
|
|
126
|
+
updated: upDatedStr ? parseDate(upDatedStr) : item.updated,
|
|
127
|
+
language,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
...item,
|
|
132
|
+
...processedItem,
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
})
|
|
136
|
+
)
|
|
137
|
+
).filter((_): _ is DataItem => true);
|
|
138
|
+
|
|
139
|
+
const title: string = $('title').text();
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
title,
|
|
143
|
+
description: $('meta[name="description"]').attr('content'),
|
|
144
|
+
link: targetUrl,
|
|
145
|
+
item: items,
|
|
146
|
+
allowEmpty: true,
|
|
147
|
+
image: new URL('static/home/images/logo.png', baseUrl).href,
|
|
148
|
+
author: title.split(/-/).pop(),
|
|
149
|
+
language,
|
|
150
|
+
id: targetUrl,
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const route: Route = {
|
|
155
|
+
path: '/article',
|
|
156
|
+
name: '网站翻译',
|
|
157
|
+
url: 'www.ltaaa.cn',
|
|
158
|
+
maintainers: ['nczitzk'],
|
|
159
|
+
handler,
|
|
160
|
+
example: '/ltaaa/article',
|
|
161
|
+
parameters: undefined,
|
|
162
|
+
description: undefined,
|
|
163
|
+
categories: ['new-media'],
|
|
164
|
+
features: {
|
|
165
|
+
requireConfig: false,
|
|
166
|
+
requirePuppeteer: false,
|
|
167
|
+
antiCrawler: false,
|
|
168
|
+
supportRadar: true,
|
|
169
|
+
supportBT: false,
|
|
170
|
+
supportPodcast: false,
|
|
171
|
+
supportScihub: false,
|
|
172
|
+
},
|
|
173
|
+
radar: [
|
|
174
|
+
{
|
|
175
|
+
source: ['www.ltaaa.cn/article'],
|
|
176
|
+
target: '/article',
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
view: ViewType.Articles,
|
|
180
|
+
};
|
|
@@ -103,7 +103,10 @@ const parseSimpleDetail = ($ele) => {
|
|
|
103
103
|
const link = new URL($ele.attr('href'), baseUrl).href;
|
|
104
104
|
const thumb = $ele.children('img');
|
|
105
105
|
const thumbSrc = thumb.attr('data-src') || thumb.attr('src');
|
|
106
|
-
const highResoThumbSrc = thumbSrc
|
|
106
|
+
const highResoThumbSrc = thumbSrc
|
|
107
|
+
.replace('thumb', '1')
|
|
108
|
+
.replace(/t(\d+)\.nhentai\.net/, 'i$1.nhentai.net')
|
|
109
|
+
.replace('.webp.webp', '.webp');
|
|
107
110
|
return {
|
|
108
111
|
title: $ele.children('.caption').text(),
|
|
109
112
|
link,
|
|
@@ -69,6 +69,9 @@ async function handler(ctx) {
|
|
|
69
69
|
const getUserResource = (username: string) =>
|
|
70
70
|
cache.tryGet(`pinterest:user:${username}`, async () => {
|
|
71
71
|
const response = await ofetch(`${baseUrl}/resource/UserResource/get/`, {
|
|
72
|
+
headers: {
|
|
73
|
+
'x-pinterest-pws-handler': 'www/[username]/_created.js',
|
|
74
|
+
},
|
|
72
75
|
query: {
|
|
73
76
|
source_url: `/${username}/_created`,
|
|
74
77
|
data: JSON.stringify({ options: { username, field_set_key: 'unauth_profile' }, context: {} }),
|
|
@@ -81,6 +84,9 @@ const getUserResource = (username: string) =>
|
|
|
81
84
|
|
|
82
85
|
const getUserActivityPinsResource = async (username: string, userId: string) => {
|
|
83
86
|
const response = await ofetch(`${baseUrl}/resource/UserActivityPinsResource/get/`, {
|
|
87
|
+
headers: {
|
|
88
|
+
'x-pinterest-pws-handler': 'www/[username]/_created.js',
|
|
89
|
+
},
|
|
84
90
|
query: {
|
|
85
91
|
source_url: `/${username}/_created`,
|
|
86
92
|
data: JSON.stringify({ options: { exclude_add_pin_rep: true, field_set_key: 'grid_item', is_own_profile_pins: false, user_id: userId, username }, context: {} }),
|
|
@@ -93,6 +99,9 @@ const getUserActivityPinsResource = async (username: string, userId: string) =>
|
|
|
93
99
|
|
|
94
100
|
const getBoardsFeedResource = async (username: string) => {
|
|
95
101
|
const response = await ofetch(`${baseUrl}/resource/BoardsFeedResource/get/`, {
|
|
102
|
+
headers: {
|
|
103
|
+
'x-pinterest-pws-handler': 'www/[username]/_saved.js',
|
|
104
|
+
},
|
|
96
105
|
query: {
|
|
97
106
|
source_url: `/${username}/_saved`,
|
|
98
107
|
data: JSON.stringify({ options: { field_set_key: 'profile_grid_item', filter_stories: false, sort: 'last_pinned_to', username }, context: {} }),
|
package/lib/routes/sohu/mp.ts
CHANGED
|
@@ -124,11 +124,12 @@ async function handler(ctx) {
|
|
|
124
124
|
)
|
|
125
125
|
.sort((a: any, b: any) => b.length - a.length)[0] || '{}'
|
|
126
126
|
);
|
|
127
|
-
const
|
|
127
|
+
const blockRenderData = JSON.parse(
|
|
128
128
|
$('script:contains("column_2_text")')
|
|
129
129
|
.text()
|
|
130
|
-
.match(/
|
|
130
|
+
.match(/({.*})/)?.[1]
|
|
131
131
|
);
|
|
132
|
+
const renderData = blockRenderData[Object.keys(blockRenderData).find((e) => e.startsWith('FeedSlideloadAuthor'))];
|
|
132
133
|
const globalConst = JSON.parse(
|
|
133
134
|
$('script:contains("globalConst")')
|
|
134
135
|
.text()
|
|
@@ -58,7 +58,7 @@ async function handler(ctx) {
|
|
|
58
58
|
itunes_category: meta.type,
|
|
59
59
|
itunes_explicit: meta.explicit,
|
|
60
60
|
allowEmpty: true,
|
|
61
|
-
item: episodes.map((x) => ({
|
|
61
|
+
item: episodes.filter(Boolean).map((x) => ({
|
|
62
62
|
title: x.name,
|
|
63
63
|
description: x.html_description,
|
|
64
64
|
pubDate: parseDate(x.release_date),
|