-
Notifications
You must be signed in to change notification settings - Fork 8.8k
feat(route): add 小木游戏情报 #20147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(route): add 小木游戏情报 #20147
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,224 @@ | ||
| import { Route } from '@/types'; | ||
| import ofetch from '@/utils/ofetch'; | ||
| import { load } from 'cheerio'; | ||
| import { parseDate } from '@/utils/parse-date'; | ||
| import logger from '@/utils/logger'; | ||
|
|
||
| export const route: Route = { | ||
| path: '/', | ||
| name: '最新文章', | ||
| url: 'xiaomuacg.com', | ||
| maintainers: ['xiaomuacg'], | ||
| example: '/xiaomuacg', | ||
| parameters: {}, | ||
| description: '小木游戏情报最新文章', | ||
| categories: ['game'], | ||
| features: { | ||
| requireConfig: false, | ||
| requirePuppeteer: false, | ||
| antiCrawler: true, // 改为true,因为网站有反爬虫机制 | ||
| supportRadar: true, | ||
| supportBT: false, | ||
| supportPodcast: false, | ||
| supportScihub: false, | ||
| }, | ||
| radar: [ | ||
| { | ||
| source: ['xiaomuacg.com'], | ||
| target: '/', | ||
| }, | ||
| ], | ||
| handler, | ||
| }; | ||
|
|
||
| async function handler() { | ||
| const baseUrl = 'https://xiaomuacg.com'; | ||
|
|
||
| // 添加请求头配置 | ||
| const headers = { | ||
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', | ||
| 'Accept': 'application/rss+xml, application/xml, text/xml, text/html, */*', | ||
| 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', | ||
| 'Accept-Encoding': 'gzip, deflate, br', | ||
| 'Cache-Control': 'no-cache', | ||
| 'Pragma': 'no-cache', | ||
| 'Referer': baseUrl, | ||
| 'Sec-Fetch-Dest': 'document', | ||
| 'Sec-Fetch-Mode': 'navigate', | ||
| 'Sec-Fetch-Site': 'same-origin', | ||
| 'Upgrade-Insecure-Requests': '1' | ||
| }; | ||
|
|
||
| try { | ||
| // 首先尝试获取网站的 RSS feed | ||
| logger.http(`Fetching RSS feed from: ${baseUrl}/feed/`); | ||
| const feedResponse = await ofetch(`${baseUrl}/feed/`, { | ||
| headers, | ||
| timeout: 10000, | ||
| retry: 2, | ||
| retryDelay: 1000 | ||
| }); | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| logger.info(`RSS feed response length: ${feedResponse.length}`); | ||
|
|
||
| const $ = load(feedResponse, { xmlMode: true }); | ||
|
|
||
| // 检查 RSS 格式 | ||
| const channelTitle = $('channel > title').text(); | ||
| const itemCount = $('item').length; | ||
| logger.info(`Channel title: ${channelTitle}, Item count: ${itemCount}`); | ||
|
|
||
| if (itemCount === 0) { | ||
| // 如果没有找到 item,尝试其他可能的结构 | ||
| const entries = $('entry').length; // Atom feed | ||
| logger.info(`Atom entries count: ${entries}`); | ||
|
|
||
| if (entries === 0) { | ||
| throw new Error('No items or entries found in feed'); | ||
| } | ||
| } | ||
|
|
||
| // 解析 RSS 条目 | ||
| const list = $('item') | ||
| .slice(0, 10) | ||
| .toArray() | ||
| .map((item) => { | ||
| const $item = $(item); | ||
| const title = $item.find('title').text().trim(); | ||
| const link = $item.find('link').text().trim(); | ||
| const pubDate = $item.find('pubDate').text().trim(); | ||
| const description = $item.find('description').text().trim(); | ||
|
|
||
| logger.debug(`Processing item: ${title}`); | ||
|
|
||
| return { | ||
| title: title || 'No title', | ||
| link: link || baseUrl, | ||
| pubDate: pubDate ? parseDate(pubDate) : new Date(), | ||
| category: $item | ||
| .find('category') | ||
| .toArray() | ||
| .map((cat) => $(cat).text()), | ||
| description: description || 'No description', | ||
| }; | ||
| }); | ||
|
|
||
| logger.info(`Parsed list length: ${list.length}`); | ||
|
|
||
| if (list.length === 0) { | ||
| throw new Error('No valid items parsed from RSS feed'); | ||
| } | ||
|
|
||
| const result = { | ||
| title: channelTitle || '小木游戏情报 - 游戏、动漫资讯', | ||
| link: baseUrl, | ||
| description: '小木游戏情报最新文章', | ||
| item: list, | ||
| }; | ||
|
|
||
| logger.info(`Final result items count: ${result.item.length}`); | ||
| return result; | ||
| } catch (error) { | ||
| logger.error(`Error in RSS handler: ${error}`); | ||
|
|
||
| // 提供备用方案,直接抓取网站首页 | ||
| try { | ||
| logger.info('RSS failed, trying to fetch homepage as fallback...'); | ||
| const response = await ofetch(baseUrl, { | ||
| headers, | ||
| timeout: 10000, | ||
| retry: 2, | ||
| retryDelay: 1000 | ||
| }); | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| const $ = load(response); | ||
|
|
||
| // 尝试多种选择器来找到文章 | ||
| let articles = $('article').slice(0, 10); | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| if (articles.length === 0) { | ||
| articles = $('.post, .entry, .content-item, .item, .news-item').slice(0, 10); | ||
| } | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| if (articles.length === 0) { | ||
| // 如果还是找不到,尝试查找包含链接的元素 | ||
| articles = $('div:has(h1), div:has(h2), div:has(h3)').slice(0, 10); | ||
| } | ||
|
|
||
| if (articles.length === 0) { | ||
| throw new Error('No articles found on homepage'); | ||
| } | ||
|
|
||
| const items = articles.toArray().map((article, index) => { | ||
| const $article = $(article); | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| // 尝试多种方式找标题 | ||
| let titleEl = $article.find('h1, h2, h3, .title, .post-title, .entry-title').first(); | ||
| if (!titleEl.length) { | ||
| titleEl = $article.find('a').first(); | ||
| } | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| // 尝试多种方式找链接 | ||
| let linkEl = $article.find('a').first(); | ||
| if (!linkEl.length) { | ||
| linkEl = $article.find('h1 a, h2 a, h3 a').first(); | ||
| } | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| const title = titleEl.text().trim() || `文章 ${index + 1}`; | ||
| const link = linkEl.attr('href') ? new URL(linkEl.attr('href'), baseUrl).href : baseUrl; | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| // 尝试获取描述 | ||
| let description = $article.find('.excerpt, .summary, .content, p').first().text().trim(); | ||
| if (!description) { | ||
| description = $article.text().slice(0, 200).trim(); | ||
| } | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| // 尝试获取日期 | ||
| let pubDate = new Date(); | ||
| const dateText = $article.find('.date, .time, .published, time').first().text().trim(); | ||
| if (dateText) { | ||
| try { | ||
| pubDate = parseDate(dateText); | ||
| } catch (e) { | ||
Check failureCode scanning / ESLint Prefer omitting the `catch` binding parameter. Error
Remove unused catch binding e.
Check failureCode scanning / ESLint Enforce a specific parameter name in catch clauses. Error
The catch parameter e should be named error_.
Check failureCode scanning / ESLint Disallow unused variables Error
'e' is defined but never used.
|
||
| logger.debug(`Failed to parse date: ${dateText}`); | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| title, | ||
| link, | ||
| description: description.substring(0, 200) + (description.length > 200 ? '...' : ''), | ||
Check warningCode scanning / ESLint Prefer `String#slice()` over `String#substr()` and `String#substring()`. Warning
Prefer String#slice() over String#substring().
|
||
| pubDate, | ||
| }; | ||
| }); | ||
|
|
||
| if (items.length === 0) { | ||
| throw new Error('No valid items parsed from homepage'); | ||
| } | ||
|
|
||
| logger.info(`Fallback parsed ${items.length} items`); | ||
|
|
||
| return { | ||
| title: '小木游戏情报 - 独立动漫、游戏情报', | ||
| link: baseUrl, | ||
| description: 'XIAOMUACG(小木游戏情报)是一个独立运营的 ACG 情报博客,为二次元和游戏爱好者提供最新、可靠的资讯。', | ||
| item: items, | ||
| }; | ||
| } catch (fallbackError) { | ||
| logger.error(`Fallback also failed: ${fallbackError}`); | ||
|
|
||
Check failureCode scanning / ESLint Disallow trailing whitespace at the end of lines Error
Trailing spaces not allowed.
|
||
| // 最终fallback:返回基本信息 | ||
| return { | ||
| title: '小木游戏情报', | ||
| link: baseUrl, | ||
| description: '暂时无法获取最新文章,请稍后再试。', | ||
| item: [{ | ||
| title: '网站暂时无法访问', | ||
| link: baseUrl, | ||
| description: `访问出现问题:${error.message}`, | ||
| pubDate: new Date(), | ||
| }], | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import type { Namespace } from '@/types'; | ||
|
|
||
| export const namespace: Namespace = { | ||
| name: 'xiaomuacg', | ||
| url: 'xiaomuacg.com', | ||
| description: 'XIAOMUACG(小木游戏情报)是一个独立运营的 ACG 情报博客,为二次元和游戏爱好者提供最新、可靠的资讯。无论是游戏上线动态、限时免费活动,还是各类大促信息,或是最新动漫作品的更新,都能通过本站点查阅。', | ||
| zh: { | ||
| name: '小木游戏情报', | ||
| }, | ||
| }; |
Check failure
Code scanning / ESLint
Disallow trailing whitespace at the end of lines Error