From a77c5f43b95b6029cab8944923519dd5589e4337 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 2 Apr 2025 11:41:19 -0700 Subject: [PATCH] feat(route): recover psnine (#18760) * feat: recover psnine * fix: update path --- lib/router.js | 12 ---- lib/routes-deprecated/psnine/game.js | 32 ----------- lib/routes-deprecated/psnine/index.js | 33 ----------- lib/routes-deprecated/psnine/news.js | 53 ----------------- lib/routes-deprecated/psnine/node.js | 54 ----------------- lib/routes-deprecated/psnine/shuzhe.js | 33 ----------- lib/routes-deprecated/psnine/trade.js | 39 ------------- lib/routes/psnine/game.ts | 42 ++++++++++++++ lib/routes/psnine/index.ts | 58 +++++++++++++++++++ lib/routes/psnine/namespace.ts | 8 +++ lib/routes/psnine/node.ts | 80 ++++++++++++++++++++++++++ lib/routes/psnine/shuzhe.ts | 43 ++++++++++++++ lib/routes/psnine/trade.ts | 58 +++++++++++++++++++ 13 files changed, 289 insertions(+), 256 deletions(-) delete mode 100644 lib/routes-deprecated/psnine/game.js delete mode 100644 lib/routes-deprecated/psnine/index.js delete mode 100644 lib/routes-deprecated/psnine/news.js delete mode 100644 lib/routes-deprecated/psnine/node.js delete mode 100644 lib/routes-deprecated/psnine/shuzhe.js delete mode 100644 lib/routes-deprecated/psnine/trade.js create mode 100644 lib/routes/psnine/game.ts create mode 100644 lib/routes/psnine/index.ts create mode 100644 lib/routes/psnine/namespace.ts create mode 100644 lib/routes/psnine/node.ts create mode 100644 lib/routes/psnine/shuzhe.ts create mode 100644 lib/routes/psnine/trade.ts diff --git a/lib/router.js b/lib/router.js index 9ab78428ed..708cadd58b 100644 --- a/lib/router.js +++ b/lib/router.js @@ -564,18 +564,6 @@ router.get('/zjgsu/xszq', lazyloadRouteHandler('./routes/universities/zjgsu/xszq router.get('/banyuetan/byt/:time?', lazyloadRouteHandler('./routes/banyuetan/byt')); router.get('/banyuetan/:name', lazyloadRouteHandler('./routes/banyuetan')); -// gamersky -router.get('/gamersky/news', lazyloadRouteHandler('./routes/gamersky/news')); -router.get('/gamersky/ent/:category', lazyloadRouteHandler('./routes/gamersky/ent')); - -// psnine -router.get('/psnine/index', lazyloadRouteHandler('./routes/psnine/index')); -router.get('/psnine/shuzhe', lazyloadRouteHandler('./routes/psnine/shuzhe')); -router.get('/psnine/trade', lazyloadRouteHandler('./routes/psnine/trade')); -router.get('/psnine/game', lazyloadRouteHandler('./routes/psnine/game')); -router.get('/psnine/news/:order?', lazyloadRouteHandler('./routes/psnine/news')); -router.get('/psnine/node/:id?/:order?', lazyloadRouteHandler('./routes/psnine/node')); - // 浙江大学城市学院 router.get('/zucc/news/latest', lazyloadRouteHandler('./routes/universities/zucc/news')); router.get('/zucc/cssearch/latest/:webVpn/:key', lazyloadRouteHandler('./routes/universities/zucc/cssearch')); diff --git a/lib/routes-deprecated/psnine/game.js b/lib/routes-deprecated/psnine/game.js deleted file mode 100644 index 18a817c14d..0000000000 --- a/lib/routes-deprecated/psnine/game.js +++ /dev/null @@ -1,32 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const { parseRelativeDate } = require('@/utils/parse-date'); - -module.exports = async (ctx) => { - const url = 'https://www.psnine.com/psngame'; - const response = await got({ - method: 'get', - url, - }); - - const data = response.data; - const $ = cheerio.load(data); - - const out = $('table tr') - .map(function () { - const info = { - title: $(this).find('.title a').text(), - link: $(this).find('.title a').attr('href'), - pubDate: parseRelativeDate($(this).find('.meta').text()), - description: $(this).find('.title span').text() + ' ' + $(this).find('.twoge').text(), - }; - return info; - }) - .get(); - - ctx.state.data = { - title: 'psnine-' + $('title').text(), - link: 'https://www.psnine.com/', - item: out, - }; -}; diff --git a/lib/routes-deprecated/psnine/index.js b/lib/routes-deprecated/psnine/index.js deleted file mode 100644 index 4e6cf72393..0000000000 --- a/lib/routes-deprecated/psnine/index.js +++ /dev/null @@ -1,33 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const { parseRelativeDate } = require('@/utils/parse-date'); - -module.exports = async (ctx) => { - const url = 'https://www.psnine.com/'; - const response = await got({ - method: 'get', - url, - }); - - const data = response.data; - const $ = cheerio.load(data); - - const out = $('.list li') - .slice(0, 20) - .map(function () { - const info = { - title: $(this).find('.title').text(), - link: $(this).find('.title a').attr('href'), - pubDate: parseRelativeDate($(this).find('.meta').text()), - author: $(this).find('.meta a').text(), - }; - return info; - }) - .get(); - - ctx.state.data = { - title: 'psnine-' + $('title').text(), - link: 'https://www.psnine.com/', - item: out, - }; -}; diff --git a/lib/routes-deprecated/psnine/news.js b/lib/routes-deprecated/psnine/news.js deleted file mode 100644 index 1e5b9ee1dc..0000000000 --- a/lib/routes-deprecated/psnine/news.js +++ /dev/null @@ -1,53 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); - -module.exports = async (ctx) => { - const order = ctx.params.order || 'obdate'; - - const rootUrl = 'https://www.psnine.com'; - const currentUrl = `${rootUrl}/node/news?ob=${order}`; - const response = await got({ - method: 'get', - url: currentUrl, - }); - - const $ = cheerio.load(response.data); - - $('.psnnode, .node').remove(); - - const list = $('.title a') - .map((_, item) => { - item = $(item); - const date = item.parent().next().text().trim(); - - return { - title: item.text(), - link: item.attr('href'), - pubDate: new Date(date.length === 11 ? `${new Date().getFullYear()}-${date}` : date).toUTCString(), - }; - }) - .get(); - - const items = await Promise.all( - list.map((item) => - ctx.cache.tryGet(item.link, async () => { - const detailResponse = await got({ - method: 'get', - url: item.link, - }); - const content = cheerio.load(detailResponse.data); - - item.author = content('a[itemprop="author"]').eq(0).text(); - item.description = content('div[itemprop="articleBody"]').html(); - - return item; - }) - ) - ); - - ctx.state.data = { - title: `${$('title').text()} - PSN中文站`, - link: currentUrl, - item: items, - }; -}; diff --git a/lib/routes-deprecated/psnine/node.js b/lib/routes-deprecated/psnine/node.js deleted file mode 100644 index 02b0625a3d..0000000000 --- a/lib/routes-deprecated/psnine/node.js +++ /dev/null @@ -1,54 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); - -module.exports = async (ctx) => { - const id = ctx.params.id || 'news'; - const order = ctx.params.order || 'obdate'; - - const rootUrl = 'https://www.psnine.com'; - const currentUrl = `${rootUrl}/node/${id}?ob=${order}`; - const response = await got({ - method: 'get', - url: currentUrl, - }); - - const $ = cheerio.load(response.data); - - $('.psnnode, .node').remove(); - - const list = $('.title a') - .map((_, item) => { - item = $(item); - const date = item.parent().next().text().trim(); - - return { - title: item.text(), - link: item.attr('href'), - pubDate: new Date(date.length === 11 ? `${new Date().getFullYear()}-${date}` : date).toUTCString(), - }; - }) - .get(); - - const items = await Promise.all( - list.map((item) => - ctx.cache.tryGet(item.link, async () => { - const detailResponse = await got({ - method: 'get', - url: item.link, - }); - const content = cheerio.load(detailResponse.data); - - item.author = content('a[itemprop="author"]').eq(0).text(); - item.description = content('div[itemprop="articleBody"]').html(); - - return item; - }) - ) - ); - - ctx.state.data = { - title: `${$('title').text()} - PSN中文站`, - link: currentUrl, - item: items, - }; -}; diff --git a/lib/routes-deprecated/psnine/shuzhe.js b/lib/routes-deprecated/psnine/shuzhe.js deleted file mode 100644 index 671911101f..0000000000 --- a/lib/routes-deprecated/psnine/shuzhe.js +++ /dev/null @@ -1,33 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const { parseRelativeDate } = require('@/utils/parse-date'); - -module.exports = async (ctx) => { - const url = 'https://www.psnine.com/dd'; - const response = await got({ - method: 'get', - url, - }); - - const data = response.data; - const $ = cheerio.load(data); - - const out = $('.dd_ul li') - .map(function () { - const info = { - title: $(this).find('.dd_title').text(), - link: $(this).find('.dd_title a').attr('href'), - description: $(this).find('.dd_status').text(), - pubDate: parseRelativeDate($(this).find('.meta').text()), - author: $(this).find('.meta a').text(), - }; - return info; - }) - .get(); - - ctx.state.data = { - title: 'psnine-' + $('title').text(), - link: 'https://www.psnine.com/', - item: out, - }; -}; diff --git a/lib/routes-deprecated/psnine/trade.js b/lib/routes-deprecated/psnine/trade.js deleted file mode 100644 index 5de4784d9d..0000000000 --- a/lib/routes-deprecated/psnine/trade.js +++ /dev/null @@ -1,39 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const { parseRelativeDate } = require('@/utils/parse-date'); - -module.exports = async (ctx) => { - const url = 'https://www.psnine.com/trade'; - const response = await got({ - method: 'get', - url, - }); - - const data = response.data; - const $ = cheerio.load(data); - - const out = $('.list li') - .map(function () { - const desc = []; - $(this) - .find('.meta a') - .each(function (i) { - desc[i] = $(this).text(); - }); - const info = { - title: $(this).find('.content').text(), - link: $(this).find('.touch').attr('href'), - description: desc.join(' '), - pubDate: parseRelativeDate($(this).find('.meta').text()), - author: $(this).find('.psnnode').text(), - }; - return info; - }) - .get(); - - ctx.state.data = { - title: 'psnine-' + $('title').text(), - link: 'https://www.psnine.com/', - item: out, - }; -}; diff --git a/lib/routes/psnine/game.ts b/lib/routes/psnine/game.ts new file mode 100644 index 0000000000..a9960ab2d7 --- /dev/null +++ b/lib/routes/psnine/game.ts @@ -0,0 +1,42 @@ +import type { Route } from '@/types'; + +import ofetch from '@/utils/ofetch'; +import * as cheerio from 'cheerio'; + +const handler = async () => { + const url = 'https://www.psnine.com/psngame'; + const response = await ofetch(url); + + const $ = cheerio.load(response); + + const out = $('table tr') + .toArray() + .map((item) => { + const $item = $(item); + return { + title: $item.find('.title a').text(), + link: $item.find('.title a').attr('href'), + description: $item.find('.title span').text() + ' ' + $item.find('.twoge').text(), + }; + }); + + return { + title: $('head title').text(), + link: url, + item: out, + }; +}; + +export const route: Route = { + path: '/game', + categories: ['game'], + example: '/psnine/game', + name: '游戏', + maintainers: ['betta-cyber'], + handler, + radar: [ + { + source: ['psnine.com/psngame', 'psnine.com'], + }, + ], +}; diff --git a/lib/routes/psnine/index.ts b/lib/routes/psnine/index.ts new file mode 100644 index 0000000000..095a9b30f0 --- /dev/null +++ b/lib/routes/psnine/index.ts @@ -0,0 +1,58 @@ +import type { Route } from '@/types'; + +import ofetch from '@/utils/ofetch'; +import * as cheerio from 'cheerio'; +import { parseRelativeDate } from '@/utils/parse-date'; + +const handler = async () => { + const url = 'https://www.psnine.com/'; + const response = await ofetch(url); + + const $ = cheerio.load(response); + + const out = $('.list li') + .toArray() + .map((item) => { + const $item = $(item); + return { + title: $item.find('.title').text(), + link: $item.find('.title a').attr('href'), + pubDate: parseRelativeDate( + $item + .find('.meta') + .contents() + .filter((_, i) => i.nodeType === 3) + .text() + .trim() + .split(/\s{2,}/)[0] + ), + author: $item.find('.meta a.psnnode').text(), + category: $item + .find('.meta a.node') + .toArray() + .map((a) => $(a).text()), + }; + }); + + return { + title: $('head title').text(), + description: $('head meta[name="description"]').attr('content'), + image: `${url}/View/aimage/p9.png`, + link: url, + item: out, + }; +}; + +export const route: Route = { + path: '/', + categories: ['game'], + example: '/psnine', + name: '首页', + maintainers: ['betta-cyber'], + handler, + radar: [ + { + source: ['psnine.com'], + }, + ], +}; diff --git a/lib/routes/psnine/namespace.ts b/lib/routes/psnine/namespace.ts new file mode 100644 index 0000000000..85580220c0 --- /dev/null +++ b/lib/routes/psnine/namespace.ts @@ -0,0 +1,8 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: 'PSN 中文站', + url: 'psnine.com', + lang: 'zh-CN', + categories: ['game'], +}; diff --git a/lib/routes/psnine/node.ts b/lib/routes/psnine/node.ts new file mode 100644 index 0000000000..47823c7efc --- /dev/null +++ b/lib/routes/psnine/node.ts @@ -0,0 +1,80 @@ +import type { Route } from '@/types'; + +import ofetch from '@/utils/ofetch'; +import * as cheerio from 'cheerio'; +import { parseDate } from '@/utils/parse-date'; +import timezone from '@/utils/timezone'; +import cache from '@/utils/cache'; + +const handler = async (ctx) => { + const { id = 'news', order = 'obdate' } = ctx.req.param(); + + const rootUrl = 'https://www.psnine.com'; + const currentUrl = `${rootUrl}/node/${id}?ob=${order}`; + const response = await ofetch(currentUrl); + + const $ = cheerio.load(response); + + $('.psnnode, .node').remove(); + + const list = $('.title a') + .toArray() + .map((item) => { + const $item = $(item); + const meta = $item.parent().next(); + return { + title: $item.text(), + link: $item.attr('href'), + pubDate: timezone( + parseDate( + meta + .contents() + .filter((_, i) => i.nodeType === 3) + .text() + .trim() + .split(/\s{2,}/)[0], + ['YYYY-MM-DD HH:mm', 'MM-DD HH:mm'] + ), + 8 + ), + }; + }); + + const items = await Promise.all( + list.map((item) => + cache.tryGet(item.link, async () => { + const detailResponse = await ofetch(item.link); + const $ = cheerio.load(detailResponse); + + item.author = $('a[itemprop="author"]').eq(0).text(); + item.description = $('div[itemprop="articleBody"]').html(); + + return item; + }) + ) + ); + + return { + title: `${$('title').text()} - PSN中文站`, + link: currentUrl, + item: items, + }; +}; + +export const route: Route = { + path: '/node/:id?/:order?', + parameters: { + id: '节点 id,见下表,默认为 news', + order: '排序,`date` 即最新,默认为 `obdate` 即综合排序', + }, + categories: ['game'], + example: '/psnine/node/news', + name: '节点', + maintainers: ['betta-cyber', 'nczitzk'], + handler, + radar: [ + { + source: ['psnine.com/node/:id'], + }, + ], +}; diff --git a/lib/routes/psnine/shuzhe.ts b/lib/routes/psnine/shuzhe.ts new file mode 100644 index 0000000000..312dd8022a --- /dev/null +++ b/lib/routes/psnine/shuzhe.ts @@ -0,0 +1,43 @@ +import type { Route } from '@/types'; + +import ofetch from '@/utils/ofetch'; +import * as cheerio from 'cheerio'; + +const handler = async () => { + const url = 'https://www.psnine.com/dd'; + const response = await ofetch(url); + + const $ = cheerio.load(response); + + const out = $('.dd_ul li') + .toArray() + .map((item) => { + const $item = $(item); + return { + title: $item.find('.dd_title').text(), + link: $item.find('.dd_title a').attr('href'), + description: $item.find('.dd_status').text(), + author: $item.find('.meta a').text(), + }; + }); + + return { + title: $('head title').text(), + link: 'https://www.psnine.com/', + item: out, + }; +}; + +export const route: Route = { + path: '/shuzhe', + categories: ['game'], + example: '/psnine/shuzhe', + name: '数折', + maintainers: ['betta-cyber'], + handler, + radar: [ + { + source: ['psnine.com/dd', 'psnine.com'], + }, + ], +}; diff --git a/lib/routes/psnine/trade.ts b/lib/routes/psnine/trade.ts new file mode 100644 index 0000000000..9a926c8e1a --- /dev/null +++ b/lib/routes/psnine/trade.ts @@ -0,0 +1,58 @@ +import type { Route } from '@/types'; + +import ofetch from '@/utils/ofetch'; +import * as cheerio from 'cheerio'; +import { parseRelativeDate } from '@/utils/parse-date'; + +const handler = async () => { + const url = 'https://www.psnine.com/trade'; + const response = await ofetch(url); + + const $ = cheerio.load(response); + + const out = $('.list li') + .toArray() + .map((item) => { + const $item = $(item); + const touch = $item.find('.touch'); + return { + title: $item.find('.content').text(), + link: touch.attr('href'), + description: $item.find('.r').text() + touch.html(), + pubDate: parseRelativeDate( + $item + .find('div.meta') + .contents() + .filter((_, i) => i.nodeType === 3) + .text() + .trim() + .split(/\s{2,}/)[0] + ), + author: $item.find('.psnnode').text(), + category: $item + .find('.node') + .toArray() + .map((a) => $(a).text()), + }; + }); + + return { + title: $('head title').text(), + link: url, + item: out, + }; +}; + +export const route: Route = { + path: '/trade', + categories: ['game'], + example: '/psnine/trade', + name: '闲游', + maintainers: ['betta-cyber'], + handler, + radar: [ + { + source: ['psnine.com/trade', 'psnine.com'], + }, + ], +};