diff --git a/docs/en/game.md b/docs/en/game.md index 66a24c2641a996..ff0137c3f12805 100755 --- a/docs/en/game.md +++ b/docs/en/game.md @@ -337,3 +337,15 @@ News data from https://warthunder.com/en/news/ The year, month and day provided under UTC time zone are the same as the official website, so please ignore the specific time!!! </RouteEn> + +## ファミ通 + +### Category + +<RouteEn author="TonyRL" example="/famitsu/category/new-article" path="/famitsu/category/:category?" :paramsDesc="['Category, see table below, `new-article` by default']" radar="1"> + +| 新着 | PS5 | Switch | PS4 | ニュース | ゲームニュース | PR TIMES | 動画 | 特集・企画記事 | インタビュー | 取材・リポート | レビュー | インディーゲーム | +| ----------- | --- | ------ | --- | ---- | --------- | -------- | ------ | --------------- | --------- | ------------ | ------ | ---------- | +| new-article | ps5 | switch | ps4 | news | news-game | prtimes | videos | special-article | interview | event-report | review | indie-game | + +</RouteEn> diff --git a/docs/game.md b/docs/game.md index fd2dcbb8ca8130..bebe6070a44a12 100644 --- a/docs/game.md +++ b/docs/game.md @@ -967,6 +967,18 @@ Example:`https://www.iyingdi.com/tz/people/55547` ,id 是 `55547` <Route author="magic-akari" example="/kirara/news" path="/kirara/news"/> +## ファミ通 + +### 分类 + +<Route author="TonyRL" example="/famitsu/category/new-article" path="/famitsu/category/:category?" :paramsDesc="['分类,见下表,预设为 `new-article`']" radar="1"> + +| 新着 | PS5 | Switch | PS4 | ニュース | ゲームニュース | PR TIMES | 動画 | 特集・企画記事 | インタビュー | 取材・リポート | レビュー | インディーゲーム | +| ----------- | --- | ------ | --- | ---- | --------- | -------- | ------ | --------------- | --------- | ------------ | ------ | ---------- | +| new-article | ps5 | switch | ps4 | news | news-game | prtimes | videos | special-article | interview | event-report | review | indie-game | + +</Route> + ## マギアレコード(Magia Record, 魔法纪录) ### 游戏公告 diff --git a/docs/shopping.md b/docs/shopping.md index ec7867fc10a0f7..835dd403eb77c4 100644 --- a/docs/shopping.md +++ b/docs/shopping.md @@ -461,19 +461,15 @@ For instance, in <https://www.leboncoin.fr/recherche/?**category=10&locations=Pa <Route author="DIYgod" example="/mi/crowdfunding" path="/mi/crowdfunding"/> +## 小米有品 + ### 小米有品众筹 -<Route author="DIYgod" example="/mi/youpin/crowdfunding" path="/mi/youpin/crowdfunding"/> +<Route author="bigfei" example="/xiaomiyoupin/crowdfunding" path="/xiaomiyoupin/crowdfunding"/> ### 小米有品每日上新 -<Route author="xyqfer DIYgod" example="/mi/youpin/new" path="/mi/youpin/new/:sort?" :paramsDesc="['排序,见下表']"> - -| 个性化排序 | 按销量从高到低 | 按好评从高到低 | 按上新时间从近到远 | -| ----- | ------- | ------- | --------- | -| 0 | 1 | 2 | 3 | - -</Route> +<Route author="xyqfer DIYgod bigfei" example="/xiaomiyoupin/latest" path="/xiaomiyoupin/latest" /> ## 宜家 IKEA diff --git a/lib/routes/mi/youpin/crowdfunding.js b/lib/routes/mi/youpin/crowdfunding.js deleted file mode 100644 index 2c211b140b39e0..00000000000000 --- a/lib/routes/mi/youpin/crowdfunding.js +++ /dev/null @@ -1,39 +0,0 @@ -const got = require('@/utils/got'); - -module.exports = async (ctx) => { - const response = await got({ - method: 'get', - url: 'https://home.mi.com/lasagne/page/5', - }); - - const data = response.data.floors.filter((floor) => floor.floor_id === 99 || floor.floor_id === 100); - const item = data.reduce((acc, item) => { - if (!item.data) { - return acc; - } - let goodsList = []; - - if (item.data.result) { - goodsList = item.data.result.goods_list; - } - - goodsList.forEach((goods) => { - const img = goods.pic_url; - acc.push({ - title: goods.name, - description: `<img src="${img}"><br>${goods.summary}<br>价格:${goods.market_price / 100}元`, - link: goods.jump_url, - pubDate: new Date(goods.first_release_time * 1000).toUTCString(), - }); - }); - - return acc; - }, []); - - ctx.state.data = { - title: '小米有品众筹', - link: 'https://m.xiaomiyoupin.com/w/crowdfunding?pageid=5', - description: '小米有品众筹', - item, - }; -}; diff --git a/lib/routes/mi/youpin/new.js b/lib/routes/mi/youpin/new.js deleted file mode 100644 index ddd1611c4a0c97..00000000000000 --- a/lib/routes/mi/youpin/new.js +++ /dev/null @@ -1,26 +0,0 @@ -const got = require('@/utils/got'); - -module.exports = async (ctx) => { - const response = await got({ - method: 'post', - url: 'https://m.xiaomiyoupin.com/homepage/main/v1005', - }); - - const items = response.data.data.homepage.floors - .filter((floor) => floor.module_key === 'product_hot')[0] - .data.items.map((item) => { - const i = item.item; - return { - title: i.name, - description: `<img src="${i.pic_url}"><br>${i.summary}<br>价格:${i.market_price / 100}元`, - link: i.jump_url, - }; - }); - - ctx.state.data = { - title: '小米有品每日上新', - link: 'https://m.xiaomiyoupin.com/w/newproduct?pageid=1605', - description: '小米有品每日上新', - item: items, - }; -}; diff --git a/lib/v2/famitsu/category.js b/lib/v2/famitsu/category.js new file mode 100644 index 00000000000000..0878b7a7b7adc2 --- /dev/null +++ b/lib/v2/famitsu/category.js @@ -0,0 +1,62 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); + +const baseUrl = 'https://www.famitsu.com'; + +module.exports = async (ctx) => { + const { category = 'new-article' } = ctx.params; + const url = `${baseUrl}/search/?category=${category}`; + const { data } = await got(url); + const $ = cheerio.load(data); + + const list = $('.col-12 .card__body') + .toArray() + .map((item) => { + item = $(item); + return { + title: item.find('.card__title').text(), + link: new URL(item.find('.card__title a').attr('href'), baseUrl).href, + pubDate: timezone(parseDate(item.find('time').attr('datetime'), 'YYYY.MM.DDTHH:mm'), +9), + }; + }) + .filter((item) => item.link.startsWith('https://www.famitsu.com/news/')); + + const items = await Promise.all( + list.map((item) => + ctx.cache.tryGet(item.link, async () => { + const { data } = await got(item.link); + const $ = cheerio.load(data); + + // remove ads + $('.article-body__contents-pr-primary').remove(); + + // fix header image + $('.article-body div.media-image').each((_, e) => { + e.tagName = 'img'; + e.attribs.src = e.attribs.style.match(/url\((.+?)\);/)[1]; + delete e.attribs['data-src']; + delete e.attribs.style; + }); + + // remove white space + $('.article-body__contents-img-block, .article-body__contents-img-common-col').each((_, e) => { + delete e.attribs.style; + }); + + item.description = $('.article-body').html(); + return item; + }) + ) + ); + + ctx.state.data = { + title: $('head title').text(), + description: $('head meta[name="description"]').attr('content'), + image: 'https://www.famitsu.com/img/1812/favicons/apple-touch-icon.png', + link: url, + item: items, + language: 'ja', + }; +}; diff --git a/lib/v2/famitsu/maintainer.js b/lib/v2/famitsu/maintainer.js new file mode 100644 index 00000000000000..670170cd9a284b --- /dev/null +++ b/lib/v2/famitsu/maintainer.js @@ -0,0 +1,3 @@ +module.exports = { + '/category/:category?': ['TonyRL'], +}; diff --git a/lib/v2/famitsu/radar.js b/lib/v2/famitsu/radar.js new file mode 100644 index 00000000000000..5bcec07144257c --- /dev/null +++ b/lib/v2/famitsu/radar.js @@ -0,0 +1,13 @@ +module.exports = { + 'famitsu.com': { + _name: 'ファミ通', + '.': [ + { + title: '分类', + docs: 'https://docs.rsshub.app/game.html#ファミ-tong', + source: ['/search'], + target: (_, url) => `/famitsu/category/${new URL(url).searchParams.get('category')}`, + }, + ], + }, +}; diff --git a/lib/v2/famitsu/router.js b/lib/v2/famitsu/router.js new file mode 100644 index 00000000000000..4f14521ba6b7c5 --- /dev/null +++ b/lib/v2/famitsu/router.js @@ -0,0 +1,3 @@ +module.exports = (router) => { + router.get('/category/:category?', require('./category')); +}; diff --git a/lib/v2/xiaomiyoupin/crowdfunding.js b/lib/v2/xiaomiyoupin/crowdfunding.js new file mode 100644 index 00000000000000..b5856ae459018f --- /dev/null +++ b/lib/v2/xiaomiyoupin/crowdfunding.js @@ -0,0 +1,15 @@ +const { parseModule, parseFloorItem } = require('./utils'); +const got = require('@/utils/got'); + +module.exports = async (ctx) => { + const response = await got('https://m.xiaomiyoupin.com/homepage/main/v1005'); + const floors = parseModule(response.data.data.homepage.floors, 'crowd_funding'); + const items = parseFloorItem(floors); + + ctx.state.data = { + title: '小米有品众筹', + link: floors.jump_url, + description: '小米有品众筹', + item: items, + }; +}; diff --git a/lib/v2/xiaomiyoupin/latest.js b/lib/v2/xiaomiyoupin/latest.js new file mode 100644 index 00000000000000..b27dd27b6e818f --- /dev/null +++ b/lib/v2/xiaomiyoupin/latest.js @@ -0,0 +1,15 @@ +const got = require('@/utils/got'); +const { parseModule, parseFloorItem } = require('./utils'); + +module.exports = async (ctx) => { + const response = await got('https://m.xiaomiyoupin.com/homepage/main/v1005'); + const floors = parseModule(response.data.data.homepage.floors, 'product_hot'); + const items = parseFloorItem(floors); + + ctx.state.data = { + title: '小米有品每日上新', + link: 'https://m.xiaomiyoupin.com/w/newproduct?pageid=1605', + description: '小米有品每日上新', + item: items, + }; +}; diff --git a/lib/v2/xiaomiyoupin/maintainer.js b/lib/v2/xiaomiyoupin/maintainer.js new file mode 100644 index 00000000000000..45ce330d7e1548 --- /dev/null +++ b/lib/v2/xiaomiyoupin/maintainer.js @@ -0,0 +1,4 @@ +module.exports = { + '/crowdfunding': ['bigfei'], + '/latest': ['xyqfer', 'DIYgod', 'bigfei'], +}; diff --git a/lib/v2/xiaomiyoupin/radar.js b/lib/v2/xiaomiyoupin/radar.js new file mode 100644 index 00000000000000..d04b8aeba0e8b8 --- /dev/null +++ b/lib/v2/xiaomiyoupin/radar.js @@ -0,0 +1,19 @@ +module.exports = { + 'xiaomiyoupin.com': { + _name: '小米有品', + '.': [ + { + title: '小米有品众筹', + docs: 'https://docs.rsshub.app/shopping.html#xiao-mi-you-pin-xiao-mi-you-pin-zhong-chou', + source: ['/'], + target: '/xiaomiyoupin/crowdfunding', + }, + { + title: '小米有品每日上新', + docs: 'https://docs.rsshub.app/shopping.html#xiao-mi-you-pin-xiao-mi-you-pin-mei-ri-shang-xin', + source: ['/'], + target: '/xiaomiyoupin/latest', + }, + ], + }, +}; diff --git a/lib/v2/xiaomiyoupin/router.js b/lib/v2/xiaomiyoupin/router.js new file mode 100644 index 00000000000000..f0d58824012dd5 --- /dev/null +++ b/lib/v2/xiaomiyoupin/router.js @@ -0,0 +1,4 @@ +module.exports = function (router) { + router.get('/crowdfunding', require('./crowdfunding')); + router.get('/latest', require('./latest')); +}; diff --git a/lib/v2/xiaomiyoupin/templates/goods.art b/lib/v2/xiaomiyoupin/templates/goods.art new file mode 100644 index 00000000000000..b54f1370173a40 --- /dev/null +++ b/lib/v2/xiaomiyoupin/templates/goods.art @@ -0,0 +1,27 @@ +<figure> + <img src="{{ pic_url || imgs.img800 }}" alt="{{ alt }}" loading="lazy" style="display:block; margin-left:auto; margin-right:auto;" width:100%;> + {{if videos_url }} + <video controls + playsinline="true" + webkit-playsinline="true" + x5-playsinline="true" + x5-video-player-type="h5" + x5-video-orientation="landscape|portrait" + x5-video-player-fullscreen="true" + x-webkit-airplay="allow" + preload="metadata" + poster="{{ pic_url || imgs.img800 }}"> + <source src="{{ videos_url[0] }}" type="video/mp4"/> + </video> + {{/if}} + + {{if name }} + <figcaption> + <div class="caption">{{@ name }}</div> + <div class="credit">{{@ summary }}</div> + <div class="price">原始价格:{{@ market_price / 100 }}元</div> + <div class="price">实际价格:{{@ (price_min || flash_price) / 100 }}元</div> + </figcaption> + {{/if}} + +</figure> diff --git a/lib/v2/xiaomiyoupin/utils.js b/lib/v2/xiaomiyoupin/utils.js new file mode 100644 index 00000000000000..7b83176c357f74 --- /dev/null +++ b/lib/v2/xiaomiyoupin/utils.js @@ -0,0 +1,21 @@ +const { art } = require('@/utils/render'); +const path = require('path'); + +const parseModule = (floors, module_key) => floors.filter((floor) => floor.module_key === module_key)[0]; + +const parseFloorItem = (floor) => + floor.data.items.map((item) => { + const i = item.item; + return { + title: i.name, + link: i.jump_url, + guid: `xiaomiyoupin:${i.gid}`, + description: art(path.join(__dirname, 'templates/goods.art'), i), + pubDate: (i.start || i.start_time) * 1000, + }; + }); + +module.exports = { + parseModule, + parseFloorItem, +};