diff --git a/docs/shopping.md b/docs/shopping.md index 11636b3168..253fed2302 100644 --- a/docs/shopping.md +++ b/docs/shopping.md @@ -105,6 +105,18 @@ pageClass: routes +### 中国 - 会员特惠 + + + +### 中国 - 低价优选 + + + +### 中国 - 当季新品推荐 + + + ## lativ ### 订阅价格 diff --git a/lib/v2/ikea/cn/family_offers.js b/lib/v2/ikea/cn/family_offers.js new file mode 100644 index 0000000000..528f5480c4 --- /dev/null +++ b/lib/v2/ikea/cn/family_offers.js @@ -0,0 +1,70 @@ +const got = require('@/utils/got'); +const { generateProductItem } = require('./utils'); + +const familyPriceProductsRequest = ({ pageIndex = 1 }) => + got({ + method: 'post', + url: 'https://www.ikea.cn/api-host/search/prod/advanced/special', + headers: { + 'X-Client-Platform': 'PcWeb', + }, + json: { + contentType: 'PRODUCT,CONTENT,PLANNER', + filters: { + filters: {}, + sortOption: 'RELEVANCE', + }, + pageIndex, + pageSize: 25, + pageType: '', + queryContent: 'family_price', + }, + }); + +const productRequest = async (productIds) => { + const response = await got({ + url: 'https://www.ikea.cn/api-host/content/products', + headers: { + 'X-Client-Platform': 'PcWeb', + }, + searchParams: new URLSearchParams(productIds), + }); + return response.data; +}; + +module.exports = async (ctx) => { + const familyPriceProductIds = []; + const productRequests = []; + + const familyPriceProductsLoadMore = async ({ pageIndex }) => { + const response = await familyPriceProductsRequest({ pageIndex }); + const { + data: { productPage, products }, + } = response.data; + + products.forEach(({ id }) => { + familyPriceProductIds.push(['ids', id]); + }); + + if (productPage.end < productPage.total) { + await familyPriceProductsLoadMore({ pageIndex: pageIndex + 1 }); + } + return Promise.resolve(); + }; + + await familyPriceProductsLoadMore({ pageIndex: 1 }); + + while (familyPriceProductIds.length) { + productRequests.push(productRequest(familyPriceProductIds.splice(0, 25))); + } + + const productResponses = await Promise.all(productRequests); + const products = productResponses.flat(); + + ctx.state.data = { + title: 'IKEA 宜家 - 会员特惠', + link: 'https://www.ikea.cn/cn/zh/offers/family-offers/', + description: '会员特惠', + item: products.map(generateProductItem), + }; +}; diff --git a/lib/v2/ikea/cn/low_price.js b/lib/v2/ikea/cn/low_price.js new file mode 100644 index 0000000000..7e353941e3 --- /dev/null +++ b/lib/v2/ikea/cn/low_price.js @@ -0,0 +1,22 @@ +const got = require('@/utils/got'); +const { generateRequestHeaders, generateProductItem } = require('./utils'); + +module.exports = async (ctx) => { + const response = await got({ + url: 'https://srv.app.ikea.cn/content/recommendation/v2/product-group/products', + headers: generateRequestHeaders(), + searchParams: { + processOutOfStock: 'SORT', + groupId: 'cms_低价好物_cms-商品列表-_0', + page: 1, + size: 200, + }, + }); + + ctx.state.data = { + title: 'IKEA 宜家 - 低价优选', + link: 'https://www.ikea.cn/cn/zh/campaigns/wo3-men2-de-chao1-zhi2-di1-jia4-pub8b08af40', + description: '低价优选', + item: response.data.products.map(generateProductItem), + }; +}; diff --git a/lib/v2/ikea/cn/new.js b/lib/v2/ikea/cn/new.js new file mode 100644 index 0000000000..5714d3d70c --- /dev/null +++ b/lib/v2/ikea/cn/new.js @@ -0,0 +1,39 @@ +const got = require('@/utils/got'); +const { generateRequestHeaders, generateProductItem } = require('./utils'); + +const request = ({ moreToken = '' }) => + got({ + method: 'post', + url: 'https://srv-mp.app.ikea.cn/content/search/products/advanced', + headers: generateRequestHeaders(), + searchParams: { + keyword: '新品', + moreToken, + }, + json: {}, + }); + +module.exports = async (ctx) => { + const allProductSummaries = []; + + const loadMoreRequest = async ({ moreToken }) => { + const response = await request({ moreToken }); + const { data } = response; + allProductSummaries.push(data.productSummaries); + if (data.moreToken) { + await loadMoreRequest({ moreToken: data.moreToken }); + } + return Promise.resolve(); + }; + + await loadMoreRequest({}); + + const products = allProductSummaries.flat(); + + ctx.state.data = { + title: 'IKEA 宜家 - 当季新品推荐', + link: 'https://www.ikea.cn/cn/zh/new/', + description: '当季新品推荐', + item: products.map(generateProductItem), + }; +}; diff --git a/lib/v2/ikea/cn/utils.js b/lib/v2/ikea/cn/utils.js new file mode 100644 index 0000000000..821a5ca70d --- /dev/null +++ b/lib/v2/ikea/cn/utils.js @@ -0,0 +1,42 @@ +const { art } = require('@/utils/render'); +const md5 = require('@/utils/md5'); +const path = require('path'); + +const generateRequestHeaders = () => { + const now = Math.round(new Date().getTime() / 1000); + return { + 'X-Client-Platform': 'WechatMiniprogram', + 'X-Client-DeviceId': md5(now.toString()), + }; +}; + +const generateProductItem = (product) => { + const { + productFullId, + name, + productType, + measureText, + priceDisplay: { currentPrice, originalPrice }, + images, + } = product; + const isFamilyOffer = currentPrice && originalPrice; + + return { + title: `${name} ${productType} - \u{000A5}${currentPrice}`, + description: art(path.join(__dirname, '../templates/cn/product.art'), { + isFamilyOffer, + name, + productType, + measureText, + currentPrice, + originalPrice, + images: images.map((image) => image.url), + }), + link: `https://www.ikea.cn/cn/zh/p/${productFullId}`, + }; +}; + +module.exports = { + generateRequestHeaders, + generateProductItem, +}; diff --git a/lib/v2/ikea/maintainer.js b/lib/v2/ikea/maintainer.js index 14b504aa31..56315aaf7e 100644 --- a/lib/v2/ikea/maintainer.js +++ b/lib/v2/ikea/maintainer.js @@ -1,4 +1,7 @@ module.exports = { + '/cn/family_offers': ['jzhangdev'], + '/cn/low_price': ['jzhangdev'], + '/cn/new': ['jzhangdev'], '/gb/new': ['HenryQW'], '/gb/offer': ['HenryQW'], }; diff --git a/lib/v2/ikea/radar.js b/lib/v2/ikea/radar.js index bfeca152ec..2733725d7c 100644 --- a/lib/v2/ikea/radar.js +++ b/lib/v2/ikea/radar.js @@ -16,4 +16,27 @@ module.exports = { }, ], }, + 'ikea.cn': { + _name: 'IKEA 宜家', + '.': [ + { + title: '中国 - 当季新品推荐', + docs: 'https://docs.rsshub.app/shopping.html#ikea-yi-jia', + source: ['/cn/zh/new/', '/'], + target: '/ikea/cn/new', + }, + { + title: '中国 - 低价优选', + docs: 'https://docs.rsshub.app/shopping.html#ikea-yi-jia', + source: ['/cn/zh/campaigns/wo3-men2-de-chao1-zhi2-di1-jia4-pub8b08af40', '/'], + target: '/ikea/cn/low_price', + }, + { + title: '中国 - 会员特惠', + docs: 'https://docs.rsshub.app/shopping.html#ikea-yi-jia', + source: ['/cn/zh/offers/family-offers', '/'], + target: '/ikea/cn/family_offers', + }, + ], + }, }; diff --git a/lib/v2/ikea/router.js b/lib/v2/ikea/router.js index 13210c57f8..dd7091fb2b 100644 --- a/lib/v2/ikea/router.js +++ b/lib/v2/ikea/router.js @@ -1,4 +1,7 @@ module.exports = (router) => { + router.get('/cn/family_offers', require('./cn/family_offers')); + router.get('/cn/low_price', require('./cn/low_price')); + router.get('/cn/new', require('./cn/new')); router.get('/gb/new', require('./gb/new')); router.get('/gb/offer', require('./gb/offer')); }; diff --git a/lib/v2/ikea/templates/cn/product.art b/lib/v2/ikea/templates/cn/product.art new file mode 100644 index 0000000000..7204bd3a1c --- /dev/null +++ b/lib/v2/ikea/templates/cn/product.art @@ -0,0 +1,14 @@ +

名称:{{name}}

+

类型:{{productType}}

+

尺寸:{{measureText}}

+{{if isFamilyOffer}} +

会员价格:¥{{currentPrice}}

+

非会员价格:¥{{originalPrice}}

+{{else}} +

价格:¥{{currentPrice}}

+{{/if}} +

+ {{each images}} + + {{/each}} +