diff --git a/lib/routes/dehenglaw/index.ts b/lib/routes/dehenglaw/index.ts new file mode 100644 index 000000000000000..1f03e03354163fc --- /dev/null +++ b/lib/routes/dehenglaw/index.ts @@ -0,0 +1,128 @@ +import { Route } from '@/types'; +import { getCurrentPath } from '@/utils/helpers'; +const __dirname = getCurrentPath(import.meta.url); + +import cache from '@/utils/cache'; +import got from '@/utils/got'; +import { load } from 'cheerio'; +import { parseDate } from '@/utils/parse-date'; +import { art } from '@/utils/render'; +import path from 'node:path'; + +export const handler = async (ctx) => { + const { language = 'CN', category = 'paper' } = ctx.req.param(); + const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 6; + + const rootUrl = 'https://www.dehenglaw.com'; + const currentUrl = new URL(`${language}/${category}/0008/000901.aspx`, rootUrl).href; + + const { data: response } = await got(currentUrl); + + const $ = load(response); + + let items = $('div.news_box ul li') + .slice(0, limit) + .toArray() + .map((item) => { + item = $(item); + + const title = item.find('h2').text(); + const description = art(path.join(__dirname, 'templates/description.art'), { + intro: item.find('div.deheng_newscontent p').text(), + }); + + return { + title, + description, + pubDate: parseDate(item.find('span').text(), 'YYYY/M/D'), + link: item.find('a').first().prop('href'), + }; + }); + + items = await Promise.all( + items.map((item) => + cache.tryGet(item.link, async () => { + const { data: detailResponse } = await got(item.link); + + const $$ = load(detailResponse); + + const description = + item.description + + art(path.join(__dirname, 'templates/description.art'), { + description: $$('div.news_content').html(), + }); + const image = $$('div.news_content img').prop('src'); + + item.description = description; + item.author = $$('div.name h4 a').text(); + item.content = { + html: description, + text: $$('div.news_content').text(), + }; + item.image = image; + item.banner = image; + + return item; + }) + ) + ); + + const image = $('div.logo_content a img').prop('src'); + + return { + title: $('title') + .text() + .replace(/\|.*?$/, `| ${$('li.onthis').text()}`), + description: $('meta[name="Description"]').prop('content'), + link: currentUrl, + item: items, + allowEmpty: true, + image, + author: $('meta[name="Description"]').prop('content'), + }; +}; + +export const route: Route = { + path: '/:language?/:category?', + name: '德恒探索', + url: 'dehenglaw.com', + maintainers: ['nczitzk'], + handler, + example: '/dehenglaw/CN/paper', + parameters: { language: '语言,默认为中文,即 CN,可在对应分类页 URL 中找到,可选 CN 和 EN', category: '分类,默认为专业文章,即 paper,可在对应分类页 URL 中找到' }, + description: `:::tip + 若订阅 [专业文章](https://dehenglaw.com/),网址为 \`https://www.dehenglaw.com/CN/paper/0008/000902.aspx\`。截取 \`https://dehenglaw.com/\` 到末尾 \`/0008/000902.aspx\` 的部分 \`CN/paper\` 作为参数填入,此时路由为 [\`/dehenglaw/CN/paper\`](https://rsshub.app/dehenglaw/CN/paper)。 + + | 专业文章 | 出版物 | 德恒论坛 | + | -------- | ------- | -------- | + | paper | publish | luntan | + :::`, + categories: ['new-media'], + + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportRadar: true, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + radar: [ + { + title: '专业文章', + source: ['dehenglaw.com/:language/paper/0008/000902.aspx'], + target: '/:language/paper', + }, + { + title: '出版物', + source: ['dehenglaw.com/:language/publish/0008/000903.aspx'], + target: '/:language/publish', + }, + { + title: '德恒论坛', + source: ['dehenglaw.com/:language/luntan/0008/000901.aspx'], + target: '/:language/luntan', + }, + ], +}; diff --git a/lib/routes/dehenglaw/namespace.ts b/lib/routes/dehenglaw/namespace.ts new file mode 100644 index 000000000000000..038d08e6cb41f35 --- /dev/null +++ b/lib/routes/dehenglaw/namespace.ts @@ -0,0 +1,8 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: '德恒律师事务所', + url: 'dehenglaw.com', + categories: ['new-media'], + description: '', +}; diff --git a/lib/routes/dehenglaw/templates/description.art b/lib/routes/dehenglaw/templates/description.art new file mode 100644 index 000000000000000..57498ab45a9d86c --- /dev/null +++ b/lib/routes/dehenglaw/templates/description.art @@ -0,0 +1,7 @@ +{{ if intro }} +
{{ intro }}
+{{ /if }} + +{{ if description }} + {{@ description }} +{{ /if }} \ No newline at end of file diff --git a/lib/routes/reuters/common.ts b/lib/routes/reuters/common.ts index e1b4e3f25c921a3..f376dabcf98ba58 100644 --- a/lib/routes/reuters/common.ts +++ b/lib/routes/reuters/common.ts @@ -64,13 +64,13 @@ export const route: Route = { }; async function handler(ctx) { - const MUST_FETCH_BY_TOPICS = new Set(['authors']); + const MUST_FETCH_BY_TOPICS = new Set(['authors', 'tags']); const CAN_USE_SOPHI = ['world']; const category = ctx.req.param('category'); const topic = ctx.req.param('topic') ?? (category === 'authors' ? 'reuters' : ''); const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 20; - const useSophi = ctx.req.query('sophi') === 'true' && 'topic' !== '' && CAN_USE_SOPHI.includes(category); + const useSophi = ctx.req.query('sophi') === 'true' && topic !== '' && CAN_USE_SOPHI.includes(category); const section_id = `/${category}/${topic ? `${topic}/` : ''}`; const { title, description, rootUrl, response } = await (async () => { diff --git a/package.json b/package.json index e24c3bd5a5471b4..ec302528e095f9d 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@hono/zod-openapi": "0.11.0", "@notionhq/client": "2.2.15", "@postlight/parser": "2.2.3", - "@sentry/node": "7.110.1", + "@sentry/node": "7.111.0", "@tonyrl/rand-user-agent": "2.0.59", "aes-js": "3.1.2", "art-template": "4.13.2", @@ -75,7 +75,7 @@ "fanfou-sdk": "5.0.0", "form-data": "4.0.0", "googleapis": "134.0.0", - "hono": "4.2.4", + "hono": "4.2.5", "html-to-text": "9.0.5", "https-proxy-agent": "7.0.4", "iconv-lite": "0.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b953295a4d10afc..a56f694640cd735 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ dependencies: version: 1.10.0 '@hono/swagger-ui': specifier: 0.2.1 - version: 0.2.1(hono@4.2.4) + version: 0.2.1(hono@4.2.5) '@hono/zod-openapi': specifier: 0.11.0 - version: 0.11.0(hono@4.2.4)(zod@3.22.4) + version: 0.11.0(hono@4.2.5)(zod@3.22.4) '@notionhq/client': specifier: 2.2.15 version: 2.2.15 @@ -21,8 +21,8 @@ dependencies: specifier: 2.2.3 version: 2.2.3 '@sentry/node': - specifier: 7.110.1 - version: 7.110.1 + specifier: 7.111.0 + version: 7.111.0 '@tonyrl/rand-user-agent': specifier: 2.0.59 version: 2.0.59 @@ -81,8 +81,8 @@ dependencies: specifier: 134.0.0 version: 134.0.0 hono: - specifier: 4.2.4 - version: 4.2.4 + specifier: 4.2.5 + version: 4.2.5 html-to-text: specifier: 9.0.5 version: 9.0.5 @@ -2148,15 +2148,15 @@ packages: engines: {node: '>=18.14.1'} dev: false - /@hono/swagger-ui@0.2.1(hono@4.2.4): + /@hono/swagger-ui@0.2.1(hono@4.2.5): resolution: {integrity: sha512-wBxVMRe3/v8xH4o6icmwztiIq0DG0s7+jHVMHVUAoFFCWEQNL2iskMmQtrhSDtsFmBZUeUFQUaaJ6Ir6DOmHLA==} peerDependencies: hono: '*' dependencies: - hono: 4.2.4 + hono: 4.2.5 dev: false - /@hono/zod-openapi@0.11.0(hono@4.2.4)(zod@3.22.4): + /@hono/zod-openapi@0.11.0(hono@4.2.5)(zod@3.22.4): resolution: {integrity: sha512-thbxV4lWJoDo1NjF8ZGnd0muD3UHUpRqpKvS3RI+kWCXU05nyuViymUbPvVpp+O6i5SjovITTF91NRMTraZm3Q==} engines: {node: '>=16.0.0'} peerDependencies: @@ -2164,18 +2164,18 @@ packages: zod: 3.* dependencies: '@asteasolutions/zod-to-openapi': 7.0.0(zod@3.22.4) - '@hono/zod-validator': 0.2.1(hono@4.2.4)(zod@3.22.4) - hono: 4.2.4 + '@hono/zod-validator': 0.2.1(hono@4.2.5)(zod@3.22.4) + hono: 4.2.5 zod: 3.22.4 dev: false - /@hono/zod-validator@0.2.1(hono@4.2.4)(zod@3.22.4): + /@hono/zod-validator@0.2.1(hono@4.2.5)(zod@3.22.4): resolution: {integrity: sha512-HFoxln7Q6JsE64qz2WBS28SD33UB2alp3aRKmcWnNLDzEL1BLsWfbdX6e1HIiUprHYTIXf5y7ax8eYidKUwyaA==} peerDependencies: hono: '>=3.9.0' zod: ^3.19.1 dependencies: - hono: 4.2.4 + hono: 4.2.5 zod: 3.22.4 dev: false @@ -2665,43 +2665,43 @@ packages: selderee: 0.11.0 dev: false - /@sentry-internal/tracing@7.110.1: - resolution: {integrity: sha512-4kTd6EM0OP1SVWl2yLn3KIwlCpld1lyhNDeR8G1aKLm1PN+kVsR6YB/jy9KPPp4Q3lN3W9EkTSES3qhP4jVffQ==} + /@sentry-internal/tracing@7.111.0: + resolution: {integrity: sha512-CgXly8rsdu4loWVKi2RqpInH3C2cVBuaYsx4ZP5IJpzSinsUAMyyr3Pc0PZzCyoVpBBXGBGj/4HhFsY3q6Z0Vg==} engines: {node: '>=8'} dependencies: - '@sentry/core': 7.110.1 - '@sentry/types': 7.110.1 - '@sentry/utils': 7.110.1 + '@sentry/core': 7.111.0 + '@sentry/types': 7.111.0 + '@sentry/utils': 7.111.0 dev: false - /@sentry/core@7.110.1: - resolution: {integrity: sha512-yC1yeUFQlmHj9u/KxKmwOMVanBmgfX+4MZnZU31QPqN95adyZTwpaYFZl4fH5kDVnz7wXJI0qRP8SxuMePtqhw==} + /@sentry/core@7.111.0: + resolution: {integrity: sha512-/ljeMjZu8CSrLGrseBi/7S2zRIFsqMcvfyG6Nwgfc07J9nbHt8/MqouE1bXZfiaILqDBpK7BK9MLAAph4mkAWg==} engines: {node: '>=8'} dependencies: - '@sentry/types': 7.110.1 - '@sentry/utils': 7.110.1 + '@sentry/types': 7.111.0 + '@sentry/utils': 7.111.0 dev: false - /@sentry/node@7.110.1: - resolution: {integrity: sha512-n6sNzZJ/ChfyCI1FxuGWgloeevC8j2vax3vXM4IZrSIm5hS1d9L2oCJ4HEPuxGUxCkQ1f4kXPcdmNaQsWH0JBw==} + /@sentry/node@7.111.0: + resolution: {integrity: sha512-bTLZNETT7W89HEk04rwsch02KSpu++Yec/BEyM3AxUNY+ZQ9ZLL/lrNZuCwbe7fURpKoZrvGAhxpPjgs5UcB9w==} engines: {node: '>=8'} dependencies: - '@sentry-internal/tracing': 7.110.1 - '@sentry/core': 7.110.1 - '@sentry/types': 7.110.1 - '@sentry/utils': 7.110.1 + '@sentry-internal/tracing': 7.111.0 + '@sentry/core': 7.111.0 + '@sentry/types': 7.111.0 + '@sentry/utils': 7.111.0 dev: false - /@sentry/types@7.110.1: - resolution: {integrity: sha512-sZxOpM5gfyxvJeWVvNpHnxERTnlqcozjqNcIv29SZ6wonlkekmxDyJ3uCuPv85VO54WLyA4uzskPKnNFHacI8A==} + /@sentry/types@7.111.0: + resolution: {integrity: sha512-Oti4pgQ55+FBHKKcHGu51ZUxO1u52G5iVNK4mbtAN+5ArSCy/2s1H8IDJiOMswn3acfUnCR0oB/QsbEgAPZ26g==} engines: {node: '>=8'} dev: false - /@sentry/utils@7.110.1: - resolution: {integrity: sha512-eibLo2m1a7sHkOHxYYmRujr3D7ek2l9sv26F1SLoQBVDF7Afw5AKyzPmtA1D+4M9P/ux1okj7cGj3SaBrVpxXA==} + /@sentry/utils@7.111.0: + resolution: {integrity: sha512-CB5rz1EgCSwj3xoXogsCZ5pQtfERrURc/ItcCuoaijUhkD0iMq5MCNWMHW3mBsBrqx/Oba+XGvDu0t/5+SWwBg==} engines: {node: '>=8'} dependencies: - '@sentry/types': 7.110.1 + '@sentry/types': 7.111.0 dev: false /@sinclair/typebox@0.27.8: @@ -5830,8 +5830,8 @@ packages: resolution: {integrity: sha512-4FP6J0oI8jqb6gLLl9tSwVdosWJ/AKSGJ+HwYf6Ixe4MUcEkst4uWzpVQrNOCin0fzTRQbXV8ePheU8WiiDYBw==} dev: false - /hono@4.2.4: - resolution: {integrity: sha512-2T5Ahxh8tT0ISKCrNeA+OIwfD5W4EZ00iIMYBBCuiIivr+sOrZYOphinARSG7wL3nFsY6zkFHMMZbcR9CzEzug==} + /hono@4.2.5: + resolution: {integrity: sha512-uonJD3i/yy005kQ7bPZRVfG3rejYJwyPqBmPoUGijS4UB/qM+YlrZ7xzSWy+ByDu9buGHUG+f+SKzz03Y6V1Kw==} engines: {node: '>=16.0.0'} dev: false