feat: route for furstar.jp, 最新角色和画家 (#5194)

Co-authored-by: Henry Wang <hi@henry.wang>
This commit is contained in:
NeverBehave 2020-07-28 13:57:51 -04:00 committed by GitHub
parent bf5b5a5807
commit da88193f04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 189 additions and 0 deletions

View File

@ -10,6 +10,20 @@ pageClass: routes
<Route author="luyuhuang" example="/alter-cn/news" path="/alter-cn/news"/>
## Furstar
### 最新售卖角色列表
<Route author="NeverBehave" example="/furstar/characters/cn" path="/furstar/characters/:lang?" :paramsDesc="['语言, 留空为jp, 支持cn, en']"/>
### 已经出售的角色列表
<Route author="NeverBehave" example="/furstar/archive/cn" path="/furstar/archive/:lang?" :paramsDesc="['语言, 留空为jp, 支持cn, en']"/>
### 画师列表
<Route author="NeverBehave" example="/furstar/artists/cn" path="/furstar/artists/:lang?" :paramsDesc="['语言, 留空为jp, 支持cn, en']"/>
## LeBonCoin
### Ads

View File

@ -2971,10 +2971,17 @@ router.get('/ngbj/cat/:cat', require('./routes/niaogebiji/cat'));
// 东方我乐多丛志
router.get('/touhougarakuta/:language/:type', require('./routes/touhougarakuta'));
// furstar.jp
router.get('/furstar/characters/:lang?', require('./routes/furstar/index'));
router.get('/furstar/artists/:lang?', require('./routes/furstar/artists'));
router.get('/furstar/archive/:lang?', require('./routes/furstar/archive'));
// 北京物资学院
router.get('/bwu/news', require('./routes/universities/bwu/news'));
// Picuki
router.get('/picuki/profile/:id', require('./routes/picuki/profile'));
// 新榜
router.get('/newrank/wechat/:wxid', require('./routes/newrank/wechat'));
router.get('/newrank/douyin/:dyid', require('./routes/newrank/douyin'));

View File

@ -0,0 +1,24 @@
const utils = require('./utils');
const got = require('@/utils/got');
const dateParser = require('@/utils/dateParser');
module.exports = async (ctx) => {
const base = utils.langBase(ctx.params.lang);
const url = `${base}/archive.php`;
const res = await got.get(url);
const info = utils.fetchAllCharacters(res.data, base);
ctx.state.data = {
title: 'Furstar 已出售角色',
link: 'https://furstar.jp',
description: 'Furstar 已经出售或预订的角色列表',
language: ctx.params.lang,
item: info.map((e) => ({
title: e.title,
author: e.author.name,
description: `<img src="${e.headImage}"/> ${utils.renderAuthor(e.author)}`,
pubDate: dateParser(new Date().toISOString()), // No Time for now
link: e.detailPage,
})),
};
};

View File

@ -0,0 +1,28 @@
const utils = require('./utils');
const cheerio = require('cheerio');
const got = require('@/utils/got');
const dateParser = require('@/utils/dateParser');
module.exports = async (ctx) => {
const base = utils.langBase(ctx.params.lang);
const res = await got.get(base);
const $ = cheerio.load(res.data);
const artists = $('.filter-item')
.map((i, e) => utils.authorDetail(e))
.get();
artists.shift(); // the first one is "show all"
ctx.state.data = {
title: 'furstar 所有画家',
link: 'https://furstar.jp',
description: 'Furstar 所有画家列表',
language: ctx.params.lang,
item: artists.map((e) => ({
title: e.name,
author: e.name,
description: `<img src="${e.avatar}"/><a href="${base}/${e.link}">${e.name}</a>`,
pubDate: dateParser(new Date().toISOString()), // No Time for now
link: `${base}/${e.link}`,
})),
};
};

View File

@ -0,0 +1,25 @@
const utils = require('./utils');
const got = require('@/utils/got');
const dateParser = require('@/utils/dateParser');
module.exports = async (ctx) => {
const base = utils.langBase(ctx.params.lang);
const res = await got.get(base);
const info = utils.fetchAllCharacters(res.data, base);
const details = await Promise.all(info.map((e) => utils.detailPage(e.detailPage, ctx.cache)));
ctx.state.data = {
title: 'Furstar 最新角色',
link: 'https://furstar.jp',
description: 'Furstar 最近更新的角色列表',
language: ctx.params.lang,
item: info.map((e, i) => ({
title: e.title,
author: e.author.name,
description: utils.renderDesc(details[i].desc, details[i].pics, e.author),
pubDate: dateParser(new Date().toISOString()), // No Time for now
link: e.detailPage,
})),
};
};

View File

@ -0,0 +1,91 @@
const cheerio = require('cheerio');
const got = require('@/utils/got');
const base = 'https://furstar.jp';
const langBase = (lang) => (lang ? `${base}/${lang}` : base); // en, cn, (none, for JP)
const renderAuthor = (author) => `<div>
<img src="${author.avatar}" />
<a href="${author.link ? author.link : '//example.com'}">${author.name}</a>
</div>`;
const renderDesc = (desc, pics, author) => {
const rpics = pics.map((e) => `<img src="${e}"/>`).join('\n');
const rauthor = renderAuthor(author);
return `<p>${desc}</p>${rpics}${rauthor}`;
};
const authorDetail = (el) => {
const $ = cheerio.load(el);
// if there is <a>
const a = $('a');
const result = {
name: null,
avatar: null,
link: null,
};
if (a.length > 0) {
const img = $('a img');
result.name = img.attr('alt');
result.avatar = img.attr('src');
result.link = a.attr('href');
} else {
const desc = $('img');
result.name = desc.attr('alt');
result.avatar = desc.attr('src');
}
return result;
};
const detailPage = async (link, cache) =>
cache.tryGet(link, async () => {
const result = await got(link);
const $ = cheerio.load(result.data);
const title = $('.row .panel-heading h2').text().trim(); // Get first title
const desc = $('.character-description p').text().trim();
const pics = $('.img-gallery .prettyPhoto')
.map((i, e) => {
const p = cheerio.load(e);
const link = p('a').attr('href').trim();
return `${base}${link.substring(2)}`;
})
.get();
return {
title,
pics,
desc,
author: authorDetail($('.character-description').html()),
};
});
const fetchAllCharacters = (data, base) => {
// All character page
const $ = cheerio.load(data);
const characters = $('.character-article');
const info = characters
.map((i, e) => {
const c = cheerio.load(e);
const r = {
title: c('.character-headline').text().trim(),
headImage: c('.character-images img').attr('src').trim(),
detailPage: `${base}/${c('.character-images a').attr('href').trim()}`,
author: authorDetail(c('.character-description').html()),
};
return r;
})
.get();
return info;
};
module.exports = {
BASE: base,
langBase,
fetchAllCharacters,
detailPage,
authorDetail,
renderDesc,
renderAuthor,
};