Skip to content

Commit

Permalink
feat(route): 增加几米创作最新消息 (#17924)
Browse files Browse the repository at this point in the history
* feat(route): 增加几米创作最新消息

* chore: update namespace

* Update lib/routes/jimmyspa/namespace.ts

Co-authored-by: Tony <[email protected]>

* chore: update jimmyspa

* chore: cache the content

---------

Co-authored-by: Cedar <[email protected]>
  • Loading branch information
FYLSen and FYLSen authored Dec 20, 2024
1 parent e20c7a0 commit 40e3dad
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 0 deletions.
112 changes: 112 additions & 0 deletions lib/routes/jimmyspa/books.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Route, ViewType } from '@/types';
import { parseDate } from '@/utils/parse-date';
import got from '@/utils/got';
import { load } from 'cheerio';
import { art } from '@/utils/render';
import { getCurrentPath } from '@/utils/helpers';
import cache from '@/utils/cache';
import path from 'node:path';

const __dirname = getCurrentPath(import.meta.url);
export const route: Route = {
path: '/books/:language',
categories: ['design'],
view: ViewType.Articles,
example: '/jimmyspa/books/tw',
parameters: {
language: {
description: '语言',
options: [
{ value: 'tw', label: '臺灣正體' },
{ value: 'en', label: 'English' },
{ value: 'jp', label: '日本語' },
],
},
},
radar: [
{
source: ['www.jimmyspa.com/:language/Books'],
},
],
name: 'Books',
description: `
| language | Description |
| --- | --- |
| tw | 臺灣正體 |
| en | English |
| jp | 日本語 |
`,
maintainers: ['FYLSen'],
handler,
};

async function handler(ctx) {
const language = ctx.req.param('language');
const baseUrl = 'https://www.jimmyspa.com';
const booksListUrl = new URL(`/${language}/Books/Ajax/changeList?year=&keyword=&categoryId=0&page=1`, baseUrl).href;

const listResponse = await got(booksListUrl);
const listPage = load(listResponse.data.view);

const bookItems = listPage('ul#appendWork li.work_block')
.toArray()
.map(async (bookElement) => {
const bookContent = load(bookElement);
const bookTitle = bookContent('p.tit').text();
const bookImageRelative = bookContent('div.work_img img').prop('src') || '';
const bookImageUrl = bookImageRelative ? baseUrl + bookImageRelative : '';
const bookDetailUrl = bookContent('li.work_block').prop('data-route');

const { renderedDescription, publishDate } = (await cache.tryGet(bookDetailUrl, async () => {
const detailResponse = await got(bookDetailUrl);
const detailPage = load(detailResponse.data);
const bookDescription = detailPage('article.intro_cont').html() || '';
const bookInfoWrap = detailPage('div.info_wrap').html() || '';

const processedDescription = bookDescription.replaceAll(/<img\b[^>]*>/g, (imgTag) =>
imgTag.replaceAll(/\b(src|data-src)="(?!http|https|\/\/)([^"]*)"/g, (_, attrName, relativePath) => {
const absoluteImageUrl = new URL(relativePath, baseUrl).href;
return `${attrName}="${absoluteImageUrl}"`;
})
);

const publishDateMatch = bookInfoWrap.match(/<span>(首次出版|First Published|初版)<\/span>\s*<span class="num">([^<]+)<\/span>/);
const publishDate = publishDateMatch ? parseDate(publishDateMatch[2] + '-02') : '';

const renderedDescription = art(path.join(__dirname, 'templates/description.art'), {
images: bookImageUrl
? [
{
src: bookImageUrl,
alt: bookTitle,
},
]
: undefined,
description: processedDescription,
});

return {
renderedDescription,
publishDate,
};
})) as { renderedDescription: string; publishDate: string };

return {
title: bookTitle,
link: bookDetailUrl,
description: renderedDescription,
pubDate: publishDate,
content: {
html: renderedDescription,
text: bookTitle,
},
};
});

return {
title: `幾米 - 幾米創作(${language})`,
link: `${baseUrl}/${language}/Books`,
allowEmpty: true,
item: await Promise.all(bookItems),
};
}
7 changes: 7 additions & 0 deletions lib/routes/jimmyspa/namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Namespace } from '@/types';

export const namespace: Namespace = {
name: '幾米 JIMMY S.P.A. Official Website',
url: 'www.jimmyspa.com',
lang: 'zh-TW',
};
124 changes: 124 additions & 0 deletions lib/routes/jimmyspa/news.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Route, ViewType } from '@/types';
import { parseDate } from '@/utils/parse-date';
import got from '@/utils/got';
import { load } from 'cheerio';
import { art } from '@/utils/render';
import { getCurrentPath } from '@/utils/helpers';
const __dirname = getCurrentPath(import.meta.url);
import path from 'node:path';

export const route: Route = {
path: '/news/:language',
categories: ['design'],
view: ViewType.Pictures,
example: '/jimmyspa/news/tw',
parameters: {
language: {
description: '语言',
options: [
{ value: 'tw', label: '臺灣正體' },
{ value: 'en', label: 'English' },
{ value: 'jp', label: '日本語' },
],
},
},
radar: [
{
source: ['www.jimmyspa.com/:language/News'],
},
],
name: 'News',
description: `
| language | Description |
| --- | --- |
| tw | 臺灣正體 |
| en | English |
| jp | 日本語 |
`,
maintainers: ['FYLSen'],
handler,
};

async function handler(ctx) {
const language = ctx.req.param('language');
const rootUrl = 'https://www.jimmyspa.com';

const currentUrl = new URL(`/${language}/News/Ajax/changeList?year=&keyword=&categoryId=0&page=1`, rootUrl).href;

const responseData = await got(currentUrl);

const $ = load(responseData.data.view);

const items = $('ul#appendNews li.card_block')
.toArray()
.map((item) => {
const $$ = load(item);
const title = $$('a.news_card .info_wrap h3').text();
const image = $$('a.news_card .card_img img').prop('src') || '';
const link = $$('a.news_card').prop('data-route');
const itemdate = $$('a.news_card div.date').html() || '';
const pubDate = convertHtmlDateToStandardFormat(itemdate.toString());

const description = art(path.join(__dirname, 'templates/description.art'), {
images: image
? [
{
src: image,
alt: title,
},
]
: undefined,
description: $$('a.news_card .info_wrap p').text(),
});

return {
title,
link,
description,
pubDate,
content: {
html: description,
text: title,
},
};
});

return {
title: `幾米 - 最新消息(${language})`,
link: `${rootUrl}/${language}/News`,
allowEmpty: true,
item: items,
};
}

function convertHtmlDateToStandardFormat(htmlContent: string): Date | undefined {
const dateRegex = /<p>(\d{1,2})<\/p>\s*<p>(\d{1,2})\s*\.\s*([A-Za-z]{3})<\/p>/;
const match = htmlContent.match(dateRegex);

if (match) {
const day = Number.parseInt(match[1]) + 1;
const year = match[2];
const monthAbbreviation = match[3];

const monthMapping: { [key: string]: string } = {
Jan: '01',
Feb: '02',
Mar: '03',
Apr: '04',
May: '05',
Jun: '06',
Jul: '07',
Aug: '08',
Sep: '09',
Oct: '10',
Nov: '11',
Dec: '12',
};

const month = monthMapping[monthAbbreviation] || '';

return parseDate(`20${year}-${month}-${day}`);
}

return undefined;
}
17 changes: 17 additions & 0 deletions lib/routes/jimmyspa/templates/description.art
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{ if images }}
{{ each images image }}
{{ if image?.src }}
<figure>
<img
{{ if image.alt }}
alt="{{ image.alt }}"
{{ /if }}
src="{{ image.src }}">
</figure>
{{ /if }}
{{ /each }}
{{ /if }}

{{ if description }}
{{@ description }}
{{ /if }}

0 comments on commit 40e3dad

Please sign in to comment.