feat(route): recover psnine (#18760)

* feat: recover psnine

* fix: update path
This commit is contained in:
Tony
2025-04-02 11:41:19 -07:00
committed by GitHub
parent 32b4c1a51d
commit a77c5f43b9
13 changed files with 289 additions and 256 deletions
-12
View File
@@ -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'));
-32
View File
@@ -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,
};
};
-33
View File
@@ -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,
};
};
-53
View File
@@ -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,
};
};
-54
View File
@@ -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,
};
};
-33
View File
@@ -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,
};
};
-39
View File
@@ -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,
};
};
+42
View File
@@ -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'],
},
],
};
+58
View File
@@ -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'],
},
],
};
+8
View File
@@ -0,0 +1,8 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: 'PSN 中文站',
url: 'psnine.com',
lang: 'zh-CN',
categories: ['game'],
};
+80
View File
@@ -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'],
},
],
};
+43
View File
@@ -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'],
},
],
};
+58
View File
@@ -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'],
},
],
};