UNPKG

rsshub

Version:
198 lines (186 loc) 5.87 kB
import { Route } from '@/types'; import cache from '@/utils/cache'; import got from '@/utils/got'; import { load } from 'cheerio'; export const route: Route = { path: '/news/:language?/:category?', categories: ['game'], example: '/blizzard/news', parameters: { language: 'Language code, see below, en-US by default', category: 'Category, see below, All News by default' }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false, }, name: 'News', maintainers: ['nczitzk'], handler, description: `Categories | Category | Slug | | ---------------------- | ------------------- | | All News | | | Diablo II: Resurrected | diablo2 | | Diablo III | diablo3 | | Diablo IV | diablo4 | | Diablo Immortal | diablo-immortal | | Hearthstone | hearthstone | | Heroes of the Storm | heroes-of-the-storm | | Overwatch 2 | overwatch | | StarCraft: Remastered | starcraft | | StarCraft II | starcraft2 | | World of Warcraft | world-of-warcraft | | Warcraft 3: Reforged | warcraft3 | | Warcraft Rumble | warcraft-rumble | | Battle.net | battlenet | | BlizzCon | blizzcon | | Inside Blizzard | blizzard | Language codes | Language | Code | | ------------------ | ----- | | Deutsch | de-de | | English (US) | en-us | | English (EU) | en-gb | | Español (EU) | es-es | | Español (Latino) | es-mx | | Français | fr-fr | | Italiano | it-it | | Português (Brasil) | pt-br | | Polski | pl-pl | | Русский | ru-ru | | 한국어 | ko-kr | | ภาษาไทย | th-th | | 日本語 | ja-jp | | 繁體中文 | zh-tw |`, }; const GAME_MAP = { diablo2: { key: 'diablo2', value: 'diablo-2-resurrected', id: 'blt54fbd3787a705054', }, diablo3: { key: 'diablo3', value: 'diablo-3', id: 'blt2031aef34200656d', }, diablo4: { key: 'diablo4', value: 'diablo-4', id: 'blt795c314400d7ded9', }, 'diablo-immortal': { key: 'diablo-immortal', value: 'diablo-immortal', id: 'blt525c436e4a1b0a97', }, hearthstone: { key: 'hearthstone', value: 'hearthstone', id: 'blt5cfc6affa3ca0638', }, 'heroes-of-the-storm': { key: 'heroes-of-the-storm', value: 'heroes-of-the-storm', id: 'blt2e50e1521bb84dc6', }, overwatch: { key: 'overwatch', value: 'overwatch', id: 'blt376fb94931906b6f', }, starcraft: { key: 'starcraft', value: 'starcraft', id: 'blt81d46fcb05ab8811', }, starcraft2: { key: 'starcraft2', value: 'starcraft-2', id: 'bltede2389c0a8885aa', }, 'world-of-warcraft': { key: 'world-of-warcraft', value: 'world-of-warcraft', id: 'blt2caca37e42f19839', }, warcraft3: { key: 'warcraft3', value: 'warcraft-3', id: 'blt24859ba8086fb294', }, 'warcraft-rumble': { key: 'warcraft-rumble', value: 'warcraft-rumble', id: 'blte27d02816a8ff3e1', }, battlenet: { key: 'battlenet', value: 'battle-net', id: 'blt90855744d00cd378', }, blizzcon: { key: 'blizzcon', value: 'blizzcon', id: 'bltec70ad0ea4fd6d1d', }, blizzard: { key: 'blizzard', value: 'blizzard', id: 'blt500c1f8b5470bfdb', }, }; function getSearchParams(category = 'all') { return category === 'all' ? Object.values(GAME_MAP) .map((item) => `feedCxpProductIds[]=${item.id}`) .join('&') : `feedCxpProductIds[]=${GAME_MAP[category].id}`; } async function handler(ctx) { const category = GAME_MAP[ctx.req.param('category')]?.key || 'all'; const language = ctx.req.param('language') || 'en-us'; const rootUrl = `https://news.blizzard.com/${language}`; const currentUrl = category === 'all' ? rootUrl : `${rootUrl}/?filter=${GAME_MAP[category].value}`; const apiUrl = `${rootUrl}/api/news/blizzard`; let rssTitle = ''; const { data: { feed: { contentItems: response }, }, } = await got(`${apiUrl}?${getSearchParams(category)}`); const list = response.map((item) => { const content = item.properties; rssTitle = category === 'all' ? 'All News' : content.cxpProduct.title; // 这个是用来填充 RSS 订阅源频道级别 title,没别的地方能拿到了(而且会根据语言切换) return { title: content.title, link: content.newsUrl, author: content.author, category: content.category, guid: content.newsId, description: content.summary, pubDate: content.lastUpdated, }; }); const items = await Promise.all( list.map((item) => cache.tryGet(item.link, async () => { try { const { data: response } = await got(item.link); const $ = load(response); item.description = $('.Content').html(); return item; } catch { return item; } }) ) ); return { title: rssTitle, link: currentUrl, item: items, }; }