From 155ea080658dd81093b36fdded1f4a336a61dc41 Mon Sep 17 00:00:00 2001 From: hoilc Date: Thu, 26 Sep 2019 14:53:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0TapTap=E8=AE=BA?= =?UTF-8?q?=E5=9D=9B=E3=80=81=E8=AF=84=E4=BB=B7=E3=80=81=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=20(#3138)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/game.md | 22 +++++++++ lib/router.js | 5 ++ lib/routes/taptap/changelog.js | 39 ++++++++++++++++ lib/routes/taptap/review.js | 54 +++++++++++++++++++++ lib/routes/taptap/topic.js | 85 ++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+) create mode 100644 lib/routes/taptap/changelog.js create mode 100644 lib/routes/taptap/review.js create mode 100644 lib/routes/taptap/topic.js diff --git a/docs/game.md b/docs/game.md index 7a1fd9e1c8..4ea56bf15e 100644 --- a/docs/game.md +++ b/docs/game.md @@ -149,6 +149,28 @@ Example: `https://store.steampowered.com/search/?specials=1&term=atelier` 中的 +## TapTap + +### 游戏论坛 + + + +| 全部 | 精华 | 官方 | +| ---- | ----- | -------- | +| all | elite | official | + +### 游戏更新 + + + +### 游戏评价 + + + +| 最新 | 最热 | 游戏时长 | +| ------ | ---- | -------- | +| update | hot | spent | + ## 篝火营地 ### 游戏资讯 diff --git a/lib/router.js b/lib/router.js index d004edd7c2..0bd4e13e3e 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1749,4 +1749,9 @@ router.get('/haimaoba/:id?', require('./routes/haimaoba/comics')); // 蒲公英 router.get('/pgyer/:app?', require('./routes/pgyer/app')); +// TAPTAP +router.get('/taptap/topic/:id/:label?', require('./routes/taptap/topic')); +router.get('/taptap/changelog/:id', require('./routes/taptap/changelog')); +router.get('/taptap/review/:id/:order?', require('./routes/taptap/review')); + module.exports = router; diff --git a/lib/routes/taptap/changelog.js b/lib/routes/taptap/changelog.js new file mode 100644 index 0000000000..b9864f420d --- /dev/null +++ b/lib/routes/taptap/changelog.js @@ -0,0 +1,39 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + + const url = `https://www.taptap.com/app/${id}`; + + const app_response = await got.get(url); + const $ = cheerio.load(app_response.data); + + const app_img = $('.header-icon-body > img').attr('src'); + const app_name = $('.breadcrumb > li.active').text(); + const app_description = $('.body-description-paragraph').text(); + + const response = await got({ + method: 'get', + url: `https://www.taptap.com/ajax/apk/v1/list-by-app?app_id=${id}&from=0&limit=10`, + headers: { + Referer: url, + }, + }); + + const list = response.data.data.list; + + ctx.state.data = { + title: `TapTap 更新记录 ${app_name}`, + description: app_description, + link: url, + image: app_img, + item: list.map((item) => ({ + title: item.version_label, + description: `${item.whatsnew.text}`, + pubDate: new Date(item.update_date), + link: url, + guid: item.version_label, + })), + }; +}; diff --git a/lib/routes/taptap/review.js b/lib/routes/taptap/review.js new file mode 100644 index 0000000000..588c1f0c0b --- /dev/null +++ b/lib/routes/taptap/review.js @@ -0,0 +1,54 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + const order = ctx.params.order; + + let url = `https://www.taptap.com/app/${id}/review`; + + if (order === 'update' || order === 'hot' || order === 'spent') { + url += `?order=${order}`; + } + + const reviews_list_response = await got.get(url); + const $ = cheerio.load(reviews_list_response.data); + + const app_img = $('.header-icon-body > img').attr('src'); + const app_name = $('.breadcrumb > li.active').text(); + const order_name = $('.taptap-review-title.section-title li.active') + .text() + .trim(); + const reviews_list = $('.review-item-text').toArray(); + + ctx.state.data = { + title: `TapTap评价 ${app_name} - ${order_name}排序`, + link: url, + image: app_img, + item: reviews_list.map((review) => { + review = $(review); + const score = + review + .find('.colored') + .attr('style') + .match(/\d+/)[0] / 14; + const author = review + .find('.item-text-header > .taptap-user ') + .first() + .text() + .trim(); + return { + title: `${author} - ${score}星`, + author: author, + description: review.find('.item-text-body').html(), + link: review.find('a.text-header-time').attr('href'), + pubDate: new Date( + review + .find('a.text-header-time [data-dynamic-time]') + .text() + .trim() + ), + }; + }), + }; +}; diff --git a/lib/routes/taptap/topic.js b/lib/routes/taptap/topic.js new file mode 100644 index 0000000000..d0589bcc3a --- /dev/null +++ b/lib/routes/taptap/topic.js @@ -0,0 +1,85 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + const label = ctx.params.label; + + let url = `https://www.taptap.com/app/${id}/topic`; + + if (label === 'elite' || label === 'official' || label === 'all') { + url += `?type=${label}`; + } else if (/^\d+$/.test(label)) { + url += `?group_label_id=${label}`; + } + + const topics_list_response = await got.get(url); + const topics_list_data = topics_list_response.data; + const $ = cheerio.load(topics_list_data); + + const app_img = $('.group-info > a > img').attr('src'); + const app_name = $('.breadcrumb > li.active').text(); + const label_name = $('.tab-label a.active span').text(); + const topics_list = $('.item-content').toArray(); + + const parseContent = (htmlString) => { + const $ = cheerio.load(htmlString); + + const author = $('.user-name-identity'); + const content = $('.topic-content > .bbcode-body'); + const time = $('.topic-update-time').length === 0 ? $('.topic-info [data-dynamic-time]') : $('.topic-update-time [data-dynamic-time]'); + const pub_date = time.length === 0 ? new Date() : new Date(time.text().trim()); + + const images = $('img'); + for (let k = 0; k < images.length; k++) { + $(images[k]).replaceWith(``); + } + + return { + author: author.text().trim(), + description: content.html(), + pubDate: pub_date, + }; + }; + + const out = await Promise.all( + topics_list.map(async (item) => { + const $ = cheerio.load(item); + const title = $('.item-title > a'); + const link = title.attr('href'); + + const cache = await ctx.cache.get(link); + if (cache) { + return Promise.resolve(JSON.parse(cache)); + } + + const topic = { + title: title.text().trim(), + link: link, + }; + + try { + const topic_response = await got.get(link); + const result = parseContent(topic_response.data); + if (!result) { + return Promise.resolve(''); + } + + topic.author = result.author; + topic.description = result.description; + topic.pubDate = result.pubDate; + } catch (err) { + return Promise.resolve(''); + } + ctx.cache.set(link, JSON.stringify(topic)); + return Promise.resolve(topic); + }) + ); + + ctx.state.data = { + title: `TapTap论坛 ${app_name} - ${label_name}`, + link: url, + image: app_img, + item: out.filter((item) => item !== ''), + }; +};