mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-01 14:57:14 +08:00
feat: rename routes .js to .ts
This commit is contained in:
+12
-16
@@ -14,23 +14,19 @@ type Root = {
|
||||
|
||||
const routes: Record<string, (root: Root) => void> = {};
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
routes.test = (await import('./routes/test/router')).default;
|
||||
} else {
|
||||
const imports = directoryImport({
|
||||
targetDirectoryPath: path.join(__dirname, './routes'),
|
||||
importPattern: /router\.ts$/,
|
||||
});
|
||||
const imports = directoryImport({
|
||||
targetDirectoryPath: path.join(__dirname, './routes'),
|
||||
importPattern: /router\.ts$/,
|
||||
});
|
||||
|
||||
for (const path in imports) {
|
||||
const name = path.split('/').find(Boolean);
|
||||
if (name) {
|
||||
routes[name] = (
|
||||
imports[path] as {
|
||||
default: (root: Root) => void;
|
||||
}
|
||||
).default;
|
||||
}
|
||||
for (const path in imports) {
|
||||
const name = path.split('/').find(Boolean);
|
||||
if (name) {
|
||||
routes[name] = (
|
||||
imports[path] as {
|
||||
default: (root: Root) => void;
|
||||
}
|
||||
).default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
export default async (ctx) => {
|
||||
const baseUrl = 'http://www.0818tuan.com';
|
||||
const listId = ctx.req.param('listId') || '1';
|
||||
const url = `${baseUrl}/list-${listId}-0.html`;
|
||||
|
||||
const { data: response } = await got(url);
|
||||
const $ = load(response);
|
||||
|
||||
const list = $(listId === '3' ? '.col-xs-12 .thumbnail > a' : '.col-md-8 .list-group > a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
title: item.attr('title'),
|
||||
link: `${baseUrl}${item.attr('href')}`,
|
||||
};
|
||||
})
|
||||
.filter((i) => !i.link.includes('m.0818tuan.com/tb1111.php'));
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
|
||||
$('.pageLink, .alert, p[style="margin:15px;"]').remove();
|
||||
|
||||
item.description = $('.post-content').html();
|
||||
item.pubDate = timezone(parseDate($('.panel-body > .text-center').text().replace('时间:', ''), 'YYYY-MM-DD HH:mm:ss'), +8);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('head title').text(),
|
||||
link: url,
|
||||
image: 'http://www.0818tuan.com/favicon.ico',
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
export default async (ctx) => {
|
||||
const baseUrl = 'http://www.0818tuan.com';
|
||||
const listId = ctx.req.param('listId') || '1';
|
||||
const url = `${baseUrl}/list-${listId}-0.html`;
|
||||
|
||||
const { data: response } = await got(url);
|
||||
const $ = load(response);
|
||||
|
||||
const list = $(listId === '3' ? '.col-xs-12 .thumbnail > a' : '.col-md-8 .list-group > a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
title: item.attr('title'),
|
||||
link: `${baseUrl}${item.attr('href')}`,
|
||||
};
|
||||
})
|
||||
.filter((i) => !i.link.includes('m.0818tuan.com/tb1111.php'));
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
|
||||
$('.pageLink, .alert, p[style="margin:15px;"]').remove();
|
||||
|
||||
item.description = $('.post-content').html();
|
||||
item.pubDate = timezone(parseDate($('.panel-body > .text-center').text().replace('时间:', ''), 'YYYY-MM-DD HH:mm:ss'), +8);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('head title').text(),
|
||||
link: url,
|
||||
image: 'http://www.0818tuan.com/favicon.ico',
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,109 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
import { config } from '@/config';
|
||||
|
||||
const rootUrl = 'https://kyfw.12306.cn';
|
||||
|
||||
async function getJSESSIONID(linkUrl) {
|
||||
const res = await got({
|
||||
method: 'get',
|
||||
url: linkUrl,
|
||||
headers: {
|
||||
UserAgent: config.ua,
|
||||
Referer: 'https://www.12306.cn/index/index.html',
|
||||
},
|
||||
});
|
||||
|
||||
return res.headers['set-cookie'].join(',').match(/JSESSIONID=([^;]+);/)[0];
|
||||
}
|
||||
|
||||
function getStationInfo(stationName) {
|
||||
return cache.tryGet(stationName, async () => {
|
||||
const res = await got({
|
||||
method: 'get',
|
||||
url: `${rootUrl}/otn/resources/js/framework/station_name.js`,
|
||||
headers: {
|
||||
UserAgent: config.ua,
|
||||
Referer: 'https://kyfw.12306.cn/otn/leftTicket/init',
|
||||
},
|
||||
});
|
||||
|
||||
return res.data
|
||||
.split('@')
|
||||
.map((item) => {
|
||||
const itemData = item.split('|');
|
||||
|
||||
return itemData.includes(stationName)
|
||||
? {
|
||||
code: itemData[2],
|
||||
name: itemData[1],
|
||||
}
|
||||
: null;
|
||||
})
|
||||
.find(Boolean);
|
||||
});
|
||||
}
|
||||
|
||||
export default async (ctx) => {
|
||||
const date = ctx.req.param('date');
|
||||
const fromStationInfo = await getStationInfo(ctx.req.param('from'));
|
||||
const toStationInfo = await getStationInfo(ctx.req.param('to'));
|
||||
const type = ctx.req.param('type') ?? 'ADULT';
|
||||
|
||||
const apiUrl = `${rootUrl}/otn/leftTicket/queryA?leftTicketDTO.train_date=${date}&leftTicketDTO.from_station=${fromStationInfo.code}&leftTicketDTO.to_station=${toStationInfo.code}&purpose_codes=${type}`;
|
||||
const linkUrl = `${rootUrl}/otn/leftTicket/init?linktypeid=dc&fs=${fromStationInfo.code}&ts=${toStationInfo.code}&date=${date}&flag=N,N,Y`;
|
||||
|
||||
const response = await got.get(apiUrl, {
|
||||
headers: {
|
||||
UserAgent: config.ua,
|
||||
Referer: 'https://kyfw.12306.cn/otn/leftTicket/init',
|
||||
Cookie: await getJSESSIONID(linkUrl),
|
||||
},
|
||||
});
|
||||
if (response.data.data === undefined || response.data.data.length === 0) {
|
||||
throw new Error('没有找到相关车次,请检查参数是否正确');
|
||||
}
|
||||
const data = response.data.data.result;
|
||||
const map = response.data.data.map;
|
||||
|
||||
const items = data.map((item) => {
|
||||
const itemData = item.split('|');
|
||||
const trainInfo = {
|
||||
trainNo: itemData[3],
|
||||
fromStation: map[itemData[6]],
|
||||
toStation: map[itemData[7]],
|
||||
startTime: itemData[8],
|
||||
arriveTime: itemData[9],
|
||||
duration: itemData[10],
|
||||
today: itemData[11],
|
||||
A9: itemData[32],
|
||||
M: itemData[31],
|
||||
O: itemData[30],
|
||||
A6: itemData[29],
|
||||
A4: itemData[28],
|
||||
F: itemData[27],
|
||||
A3: itemData[26],
|
||||
A2: itemData[25],
|
||||
A1: itemData[24],
|
||||
WZ: itemData[23],
|
||||
QT: itemData[22],
|
||||
};
|
||||
|
||||
return {
|
||||
title: `${trainInfo.fromStation} → ${trainInfo.toStation} ${trainInfo.startTime} ${trainInfo.arriveTime}`,
|
||||
description: art(path.join(__dirname, 'templates/train.art'), {
|
||||
trainInfo,
|
||||
}),
|
||||
link: linkUrl,
|
||||
guid: Object.values(trainInfo).join('|'),
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${fromStationInfo.name} → ${toStationInfo.name} ${date}`,
|
||||
link: linkUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
import { config } from '@/config';
|
||||
|
||||
const rootUrl = 'https://kyfw.12306.cn';
|
||||
|
||||
async function getJSESSIONID(linkUrl) {
|
||||
const res = await got({
|
||||
method: 'get',
|
||||
url: linkUrl,
|
||||
headers: {
|
||||
UserAgent: config.ua,
|
||||
Referer: 'https://www.12306.cn/index/index.html',
|
||||
},
|
||||
});
|
||||
|
||||
return res.headers['set-cookie'].join(',').match(/JSESSIONID=([^;]+);/)[0];
|
||||
}
|
||||
|
||||
function getStationInfo(stationName) {
|
||||
return cache.tryGet(stationName, async () => {
|
||||
const res = await got({
|
||||
method: 'get',
|
||||
url: `${rootUrl}/otn/resources/js/framework/station_name.js`,
|
||||
headers: {
|
||||
UserAgent: config.ua,
|
||||
Referer: 'https://kyfw.12306.cn/otn/leftTicket/init',
|
||||
},
|
||||
});
|
||||
|
||||
return res.data
|
||||
.split('@')
|
||||
.map((item) => {
|
||||
const itemData = item.split('|');
|
||||
|
||||
return itemData.includes(stationName)
|
||||
? {
|
||||
code: itemData[2],
|
||||
name: itemData[1],
|
||||
}
|
||||
: null;
|
||||
})
|
||||
.find(Boolean);
|
||||
});
|
||||
}
|
||||
|
||||
export default async (ctx) => {
|
||||
const date = ctx.req.param('date');
|
||||
const fromStationInfo = await getStationInfo(ctx.req.param('from'));
|
||||
const toStationInfo = await getStationInfo(ctx.req.param('to'));
|
||||
const type = ctx.req.param('type') ?? 'ADULT';
|
||||
|
||||
const apiUrl = `${rootUrl}/otn/leftTicket/queryA?leftTicketDTO.train_date=${date}&leftTicketDTO.from_station=${fromStationInfo.code}&leftTicketDTO.to_station=${toStationInfo.code}&purpose_codes=${type}`;
|
||||
const linkUrl = `${rootUrl}/otn/leftTicket/init?linktypeid=dc&fs=${fromStationInfo.code}&ts=${toStationInfo.code}&date=${date}&flag=N,N,Y`;
|
||||
|
||||
const response = await got.get(apiUrl, {
|
||||
headers: {
|
||||
UserAgent: config.ua,
|
||||
Referer: 'https://kyfw.12306.cn/otn/leftTicket/init',
|
||||
Cookie: await getJSESSIONID(linkUrl),
|
||||
},
|
||||
});
|
||||
if (response.data.data === undefined || response.data.data.length === 0) {
|
||||
throw new Error('没有找到相关车次,请检查参数是否正确');
|
||||
}
|
||||
const data = response.data.data.result;
|
||||
const map = response.data.data.map;
|
||||
|
||||
const items = data.map((item) => {
|
||||
const itemData = item.split('|');
|
||||
const trainInfo = {
|
||||
trainNo: itemData[3],
|
||||
fromStation: map[itemData[6]],
|
||||
toStation: map[itemData[7]],
|
||||
startTime: itemData[8],
|
||||
arriveTime: itemData[9],
|
||||
duration: itemData[10],
|
||||
today: itemData[11],
|
||||
A9: itemData[32],
|
||||
M: itemData[31],
|
||||
O: itemData[30],
|
||||
A6: itemData[29],
|
||||
A4: itemData[28],
|
||||
F: itemData[27],
|
||||
A3: itemData[26],
|
||||
A2: itemData[25],
|
||||
A1: itemData[24],
|
||||
WZ: itemData[23],
|
||||
QT: itemData[22],
|
||||
};
|
||||
|
||||
return {
|
||||
title: `${trainInfo.fromStation} → ${trainInfo.toStation} ${trainInfo.startTime} ${trainInfo.arriveTime}`,
|
||||
description: art(path.join(__dirname, 'templates/train.art'), {
|
||||
trainInfo,
|
||||
}),
|
||||
link: linkUrl,
|
||||
guid: Object.values(trainInfo).join('|'),
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${fromStationInfo.name} → ${toStationInfo.name} ${date}`,
|
||||
link: linkUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const url = require('url');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') || -1;
|
||||
|
||||
const link = id === -1 ? 'https://www.12306.cn/mormhweb/zxdt/index_zxdt.html' : `https://www.12306.cn/mormhweb/1/${id}/index_fl.html`;
|
||||
|
||||
const response = await got.get(link);
|
||||
const data = response.data;
|
||||
const $ = load(data);
|
||||
const name = $('div.nav_center > a:nth-child(4)').text();
|
||||
|
||||
const list = $('#newList > ul > li')
|
||||
.map(function () {
|
||||
const info = {
|
||||
title: $(this).find('a').text(),
|
||||
link: $(this).find('a').attr('href'),
|
||||
date: $(this).find('span').text().slice(1, -1),
|
||||
};
|
||||
return info;
|
||||
})
|
||||
.get();
|
||||
|
||||
const out = await Promise.all(
|
||||
list.map(async (info) => {
|
||||
const title = info.title;
|
||||
const date = info.date;
|
||||
const itemUrl = url.resolve(link, info.link);
|
||||
|
||||
const cacheIn = await cache.get(itemUrl);
|
||||
if (cacheIn) {
|
||||
return JSON.parse(cacheIn);
|
||||
}
|
||||
|
||||
const response = await got.get(itemUrl);
|
||||
const $ = load(response.data);
|
||||
let description = $('.article-box').html();
|
||||
description = description ? description.replaceAll('src="', `src="${url.resolve(itemUrl, '.')}`).trim() : $('.content_text').html() || '文章已被删除';
|
||||
|
||||
const single = {
|
||||
title,
|
||||
link: itemUrl,
|
||||
description,
|
||||
pubDate: new Date(date).toUTCString(),
|
||||
};
|
||||
cache.set(itemUrl, JSON.stringify(single));
|
||||
return single;
|
||||
})
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${name}最新动态`,
|
||||
link,
|
||||
item: out,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const url = require('url');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') || -1;
|
||||
|
||||
const link = id === -1 ? 'https://www.12306.cn/mormhweb/zxdt/index_zxdt.html' : `https://www.12306.cn/mormhweb/1/${id}/index_fl.html`;
|
||||
|
||||
const response = await got.get(link);
|
||||
const data = response.data;
|
||||
const $ = load(data);
|
||||
const name = $('div.nav_center > a:nth-child(4)').text();
|
||||
|
||||
const list = $('#newList > ul > li')
|
||||
.map(function () {
|
||||
const info = {
|
||||
title: $(this).find('a').text(),
|
||||
link: $(this).find('a').attr('href'),
|
||||
date: $(this).find('span').text().slice(1, -1),
|
||||
};
|
||||
return info;
|
||||
})
|
||||
.get();
|
||||
|
||||
const out = await Promise.all(
|
||||
list.map(async (info) => {
|
||||
const title = info.title;
|
||||
const date = info.date;
|
||||
const itemUrl = url.resolve(link, info.link);
|
||||
|
||||
const cacheIn = await cache.get(itemUrl);
|
||||
if (cacheIn) {
|
||||
return JSON.parse(cacheIn);
|
||||
}
|
||||
|
||||
const response = await got.get(itemUrl);
|
||||
const $ = load(response.data);
|
||||
let description = $('.article-box').html();
|
||||
description = description ? description.replaceAll('src="', `src="${url.resolve(itemUrl, '.')}`).trim() : $('.content_text').html() || '文章已被删除';
|
||||
|
||||
const single = {
|
||||
title,
|
||||
link: itemUrl,
|
||||
description,
|
||||
pubDate: new Date(date).toUTCString(),
|
||||
};
|
||||
cache.set(itemUrl, JSON.stringify(single));
|
||||
return single;
|
||||
})
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${name}最新动态`,
|
||||
link,
|
||||
item: out,
|
||||
});
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const rootUrl = 'https://www.141jav.com';
|
||||
const currentUrl = `${rootUrl}${getSubPath(ctx)}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
if (getSubPath(ctx) === '/') {
|
||||
ctx.redirect(`/141jav${$('.overview').first().attr('href')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const items = $('.columns')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
const id = item.find('.title a').text();
|
||||
const size = item.find('.title span').text();
|
||||
const pubDate = item.find('.subtitle a').attr('href').split('/date/').pop();
|
||||
const description = item.find('.has-text-grey-dark').text();
|
||||
const actresses = item
|
||||
.find('.panel-block')
|
||||
.toArray()
|
||||
.map((a) => $(a).text().trim());
|
||||
const tags = item
|
||||
.find('.tag')
|
||||
.toArray()
|
||||
.map((t) => $(t).text().trim());
|
||||
const magnet = item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = item.find('a[title="Download .torrent"]').attr('href');
|
||||
const image = item.find('.image').attr('src');
|
||||
|
||||
return {
|
||||
title: `${id} ${size}`,
|
||||
pubDate: parseDate(pubDate, 'YYYY/MM/DD'),
|
||||
link: new URL(item.find('a').first().attr('href'), rootUrl).href,
|
||||
description: art(path.join(__dirname, 'templates/description.art'), {
|
||||
image,
|
||||
id,
|
||||
size,
|
||||
pubDate,
|
||||
description,
|
||||
actresses,
|
||||
tags,
|
||||
magnet,
|
||||
link,
|
||||
}),
|
||||
author: actresses.join(', '),
|
||||
category: [...tags, ...actresses],
|
||||
enclosure_type: 'application/x-bittorrent',
|
||||
enclosure_url: magnet,
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `141JAV - ${$('title').text().split('-')[0].trim()}`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const rootUrl = 'https://www.141jav.com';
|
||||
const currentUrl = `${rootUrl}${getSubPath(ctx)}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
if (getSubPath(ctx) === '/') {
|
||||
ctx.redirect(`/141jav${$('.overview').first().attr('href')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const items = $('.columns')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
const id = item.find('.title a').text();
|
||||
const size = item.find('.title span').text();
|
||||
const pubDate = item.find('.subtitle a').attr('href').split('/date/').pop();
|
||||
const description = item.find('.has-text-grey-dark').text();
|
||||
const actresses = item
|
||||
.find('.panel-block')
|
||||
.toArray()
|
||||
.map((a) => $(a).text().trim());
|
||||
const tags = item
|
||||
.find('.tag')
|
||||
.toArray()
|
||||
.map((t) => $(t).text().trim());
|
||||
const magnet = item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = item.find('a[title="Download .torrent"]').attr('href');
|
||||
const image = item.find('.image').attr('src');
|
||||
|
||||
return {
|
||||
title: `${id} ${size}`,
|
||||
pubDate: parseDate(pubDate, 'YYYY/MM/DD'),
|
||||
link: new URL(item.find('a').first().attr('href'), rootUrl).href,
|
||||
description: art(path.join(__dirname, 'templates/description.art'), {
|
||||
image,
|
||||
id,
|
||||
size,
|
||||
pubDate,
|
||||
description,
|
||||
actresses,
|
||||
tags,
|
||||
magnet,
|
||||
link,
|
||||
}),
|
||||
author: actresses.join(', '),
|
||||
category: [...tags, ...actresses],
|
||||
enclosure_type: 'application/x-bittorrent',
|
||||
enclosure_url: magnet,
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `141JAV - ${$('title').text().split('-')[0].trim()}`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const rootUrl = 'https://www.141ppv.com';
|
||||
const currentUrl = `${rootUrl}${getSubPath(ctx)}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
if (getSubPath(ctx) === '/') {
|
||||
ctx.redirect(`/141ppv${$('.overview').first().attr('href')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const items = $('.columns')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
const id = item.find('.title a').text();
|
||||
const size = item.find('.title span').text();
|
||||
const pubDate = item.find('.subtitle a').attr('href').split('/date/').pop();
|
||||
const description = item.find('.has-text-grey-dark').text();
|
||||
const actresses = item
|
||||
.find('.panel-block')
|
||||
.toArray()
|
||||
.map((a) => $(a).text().trim());
|
||||
const tags = item
|
||||
.find('.tag')
|
||||
.toArray()
|
||||
.map((t) => $(t).text().trim());
|
||||
const magnet = item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = item.find('a[title="Download .torrent"]').attr('href');
|
||||
const onErrorAttr = item.find('.image').attr('onerror');
|
||||
const backupImageRegex = /this\.src='(.*?)'/;
|
||||
const match = backupImageRegex.exec(onErrorAttr);
|
||||
const image = match ? match[1] : item.find('.image').attr('src');
|
||||
|
||||
return {
|
||||
title: `${id} ${size}`,
|
||||
pubDate: parseDate(pubDate, 'YYYY/MM/DD'),
|
||||
link: new URL(item.find('a').first().attr('href'), rootUrl).href,
|
||||
description: art(path.join(__dirname, 'templates/description.art'), {
|
||||
image,
|
||||
id,
|
||||
size,
|
||||
pubDate,
|
||||
description,
|
||||
actresses,
|
||||
tags,
|
||||
magnet,
|
||||
link,
|
||||
}),
|
||||
author: actresses.join(', '),
|
||||
category: [...tags, ...actresses],
|
||||
enclosure_type: 'application/x-bittorrent',
|
||||
enclosure_url: magnet,
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `141PPV - ${$('title').text().split('-')[0].trim()}`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
// @ts-nocheck
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const rootUrl = 'https://www.141ppv.com';
|
||||
const currentUrl = `${rootUrl}${getSubPath(ctx)}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
if (getSubPath(ctx) === '/') {
|
||||
ctx.redirect(`/141ppv${$('.overview').first().attr('href')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const items = $('.columns')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
const id = item.find('.title a').text();
|
||||
const size = item.find('.title span').text();
|
||||
const pubDate = item.find('.subtitle a').attr('href').split('/date/').pop();
|
||||
const description = item.find('.has-text-grey-dark').text();
|
||||
const actresses = item
|
||||
.find('.panel-block')
|
||||
.toArray()
|
||||
.map((a) => $(a).text().trim());
|
||||
const tags = item
|
||||
.find('.tag')
|
||||
.toArray()
|
||||
.map((t) => $(t).text().trim());
|
||||
const magnet = item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = item.find('a[title="Download .torrent"]').attr('href');
|
||||
const onErrorAttr = item.find('.image').attr('onerror');
|
||||
const backupImageRegex = /this\.src='(.*?)'/;
|
||||
const match = backupImageRegex.exec(onErrorAttr);
|
||||
const image = match ? match[1] : item.find('.image').attr('src');
|
||||
|
||||
return {
|
||||
title: `${id} ${size}`,
|
||||
pubDate: parseDate(pubDate, 'YYYY/MM/DD'),
|
||||
link: new URL(item.find('a').first().attr('href'), rootUrl).href,
|
||||
description: art(path.join(__dirname, 'templates/description.art'), {
|
||||
image,
|
||||
id,
|
||||
size,
|
||||
pubDate,
|
||||
description,
|
||||
actresses,
|
||||
tags,
|
||||
magnet,
|
||||
link,
|
||||
}),
|
||||
author: actresses.join(', '),
|
||||
category: [...tags, ...actresses],
|
||||
enclosure_type: 'application/x-bittorrent',
|
||||
enclosure_url: magnet,
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `141PPV - ${$('title').text().split('-')[0].trim()}`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const root_url = 'https://inf.ds.163.com';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const current_url = `${root_url}/v1/web/feed/basic/getSomeOneFeeds?feedTypes=1,2,3,4,6,7,10,11&someOneUid=${id}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: current_url,
|
||||
});
|
||||
const data = response.data.result.feeds;
|
||||
|
||||
const list = data.map((feed) => ({
|
||||
title: JSON.parse(feed.content).body.text,
|
||||
link: `https://ds.163.com/feed/${feed.id}`,
|
||||
description: art(path.resolve(__dirname, 'templates/ds.art'), {
|
||||
text: JSON.parse(feed.content).body.text,
|
||||
medias: JSON.parse(feed.content).body.media,
|
||||
}),
|
||||
pubDate: parseDate(feed.updateTime),
|
||||
}));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${response.data.result.userInfos[0].user.nick} 的动态`,
|
||||
link: `https://ds.163.com/user/${id}`,
|
||||
item: list,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const root_url = 'https://inf.ds.163.com';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const current_url = `${root_url}/v1/web/feed/basic/getSomeOneFeeds?feedTypes=1,2,3,4,6,7,10,11&someOneUid=${id}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: current_url,
|
||||
});
|
||||
const data = response.data.result.feeds;
|
||||
|
||||
const list = data.map((feed) => ({
|
||||
title: JSON.parse(feed.content).body.text,
|
||||
link: `https://ds.163.com/feed/${feed.id}`,
|
||||
description: art(path.resolve(__dirname, 'templates/ds.art'), {
|
||||
text: JSON.parse(feed.content).body.text,
|
||||
medias: JSON.parse(feed.content).body.media,
|
||||
}),
|
||||
pubDate: parseDate(feed.updateTime),
|
||||
}));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${response.data.result.userInfos[0].user.nick} 的动态`,
|
||||
link: `https://ds.163.com/user/${id}`,
|
||||
item: list,
|
||||
});
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
const { parseDyArticle } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got(`https://dy.163.com/v2/article/list.do?pageNo=1&wemediaId=${id}&size=10`);
|
||||
const charset = response.headers['content-type'].split('=')[1];
|
||||
|
||||
const list = response.data.data.list.map((e) => ({
|
||||
title: e.title,
|
||||
link: 'https://www.163.com/dy/article/' + e.docid + '.html',
|
||||
pubDate: timezone(parseDate(e.ptime), 8),
|
||||
author: e.source,
|
||||
imgsrc: e.imgsrc,
|
||||
}));
|
||||
|
||||
const items = await Promise.all(list.map((e) => parseDyArticle(charset, e, cache.tryGet)));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `网易号 - ${list[0].author}`,
|
||||
link: items[0].feedLink,
|
||||
description: items[0].feedDescription,
|
||||
image: items[0].feedImage,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
const { parseDyArticle } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got(`https://dy.163.com/v2/article/list.do?pageNo=1&wemediaId=${id}&size=10`);
|
||||
const charset = response.headers['content-type'].split('=')[1];
|
||||
|
||||
const list = response.data.data.list.map((e) => ({
|
||||
title: e.title,
|
||||
link: 'https://www.163.com/dy/article/' + e.docid + '.html',
|
||||
pubDate: timezone(parseDate(e.ptime), 8),
|
||||
author: e.source,
|
||||
imgsrc: e.imgsrc,
|
||||
}));
|
||||
|
||||
const items = await Promise.all(list.map((e) => parseDyArticle(charset, e, cache.tryGet)));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `网易号 - ${list[0].author}`,
|
||||
link: items[0].feedLink,
|
||||
description: items[0].feedDescription,
|
||||
image: items[0].feedImage,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
const { parseDyArticle } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
const limit = ctx.req.query('limit') ?? 30;
|
||||
const url = `https://www.163.com/dy/media/${id}.html`;
|
||||
|
||||
const response = await got(url, { responseType: 'buffer' });
|
||||
|
||||
const charset = response.headers['content-type'].split('=')[1];
|
||||
const data = iconv.decode(response.data, charset);
|
||||
const $ = load(data);
|
||||
|
||||
const list = $('.tab_content ul li')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
title: item.find('h4 a').text(),
|
||||
link: item.find('a').first().attr('href'),
|
||||
pubDate: timezone(parseDate(item.find('.time').text()), 8),
|
||||
imgsrc: item.find('a img').attr('src'),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(list.map((item) => parseDyArticle(charset, item, cache.tryGet)));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${$('head title').text()} - 网易号`,
|
||||
link: url,
|
||||
description: $('.icon_line.desc').text(),
|
||||
image: $('.head_img').attr('src'),
|
||||
item: items,
|
||||
author: $('h2').text(),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
const { parseDyArticle } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
const limit = ctx.req.query('limit') ?? 30;
|
||||
const url = `https://www.163.com/dy/media/${id}.html`;
|
||||
|
||||
const response = await got(url, { responseType: 'buffer' });
|
||||
|
||||
const charset = response.headers['content-type'].split('=')[1];
|
||||
const data = iconv.decode(response.data, charset);
|
||||
const $ = load(data);
|
||||
|
||||
const list = $('.tab_content ul li')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
title: item.find('h4 a').text(),
|
||||
link: item.find('a').first().attr('href'),
|
||||
pubDate: timezone(parseDate(item.find('.time').text()), 8),
|
||||
imgsrc: item.find('a img').attr('src'),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(list.map((item) => parseDyArticle(charset, item, cache.tryGet)));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${$('head title').text()} - 网易号`,
|
||||
link: url,
|
||||
description: $('.icon_line.desc').text(),
|
||||
image: $('.head_img').attr('src'),
|
||||
item: items,
|
||||
author: $('h2').text(),
|
||||
});
|
||||
};
|
||||
@@ -1,149 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const ids = {
|
||||
'': {
|
||||
id: 'BAI5E21O',
|
||||
title: '首页',
|
||||
},
|
||||
qsyk: {
|
||||
id: 'BD21K0DL',
|
||||
title: '轻松一刻',
|
||||
},
|
||||
cz: {
|
||||
id: 'CICMICLU',
|
||||
title: '槽值',
|
||||
},
|
||||
rj: {
|
||||
id: 'CICMOMBL',
|
||||
title: '人间',
|
||||
},
|
||||
dgxm: {
|
||||
id: 'CICMPVC5',
|
||||
title: '大国小民',
|
||||
},
|
||||
ssyg: {
|
||||
id: 'CICMLCOU',
|
||||
title: '三三有梗',
|
||||
},
|
||||
sd: {
|
||||
id: 'D551V75C',
|
||||
title: '数读',
|
||||
},
|
||||
kk: {
|
||||
id: 'D55253RH',
|
||||
title: '看客',
|
||||
},
|
||||
xhx: {
|
||||
id: 'D553A53L',
|
||||
title: '下划线',
|
||||
},
|
||||
txs: {
|
||||
id: 'D553PGHQ',
|
||||
title: '谈心社',
|
||||
},
|
||||
dd: {
|
||||
id: 'CICMS5BI',
|
||||
title: '哒哒',
|
||||
},
|
||||
pbgl: {
|
||||
id: 'CQ9UDVKO',
|
||||
title: '胖编怪聊',
|
||||
},
|
||||
qyd: {
|
||||
id: 'CQ9UJIJN',
|
||||
title: '曲一刀',
|
||||
},
|
||||
jrzs: {
|
||||
id: 'BD284UM8',
|
||||
title: '今日之声',
|
||||
},
|
||||
lc: {
|
||||
id: 'CICMMGBH',
|
||||
title: '浪潮',
|
||||
},
|
||||
fd: {
|
||||
id: 'D5543R68',
|
||||
title: '沸点',
|
||||
},
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') ?? '';
|
||||
|
||||
const rootUrl = 'https://3g.163.com';
|
||||
const currentUrl = `${rootUrl}/touch/exclusive${id ? `/sub/${id}` : ''}`;
|
||||
const apiUrl = `${rootUrl}/touch/reconstruct/article/list/${ids[id].id}wangning/0-20.html`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: apiUrl,
|
||||
});
|
||||
|
||||
const data = JSON.parse(response.data.match(/^artiList\((.*)\)$/)[1])[`${ids[id].id}wangning`];
|
||||
|
||||
let items = data.map((item) => ({
|
||||
title: item.title,
|
||||
author: item.source,
|
||||
link: item.skipURL || item.url || `${rootUrl}/dy/article/${item.docid}.html`,
|
||||
pubDate: timezone(parseDate(item.ptime), +8),
|
||||
videoId: item.skipType === 'video' ? item.stitle : '',
|
||||
}));
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
try {
|
||||
if (item.videoId) {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: `${rootUrl}/touch/video/detail/jsonp/VIA8K0PTB.html?callback=videoList`,
|
||||
});
|
||||
|
||||
const video = JSON.parse(detailResponse.data.match(/^videoList\((.*)\)$/)[1])?.mp4_url;
|
||||
|
||||
item.description = art(path.join(__dirname, 'templates/exclusive.art'), {
|
||||
video,
|
||||
});
|
||||
} else {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.m-linkCard').remove();
|
||||
|
||||
content('.m-photo').each(function () {
|
||||
content(this).html(
|
||||
art(path.join(__dirname, 'templates/exclusive.art'), {
|
||||
image: content(this).find('img').attr('data-src'),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
item.description = content('.article-body').html();
|
||||
}
|
||||
} catch {
|
||||
// no-empty
|
||||
}
|
||||
|
||||
delete item.videoId;
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `网易独家 - ${ids[id].title}`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,150 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const ids = {
|
||||
'': {
|
||||
id: 'BAI5E21O',
|
||||
title: '首页',
|
||||
},
|
||||
qsyk: {
|
||||
id: 'BD21K0DL',
|
||||
title: '轻松一刻',
|
||||
},
|
||||
cz: {
|
||||
id: 'CICMICLU',
|
||||
title: '槽值',
|
||||
},
|
||||
rj: {
|
||||
id: 'CICMOMBL',
|
||||
title: '人间',
|
||||
},
|
||||
dgxm: {
|
||||
id: 'CICMPVC5',
|
||||
title: '大国小民',
|
||||
},
|
||||
ssyg: {
|
||||
id: 'CICMLCOU',
|
||||
title: '三三有梗',
|
||||
},
|
||||
sd: {
|
||||
id: 'D551V75C',
|
||||
title: '数读',
|
||||
},
|
||||
kk: {
|
||||
id: 'D55253RH',
|
||||
title: '看客',
|
||||
},
|
||||
xhx: {
|
||||
id: 'D553A53L',
|
||||
title: '下划线',
|
||||
},
|
||||
txs: {
|
||||
id: 'D553PGHQ',
|
||||
title: '谈心社',
|
||||
},
|
||||
dd: {
|
||||
id: 'CICMS5BI',
|
||||
title: '哒哒',
|
||||
},
|
||||
pbgl: {
|
||||
id: 'CQ9UDVKO',
|
||||
title: '胖编怪聊',
|
||||
},
|
||||
qyd: {
|
||||
id: 'CQ9UJIJN',
|
||||
title: '曲一刀',
|
||||
},
|
||||
jrzs: {
|
||||
id: 'BD284UM8',
|
||||
title: '今日之声',
|
||||
},
|
||||
lc: {
|
||||
id: 'CICMMGBH',
|
||||
title: '浪潮',
|
||||
},
|
||||
fd: {
|
||||
id: 'D5543R68',
|
||||
title: '沸点',
|
||||
},
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') ?? '';
|
||||
|
||||
const rootUrl = 'https://3g.163.com';
|
||||
const currentUrl = `${rootUrl}/touch/exclusive${id ? `/sub/${id}` : ''}`;
|
||||
const apiUrl = `${rootUrl}/touch/reconstruct/article/list/${ids[id].id}wangning/0-20.html`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: apiUrl,
|
||||
});
|
||||
|
||||
const data = JSON.parse(response.data.match(/^artiList\((.*)\)$/)[1])[`${ids[id].id}wangning`];
|
||||
|
||||
let items = data.map((item) => ({
|
||||
title: item.title,
|
||||
author: item.source,
|
||||
link: item.skipURL || item.url || `${rootUrl}/dy/article/${item.docid}.html`,
|
||||
pubDate: timezone(parseDate(item.ptime), +8),
|
||||
videoId: item.skipType === 'video' ? item.stitle : '',
|
||||
}));
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
try {
|
||||
if (item.videoId) {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: `${rootUrl}/touch/video/detail/jsonp/VIA8K0PTB.html?callback=videoList`,
|
||||
});
|
||||
|
||||
const video = JSON.parse(detailResponse.data.match(/^videoList\((.*)\)$/)[1])?.mp4_url;
|
||||
|
||||
item.description = art(path.join(__dirname, 'templates/exclusive.art'), {
|
||||
video,
|
||||
});
|
||||
} else {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.m-linkCard').remove();
|
||||
|
||||
content('.m-photo').each(function () {
|
||||
content(this).html(
|
||||
art(path.join(__dirname, 'templates/exclusive.art'), {
|
||||
image: content(this).find('img').attr('data-src'),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
item.description = content('.article-body').html();
|
||||
}
|
||||
} catch {
|
||||
// no-empty
|
||||
}
|
||||
|
||||
delete item.videoId;
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `网易独家 - ${ids[id].title}`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const { data } = await got(`https://music.163.com/api/v1/artist/songs`, {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
searchParams: {
|
||||
id,
|
||||
private_cloud: 'true',
|
||||
work_type: 1,
|
||||
order: 'time',
|
||||
offset: 0,
|
||||
limit: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const artist = data.songs.find(({ ar }) => ar[0].id === Number.parseInt(id)).ar[0];
|
||||
const items = data.songs.map((song) => ({
|
||||
title: `${song.name} - ${song.ar.map(({ name }) => name).join(' / ')}`,
|
||||
description: art(path.join(__dirname, '../templates/music/playlist.art'), {
|
||||
singer: song.ar.map(({ name }) => name).join(' / '),
|
||||
album: song.al.name,
|
||||
picUrl: song.al.picUrl,
|
||||
}),
|
||||
link: `https://music.163.com/#/song?id=${song.id}`,
|
||||
}));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${artist.name} - 歌手歌曲`,
|
||||
link: `https://music.163.com/#/artist?id=${id}`,
|
||||
description: `网易云音乐 - 歌手歌曲 - ${artist.name}`,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const { data } = await got(`https://music.163.com/api/v1/artist/songs`, {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
searchParams: {
|
||||
id,
|
||||
private_cloud: 'true',
|
||||
work_type: 1,
|
||||
order: 'time',
|
||||
offset: 0,
|
||||
limit: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const artist = data.songs.find(({ ar }) => ar[0].id === Number.parseInt(id)).ar[0];
|
||||
const items = data.songs.map((song) => ({
|
||||
title: `${song.name} - ${song.ar.map(({ name }) => name).join(' / ')}`,
|
||||
description: art(path.join(__dirname, '../templates/music/playlist.art'), {
|
||||
singer: song.ar.map(({ name }) => name).join(' / '),
|
||||
album: song.al.name,
|
||||
picUrl: song.al.picUrl,
|
||||
}),
|
||||
link: `https://music.163.com/#/song?id=${song.id}`,
|
||||
}));
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${artist.name} - 歌手歌曲`,
|
||||
link: `https://music.163.com/#/artist?id=${id}`,
|
||||
description: `网易云音乐 - 歌手歌曲 - ${artist.name}`,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got(`https://music.163.com/api/artist/albums/${id}`, {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data;
|
||||
|
||||
ctx.set('data', {
|
||||
title: data.artist.name,
|
||||
link: `https://music.163.com/#/artist/album?id=${id}`,
|
||||
description: `网易云音乐歌手专辑 - ${data.artist.name}`,
|
||||
image: data.artist.img1v1Url || data.artist.picUrl,
|
||||
item: data.hotAlbums.map((item) => {
|
||||
const singer = item.artists.length === 1 ? item.artists[0].name : item.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
|
||||
return {
|
||||
title: `${item.name} - ${singer}`,
|
||||
description: art(path.join(__dirname, '../templates/music/playlist.art'), {
|
||||
singer,
|
||||
album: item.name,
|
||||
date: new Date(item.publishTime).toLocaleDateString(),
|
||||
picUrl: item.picUrl,
|
||||
}),
|
||||
link: `https://music.163.com/#/album?id=${item.id}`,
|
||||
pubDate: new Date(item.publishTime),
|
||||
published: new Date(item.publishTime),
|
||||
category: item.subType,
|
||||
author: singer,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got(`https://music.163.com/api/artist/albums/${id}`, {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data;
|
||||
|
||||
ctx.set('data', {
|
||||
title: data.artist.name,
|
||||
link: `https://music.163.com/#/artist/album?id=${id}`,
|
||||
description: `网易云音乐歌手专辑 - ${data.artist.name}`,
|
||||
image: data.artist.img1v1Url || data.artist.picUrl,
|
||||
item: data.hotAlbums.map((item) => {
|
||||
const singer = item.artists.length === 1 ? item.artists[0].name : item.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
|
||||
return {
|
||||
title: `${item.name} - ${singer}`,
|
||||
description: art(path.join(__dirname, '../templates/music/playlist.art'), {
|
||||
singer,
|
||||
album: item.name,
|
||||
date: new Date(item.publishTime).toLocaleDateString(),
|
||||
picUrl: item.picUrl,
|
||||
}),
|
||||
link: `https://music.163.com/#/album?id=${item.id}`,
|
||||
pubDate: new Date(item.publishTime),
|
||||
published: new Date(item.publishTime),
|
||||
category: item.subType,
|
||||
author: singer,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const ProcessFeed = (limit, offset) =>
|
||||
got.post('https://music.163.com/api/dj/program/byradio', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
form: {
|
||||
radioId: id,
|
||||
limit,
|
||||
offset,
|
||||
},
|
||||
});
|
||||
|
||||
const response = await ProcessFeed(1, 0);
|
||||
|
||||
const programs = response.data.programs || [];
|
||||
const { radio, dj } = programs[0] || { radio: {}, dj: {} };
|
||||
const count = response.data.count || 0;
|
||||
|
||||
const countPage = [];
|
||||
for (let i = 0; i < Math.ceil(count / 500); i++) {
|
||||
countPage.push(i);
|
||||
}
|
||||
|
||||
const items = await Promise.all(
|
||||
countPage.map(async (item) => {
|
||||
const response = await ProcessFeed(500, item * 500);
|
||||
const programs = response.data.programs || [];
|
||||
const list = programs.map((pg) => {
|
||||
const description = (pg.description || '').split('\n').map((p) => p);
|
||||
const duration = Math.trunc(pg.duration / 1000);
|
||||
const mm_ss_duration = `${(duration / 60).toFixed(0).padStart(2, '0')}:${(duration % 60).toFixed(0).padStart(2, '0')}`;
|
||||
|
||||
const html = art(path.join(__dirname, '../templates/music/djradio-content.art'), {
|
||||
pg,
|
||||
description,
|
||||
itunes_duration: mm_ss_duration,
|
||||
});
|
||||
|
||||
return {
|
||||
title: pg.name,
|
||||
link: 'https://music.163.com/program/' + pg.id,
|
||||
pubDate: parseDate(pg.createTime),
|
||||
published: parseDate(pg.createTime),
|
||||
author: pg.dj.nickname,
|
||||
description: html,
|
||||
content: { html },
|
||||
itunes_item_image: pg.coverUrl,
|
||||
enclosure_url: `https://music.163.com/song/media/outer/url?id=${pg.mainTrackId}.mp3`,
|
||||
enclosure_type: 'audio/mpeg',
|
||||
itunes_duration: duration,
|
||||
};
|
||||
});
|
||||
return list;
|
||||
})
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: radio.name,
|
||||
link: `https://music.163.com/djradio?id=${id}`,
|
||||
subtitle: radio.desc,
|
||||
description: radio.desc,
|
||||
author: dj.nickname,
|
||||
updated: radio.lastProgramCreateTime,
|
||||
icon: radio.picUrl,
|
||||
image: radio.picUrl,
|
||||
itunes_author: dj.nickname,
|
||||
itunes_category: radio.category,
|
||||
item: items.flat(),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const ProcessFeed = (limit, offset) =>
|
||||
got.post('https://music.163.com/api/dj/program/byradio', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
form: {
|
||||
radioId: id,
|
||||
limit,
|
||||
offset,
|
||||
},
|
||||
});
|
||||
|
||||
const response = await ProcessFeed(1, 0);
|
||||
|
||||
const programs = response.data.programs || [];
|
||||
const { radio, dj } = programs[0] || { radio: {}, dj: {} };
|
||||
const count = response.data.count || 0;
|
||||
|
||||
const countPage = [];
|
||||
for (let i = 0; i < Math.ceil(count / 500); i++) {
|
||||
countPage.push(i);
|
||||
}
|
||||
|
||||
const items = await Promise.all(
|
||||
countPage.map(async (item) => {
|
||||
const response = await ProcessFeed(500, item * 500);
|
||||
const programs = response.data.programs || [];
|
||||
const list = programs.map((pg) => {
|
||||
const description = (pg.description || '').split('\n').map((p) => p);
|
||||
const duration = Math.trunc(pg.duration / 1000);
|
||||
const mm_ss_duration = `${(duration / 60).toFixed(0).padStart(2, '0')}:${(duration % 60).toFixed(0).padStart(2, '0')}`;
|
||||
|
||||
const html = art(path.join(__dirname, '../templates/music/djradio-content.art'), {
|
||||
pg,
|
||||
description,
|
||||
itunes_duration: mm_ss_duration,
|
||||
});
|
||||
|
||||
return {
|
||||
title: pg.name,
|
||||
link: 'https://music.163.com/program/' + pg.id,
|
||||
pubDate: parseDate(pg.createTime),
|
||||
published: parseDate(pg.createTime),
|
||||
author: pg.dj.nickname,
|
||||
description: html,
|
||||
content: { html },
|
||||
itunes_item_image: pg.coverUrl,
|
||||
enclosure_url: `https://music.163.com/song/media/outer/url?id=${pg.mainTrackId}.mp3`,
|
||||
enclosure_type: 'audio/mpeg',
|
||||
itunes_duration: duration,
|
||||
};
|
||||
});
|
||||
return list;
|
||||
})
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: radio.name,
|
||||
link: `https://music.163.com/djradio?id=${id}`,
|
||||
subtitle: radio.desc,
|
||||
description: radio.desc,
|
||||
author: dj.nickname,
|
||||
updated: radio.lastProgramCreateTime,
|
||||
icon: radio.picUrl,
|
||||
image: radio.picUrl,
|
||||
itunes_author: dj.nickname,
|
||||
itunes_category: radio.category,
|
||||
item: items.flat(),
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { config } from '@/config';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
if (!config.ncm || !config.ncm.cookies) {
|
||||
throw new Error('163 Music RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>');
|
||||
}
|
||||
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got.post('https://music.163.com/api/v3/playlist/detail', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
Cookie: config.ncm.cookies,
|
||||
},
|
||||
form: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data.playlist;
|
||||
const songinfo = await got('https://music.163.com/api/song/detail', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com',
|
||||
},
|
||||
searchParams: {
|
||||
ids: `[${data.trackIds.slice(0, 201).map((item) => item.id)}]`,
|
||||
},
|
||||
});
|
||||
const songs = songinfo.data.songs;
|
||||
|
||||
ctx.set('data', {
|
||||
title: data.name,
|
||||
link: `https://music.163.com/#/playlist?id=${id}`,
|
||||
description: `网易云音乐歌单 - ${data.name}`,
|
||||
item: data.trackIds.slice(0, 201).map((item) => {
|
||||
const thisSong = songs.find((element) => element.id === item.id);
|
||||
const singer = thisSong.artists.length === 1 ? thisSong.artists[0].name : thisSong.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
|
||||
return {
|
||||
title: `${thisSong.name} - ${singer}`,
|
||||
description: art(path.join(__dirname, '../templates/music/playlist.art'), {
|
||||
singer,
|
||||
album: thisSong.album.name,
|
||||
date: new Date(thisSong.album.publishTime).toLocaleDateString(),
|
||||
picUrl: thisSong.album.picUrl,
|
||||
}),
|
||||
link: `https://music.163.com/#/song?id=${item.id}`,
|
||||
pubDate: new Date(item.at),
|
||||
author: singer,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { config } from '@/config';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
if (!config.ncm || !config.ncm.cookies) {
|
||||
throw new Error('163 Music RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>');
|
||||
}
|
||||
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got.post('https://music.163.com/api/v3/playlist/detail', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
Cookie: config.ncm.cookies,
|
||||
},
|
||||
form: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data.playlist;
|
||||
const songinfo = await got('https://music.163.com/api/song/detail', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com',
|
||||
},
|
||||
searchParams: {
|
||||
ids: `[${data.trackIds.slice(0, 201).map((item) => item.id)}]`,
|
||||
},
|
||||
});
|
||||
const songs = songinfo.data.songs;
|
||||
|
||||
ctx.set('data', {
|
||||
title: data.name,
|
||||
link: `https://music.163.com/#/playlist?id=${id}`,
|
||||
description: `网易云音乐歌单 - ${data.name}`,
|
||||
item: data.trackIds.slice(0, 201).map((item) => {
|
||||
const thisSong = songs.find((element) => element.id === item.id);
|
||||
const singer = thisSong.artists.length === 1 ? thisSong.artists[0].name : thisSong.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
|
||||
return {
|
||||
title: `${thisSong.name} - ${singer}`,
|
||||
description: art(path.join(__dirname, '../templates/music/playlist.art'), {
|
||||
singer,
|
||||
album: thisSong.album.name,
|
||||
date: new Date(thisSong.album.publishTime).toLocaleDateString(),
|
||||
picUrl: thisSong.album.picUrl,
|
||||
}),
|
||||
link: `https://music.163.com/#/song?id=${item.id}`,
|
||||
pubDate: new Date(item.at),
|
||||
author: singer,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
import * as path from 'node:path';
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
const renderDescription = (info) => art(path.join(__dirname, '../templates/music/userevents.art'), info);
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got(`https://music.163.com/api/event/get/${id}`, {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
});
|
||||
|
||||
const { data } = response;
|
||||
const { nickname, signature, avatarUrl } = data.events[0].user;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${nickname}的云村动态`,
|
||||
link: `https://music.163.com/#/user/event?id=${id}`,
|
||||
description: `网易云音乐用户动态 - ${signature}`,
|
||||
icon: avatarUrl,
|
||||
image: avatarUrl,
|
||||
item: data.events.map((item) => {
|
||||
const title = item.info.commentThread.resourceTitle;
|
||||
const userId = item.user.userId;
|
||||
const description = JSON.parse(item.json).msg;
|
||||
const pics = item.pics.map(({ originUrl }) => originUrl);
|
||||
const eventId = item.id;
|
||||
|
||||
/**
|
||||
* @todo 根据 `item.info.commentThread.resourceInfo.eventType` 生成 Media
|
||||
* 17 分享节目
|
||||
* 18 分享单曲
|
||||
* 19 分享专辑
|
||||
* 35 空
|
||||
* 因为我不需要,我就不写了。
|
||||
* 因为 api 并没有 mp3 URL,生成 `media` 字段会有困难。
|
||||
*/
|
||||
return {
|
||||
title,
|
||||
description: renderDescription({ description, pics }),
|
||||
link: `https://music.163.com/#/event?id=${eventId}&uid=${userId}`,
|
||||
pubDate: new Date(item.eventTime),
|
||||
published: new Date(item.eventTime),
|
||||
author: nickname,
|
||||
upvotes: item.info.likedCount,
|
||||
comments: item.info.commentCount,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
// @ts-nocheck
|
||||
import * as path from 'node:path';
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
const renderDescription = (info) => art(path.join(__dirname, '../templates/music/userevents.art'), info);
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const response = await got(`https://music.163.com/api/event/get/${id}`, {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
});
|
||||
|
||||
const { data } = response;
|
||||
const { nickname, signature, avatarUrl } = data.events[0].user;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${nickname}的云村动态`,
|
||||
link: `https://music.163.com/#/user/event?id=${id}`,
|
||||
description: `网易云音乐用户动态 - ${signature}`,
|
||||
icon: avatarUrl,
|
||||
image: avatarUrl,
|
||||
item: data.events.map((item) => {
|
||||
const title = item.info.commentThread.resourceTitle;
|
||||
const userId = item.user.userId;
|
||||
const description = JSON.parse(item.json).msg;
|
||||
const pics = item.pics.map(({ originUrl }) => originUrl);
|
||||
const eventId = item.id;
|
||||
|
||||
/**
|
||||
* @todo 根据 `item.info.commentThread.resourceInfo.eventType` 生成 Media
|
||||
* 17 分享节目
|
||||
* 18 分享单曲
|
||||
* 19 分享专辑
|
||||
* 35 空
|
||||
* 因为我不需要,我就不写了。
|
||||
* 因为 api 并没有 mp3 URL,生成 `media` 字段会有困难。
|
||||
*/
|
||||
return {
|
||||
title,
|
||||
description: renderDescription({ description, pics }),
|
||||
link: `https://music.163.com/#/event?id=${eventId}&uid=${userId}`,
|
||||
pubDate: new Date(item.eventTime),
|
||||
published: new Date(item.eventTime),
|
||||
author: nickname,
|
||||
upvotes: item.info.likedCount,
|
||||
comments: item.info.commentCount,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const uid = ctx.req.param('uid');
|
||||
|
||||
const response = await got.post('https://music.163.com/api/user/playlist', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
form: {
|
||||
uid,
|
||||
limit: 1000,
|
||||
offset: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const playlist = response.data.playlist || [];
|
||||
|
||||
const creator = (playlist[0] || {}).creator;
|
||||
|
||||
const { nickname, signature, avatarUrl } = creator;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${nickname} 的所有歌单`,
|
||||
link: `https://music.163.com/user/home?id=${uid}`,
|
||||
subtitle: signature,
|
||||
description: signature,
|
||||
author: nickname,
|
||||
updated: response.headers.date,
|
||||
icon: avatarUrl,
|
||||
image: avatarUrl,
|
||||
item: playlist.map((pl) => {
|
||||
const src = `http://music.163.com/playlist/${pl.id}`;
|
||||
|
||||
const html = art(path.join(__dirname, '../templates/music/userplaylist.art'), {
|
||||
image: pl.coverImgUrl,
|
||||
description: (pl.description || '').split('\n'),
|
||||
src,
|
||||
});
|
||||
|
||||
return {
|
||||
title: pl.name,
|
||||
link: src,
|
||||
pubDate: new Date(pl.createTime).toUTCString(),
|
||||
published: new Date(pl.createTime).toISOString(),
|
||||
updated: new Date(pl.updateTime).toISOString(),
|
||||
author: pl.creator.nickname,
|
||||
description: html,
|
||||
content: { html },
|
||||
category: pl.tags,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const uid = ctx.req.param('uid');
|
||||
|
||||
const response = await got.post('https://music.163.com/api/user/playlist', {
|
||||
headers: {
|
||||
Referer: 'https://music.163.com/',
|
||||
},
|
||||
form: {
|
||||
uid,
|
||||
limit: 1000,
|
||||
offset: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const playlist = response.data.playlist || [];
|
||||
|
||||
const creator = (playlist[0] || {}).creator;
|
||||
|
||||
const { nickname, signature, avatarUrl } = creator;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${nickname} 的所有歌单`,
|
||||
link: `https://music.163.com/user/home?id=${uid}`,
|
||||
subtitle: signature,
|
||||
description: signature,
|
||||
author: nickname,
|
||||
updated: response.headers.date,
|
||||
icon: avatarUrl,
|
||||
image: avatarUrl,
|
||||
item: playlist.map((pl) => {
|
||||
const src = `http://music.163.com/playlist/${pl.id}`;
|
||||
|
||||
const html = art(path.join(__dirname, '../templates/music/userplaylist.art'), {
|
||||
image: pl.coverImgUrl,
|
||||
description: (pl.description || '').split('\n'),
|
||||
src,
|
||||
});
|
||||
|
||||
return {
|
||||
title: pl.name,
|
||||
link: src,
|
||||
pubDate: new Date(pl.createTime).toUTCString(),
|
||||
published: new Date(pl.createTime).toISOString(),
|
||||
updated: new Date(pl.updateTime).toISOString(),
|
||||
author: pl.creator.nickname,
|
||||
description: html,
|
||||
content: { html },
|
||||
category: pl.tags,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { config } from '@/config';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const headers = {
|
||||
cookie: config.ncm.cookies,
|
||||
Referer: 'https://music.163.com/',
|
||||
};
|
||||
|
||||
function getItem(records) {
|
||||
if (!records || records.length === 0) {
|
||||
return [
|
||||
{
|
||||
title: '暂无听歌排行',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return records.map((record, index) => {
|
||||
const song = record.song;
|
||||
|
||||
const artists_paintext = song.ar.map((a) => a.name).join('/');
|
||||
|
||||
const html = art(path.join(__dirname, '../templates/music/userplayrecords.art'), {
|
||||
index,
|
||||
record,
|
||||
song,
|
||||
});
|
||||
|
||||
return {
|
||||
title: `[${index + 1}] ${song.name} - ${artists_paintext}`,
|
||||
link: `http://music.163.com/song?id=${song.id}`,
|
||||
author: artists_paintext,
|
||||
description: html,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default async (ctx) => {
|
||||
const uid = ctx.req.param('uid');
|
||||
const type = Number.parseInt(ctx.req.param('type')) || 0;
|
||||
|
||||
const url = `https://music.163.com/api/v1/play/record?uid=${uid}&type=${type}`;
|
||||
const response = await got(url, { headers });
|
||||
|
||||
const records = type === 1 ? response.data.weekData : response.data.allData;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${type === 1 ? '听歌榜单(最近一周)' : '听歌榜单(所有时间}'} - ${uid}}`,
|
||||
link: `https://music.163.com/user/home?id=${uid}`,
|
||||
updated: response.headers.date,
|
||||
item: getItem(records),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { config } from '@/config';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const headers = {
|
||||
cookie: config.ncm.cookies,
|
||||
Referer: 'https://music.163.com/',
|
||||
};
|
||||
|
||||
function getItem(records) {
|
||||
if (!records || records.length === 0) {
|
||||
return [
|
||||
{
|
||||
title: '暂无听歌排行',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return records.map((record, index) => {
|
||||
const song = record.song;
|
||||
|
||||
const artists_paintext = song.ar.map((a) => a.name).join('/');
|
||||
|
||||
const html = art(path.join(__dirname, '../templates/music/userplayrecords.art'), {
|
||||
index,
|
||||
record,
|
||||
song,
|
||||
});
|
||||
|
||||
return {
|
||||
title: `[${index + 1}] ${song.name} - ${artists_paintext}`,
|
||||
link: `http://music.163.com/song?id=${song.id}`,
|
||||
author: artists_paintext,
|
||||
description: html,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default async (ctx) => {
|
||||
const uid = ctx.req.param('uid');
|
||||
const type = Number.parseInt(ctx.req.param('type')) || 0;
|
||||
|
||||
const url = `https://music.163.com/api/v1/play/record?uid=${uid}&type=${type}`;
|
||||
const response = await got(url, { headers });
|
||||
|
||||
const records = type === 1 ? response.data.weekData : response.data.allData;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${type === 1 ? '听歌榜单(最近一周)' : '听歌榜单(所有时间}'} - ${uid}}`,
|
||||
link: `https://music.163.com/user/home?id=${uid}`,
|
||||
updated: response.headers.date,
|
||||
item: getItem(records),
|
||||
});
|
||||
};
|
||||
@@ -1,156 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const rootUrl = 'https://news.163.com';
|
||||
|
||||
const config = {
|
||||
whole: {
|
||||
link: '/special/0001386F/rank_whole.html',
|
||||
title: '全站',
|
||||
},
|
||||
news: {
|
||||
link: '/special/0001386F/rank_news.html',
|
||||
title: '新闻',
|
||||
},
|
||||
entertainment: {
|
||||
link: '/special/0001386F/rank_ent.html',
|
||||
title: '娱乐',
|
||||
},
|
||||
sports: {
|
||||
link: '/special/0001386F/rank_sports.html',
|
||||
title: '体育',
|
||||
},
|
||||
money: {
|
||||
link: 'https://money.163.com/special/002526BH/rank.html',
|
||||
title: '财经',
|
||||
},
|
||||
tech: {
|
||||
link: '/special/0001386F/rank_tech.html',
|
||||
title: '科技',
|
||||
},
|
||||
auto: {
|
||||
link: '/special/0001386F/rank_auto.html',
|
||||
title: '汽车',
|
||||
},
|
||||
lady: {
|
||||
link: '/special/0001386F/rank_lady.html',
|
||||
title: '女人',
|
||||
},
|
||||
house: {
|
||||
link: '/special/0001386F/rank_house.html',
|
||||
title: '房产',
|
||||
},
|
||||
game: {
|
||||
link: '/special/0001386F/game_rank.html',
|
||||
title: '游戏',
|
||||
},
|
||||
travel: {
|
||||
link: '/special/0001386F/rank_travel.html',
|
||||
title: '旅游',
|
||||
},
|
||||
edu: {
|
||||
link: '/special/0001386F/rank_edu.html',
|
||||
title: '教育',
|
||||
},
|
||||
};
|
||||
|
||||
const timeRange = {
|
||||
hour: {
|
||||
index: 0,
|
||||
title: '1小时',
|
||||
},
|
||||
day: {
|
||||
index: 1,
|
||||
title: '24小时',
|
||||
},
|
||||
week: {
|
||||
index: 2,
|
||||
title: '本周',
|
||||
},
|
||||
month: {
|
||||
index: 3,
|
||||
title: '本月',
|
||||
},
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') || 'whole';
|
||||
const type = ctx.req.param('type') || 'click';
|
||||
const time = ctx.req.param('time') || 'day';
|
||||
|
||||
const cfg = config[category];
|
||||
if (!cfg) {
|
||||
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
|
||||
} else if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
|
||||
throw new Error('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
|
||||
}
|
||||
|
||||
const currentUrl = category === 'money' ? cfg.link : `${rootUrl}${cfg.link}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const $ = load(iconv.decode(response.data, 'gbk'));
|
||||
|
||||
const list = $('div.tabContents')
|
||||
.eq(timeRange[time].index + (category === 'whole' ? (type === 'click' ? -1 : 2) : type === 'click' ? 0 : 2))
|
||||
.find('table tbody tr td a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
link: item.attr('href'),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
try {
|
||||
let link;
|
||||
if (category === 'auto' || category === 'house' || category === 'travel') {
|
||||
const category = item.link.split('.163.com')[0].split('//').pop().split('.').pop();
|
||||
link = `https://3g.163.com/${category}/article/${item.link.split('/').pop()}`;
|
||||
} else {
|
||||
const pathname = new URL(item.link).pathname;
|
||||
link = `https://3g.163.com${pathname}`;
|
||||
}
|
||||
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
});
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.bot_word, .js-open-app, .s-img').remove();
|
||||
content('video').each(function () {
|
||||
content(this).attr('src', content(this).attr('data-src'));
|
||||
});
|
||||
content('.article-body .image-lazy').each((_, elem) => {
|
||||
elem.attribs.src = elem.attribs['data-src'] ?? elem.attribs.src;
|
||||
});
|
||||
|
||||
item.title = content('meta[property="og:title"]').attr('content').replace('_手机网易网', '');
|
||||
item.pubDate = parseDate(content('meta[property="og:release_date"]').attr('content'));
|
||||
item.description = content('.article-body').html();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `网易新闻${timeRange[time].title}${type === 'click' ? '点击' : '跟帖'}榜 - ${cfg.title}`,
|
||||
link: currentUrl,
|
||||
item: items.filter(Boolean),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,157 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const rootUrl = 'https://news.163.com';
|
||||
|
||||
const config = {
|
||||
whole: {
|
||||
link: '/special/0001386F/rank_whole.html',
|
||||
title: '全站',
|
||||
},
|
||||
news: {
|
||||
link: '/special/0001386F/rank_news.html',
|
||||
title: '新闻',
|
||||
},
|
||||
entertainment: {
|
||||
link: '/special/0001386F/rank_ent.html',
|
||||
title: '娱乐',
|
||||
},
|
||||
sports: {
|
||||
link: '/special/0001386F/rank_sports.html',
|
||||
title: '体育',
|
||||
},
|
||||
money: {
|
||||
link: 'https://money.163.com/special/002526BH/rank.html',
|
||||
title: '财经',
|
||||
},
|
||||
tech: {
|
||||
link: '/special/0001386F/rank_tech.html',
|
||||
title: '科技',
|
||||
},
|
||||
auto: {
|
||||
link: '/special/0001386F/rank_auto.html',
|
||||
title: '汽车',
|
||||
},
|
||||
lady: {
|
||||
link: '/special/0001386F/rank_lady.html',
|
||||
title: '女人',
|
||||
},
|
||||
house: {
|
||||
link: '/special/0001386F/rank_house.html',
|
||||
title: '房产',
|
||||
},
|
||||
game: {
|
||||
link: '/special/0001386F/game_rank.html',
|
||||
title: '游戏',
|
||||
},
|
||||
travel: {
|
||||
link: '/special/0001386F/rank_travel.html',
|
||||
title: '旅游',
|
||||
},
|
||||
edu: {
|
||||
link: '/special/0001386F/rank_edu.html',
|
||||
title: '教育',
|
||||
},
|
||||
};
|
||||
|
||||
const timeRange = {
|
||||
hour: {
|
||||
index: 0,
|
||||
title: '1小时',
|
||||
},
|
||||
day: {
|
||||
index: 1,
|
||||
title: '24小时',
|
||||
},
|
||||
week: {
|
||||
index: 2,
|
||||
title: '本周',
|
||||
},
|
||||
month: {
|
||||
index: 3,
|
||||
title: '本月',
|
||||
},
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') || 'whole';
|
||||
const type = ctx.req.param('type') || 'click';
|
||||
const time = ctx.req.param('time') || 'day';
|
||||
|
||||
const cfg = config[category];
|
||||
if (!cfg) {
|
||||
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
|
||||
} else if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
|
||||
throw new Error('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
|
||||
}
|
||||
|
||||
const currentUrl = category === 'money' ? cfg.link : `${rootUrl}${cfg.link}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const $ = load(iconv.decode(response.data, 'gbk'));
|
||||
|
||||
const list = $('div.tabContents')
|
||||
.eq(timeRange[time].index + (category === 'whole' ? (type === 'click' ? -1 : 2) : type === 'click' ? 0 : 2))
|
||||
.find('table tbody tr td a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
link: item.attr('href'),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
try {
|
||||
let link;
|
||||
if (category === 'auto' || category === 'house' || category === 'travel') {
|
||||
const category = item.link.split('.163.com')[0].split('//').pop().split('.').pop();
|
||||
link = `https://3g.163.com/${category}/article/${item.link.split('/').pop()}`;
|
||||
} else {
|
||||
const pathname = new URL(item.link).pathname;
|
||||
link = `https://3g.163.com${pathname}`;
|
||||
}
|
||||
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
});
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.bot_word, .js-open-app, .s-img').remove();
|
||||
content('video').each(function () {
|
||||
content(this).attr('src', content(this).attr('data-src'));
|
||||
});
|
||||
content('.article-body .image-lazy').each((_, elem) => {
|
||||
elem.attribs.src = elem.attribs['data-src'] ?? elem.attribs.src;
|
||||
});
|
||||
|
||||
item.title = content('meta[property="og:title"]').attr('content').replace('_手机网易网', '');
|
||||
item.pubDate = parseDate(content('meta[property="og:release_date"]').attr('content'));
|
||||
item.description = content('.article-body').html();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `网易新闻${timeRange[time].title}${type === 'click' ? '点击' : '跟帖'}榜 - ${cfg.title}`,
|
||||
link: currentUrl,
|
||||
item: items.filter(Boolean),
|
||||
});
|
||||
};
|
||||
@@ -1,115 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { load } from 'cheerio';
|
||||
const typeMap = {
|
||||
1: '轻松一刻',
|
||||
2: '槽值',
|
||||
3: '人间',
|
||||
4: '大国小民',
|
||||
5: '三三有梗',
|
||||
6: '数读',
|
||||
7: '看客',
|
||||
8: '下划线',
|
||||
9: '谈心社',
|
||||
10: '哒哒',
|
||||
11: '胖编怪聊',
|
||||
12: '曲一刀',
|
||||
13: '今日之声',
|
||||
14: '浪潮',
|
||||
15: '沸点',
|
||||
};
|
||||
export default async (ctx) => {
|
||||
if (!ctx.req.param('type')) {
|
||||
throw new Error('Bad parameter. See <a href="https://docs.rsshub.app/routes/game#wang-yi-da-shen">https://docs.rsshub.app/routes/game#wang-yi-da-shen</a>');
|
||||
}
|
||||
const selectedType = Number.parseInt(ctx.req.param('type'));
|
||||
let type;
|
||||
switch (selectedType) {
|
||||
case 1:
|
||||
type = `BD21K0DLwangning`; // 轻松一刻
|
||||
break;
|
||||
case 2:
|
||||
type = `CICMICLUwangning`; // 槽值
|
||||
break;
|
||||
case 3:
|
||||
type = `CICMOMBLwangning`; // 人间
|
||||
break;
|
||||
case 4:
|
||||
type = `CICMPVC5wangning`; // 大国小民
|
||||
break;
|
||||
case 5:
|
||||
type = `CICMLCOUwangning`; // 三三有梗
|
||||
break;
|
||||
case 6:
|
||||
type = `D551V75Cwangning`; // 数读
|
||||
break;
|
||||
case 7:
|
||||
type = `D55253RHwangning`; // 看客
|
||||
break;
|
||||
case 8:
|
||||
type = `D553A53Lwangning`; // 下划线
|
||||
break;
|
||||
case 9:
|
||||
type = `D553PGHQwangning`; // 谈心社
|
||||
break;
|
||||
case 10:
|
||||
type = `CICMS5BIwangning`; // 哒哒
|
||||
break;
|
||||
case 11:
|
||||
type = `CQ9UDVKOwangning`; // 胖编怪聊
|
||||
break;
|
||||
case 12:
|
||||
type = `CQ9UJIJNwangning`; // 曲一刀
|
||||
break;
|
||||
case 13:
|
||||
type = `BD284UM8wangning`; // 今日之声
|
||||
break;
|
||||
case 14:
|
||||
type = `CICMMGBHwangning`; // 浪潮
|
||||
break;
|
||||
case 15:
|
||||
type = `D5543R68wangning`; // 沸点
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const url = `https://3g.163.com/touch/reconstruct/article/list/${type}/0-20.html`;
|
||||
const response = await got(url);
|
||||
const data = response.data;
|
||||
const matches = data.replaceAll(/\s/g, '').match(/artiList\((.*?)]}\)/);
|
||||
const articlelist0 = matches[1].replace(/".*?wangning/, '"articles') + ']}';
|
||||
const articlelist = JSON.parse(articlelist0);
|
||||
const articles = articlelist.articles;
|
||||
|
||||
const items = await Promise.all(
|
||||
articles.map((article) => {
|
||||
let url = article.url;
|
||||
if (url === null || article.skipType === 'video') {
|
||||
const skipurl = article.skipURL;
|
||||
const vid = skipurl.match(/vid=(.*?)$/);
|
||||
if (vid !== null) {
|
||||
url = `https://3g.163.com/exclusive/video/${vid[1]}.html`;
|
||||
}
|
||||
}
|
||||
return cache.tryGet(url, async () => {
|
||||
const article_response = await got(url);
|
||||
const $ = load(article_response.data);
|
||||
|
||||
article.link = url;
|
||||
article.description = $('.article-body').html() || $('div[class="video"]').html();
|
||||
article.pubDate = parseDate(article.ptime);
|
||||
|
||||
return article;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const selectedTypeName = typeMap[selectedType];
|
||||
|
||||
ctx.set('data', {
|
||||
title: selectedTypeName ? `${selectedTypeName} - 网易专栏` : '网易专栏',
|
||||
link: 'https://3g.163.com/touch/exclusive/?referFrom=163',
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { load } from 'cheerio';
|
||||
const typeMap = {
|
||||
1: '轻松一刻',
|
||||
2: '槽值',
|
||||
3: '人间',
|
||||
4: '大国小民',
|
||||
5: '三三有梗',
|
||||
6: '数读',
|
||||
7: '看客',
|
||||
8: '下划线',
|
||||
9: '谈心社',
|
||||
10: '哒哒',
|
||||
11: '胖编怪聊',
|
||||
12: '曲一刀',
|
||||
13: '今日之声',
|
||||
14: '浪潮',
|
||||
15: '沸点',
|
||||
};
|
||||
export default async (ctx) => {
|
||||
if (!ctx.req.param('type')) {
|
||||
throw new Error('Bad parameter. See <a href="https://docs.rsshub.app/routes/game#wang-yi-da-shen">https://docs.rsshub.app/routes/game#wang-yi-da-shen</a>');
|
||||
}
|
||||
const selectedType = Number.parseInt(ctx.req.param('type'));
|
||||
let type;
|
||||
switch (selectedType) {
|
||||
case 1:
|
||||
type = `BD21K0DLwangning`; // 轻松一刻
|
||||
break;
|
||||
case 2:
|
||||
type = `CICMICLUwangning`; // 槽值
|
||||
break;
|
||||
case 3:
|
||||
type = `CICMOMBLwangning`; // 人间
|
||||
break;
|
||||
case 4:
|
||||
type = `CICMPVC5wangning`; // 大国小民
|
||||
break;
|
||||
case 5:
|
||||
type = `CICMLCOUwangning`; // 三三有梗
|
||||
break;
|
||||
case 6:
|
||||
type = `D551V75Cwangning`; // 数读
|
||||
break;
|
||||
case 7:
|
||||
type = `D55253RHwangning`; // 看客
|
||||
break;
|
||||
case 8:
|
||||
type = `D553A53Lwangning`; // 下划线
|
||||
break;
|
||||
case 9:
|
||||
type = `D553PGHQwangning`; // 谈心社
|
||||
break;
|
||||
case 10:
|
||||
type = `CICMS5BIwangning`; // 哒哒
|
||||
break;
|
||||
case 11:
|
||||
type = `CQ9UDVKOwangning`; // 胖编怪聊
|
||||
break;
|
||||
case 12:
|
||||
type = `CQ9UJIJNwangning`; // 曲一刀
|
||||
break;
|
||||
case 13:
|
||||
type = `BD284UM8wangning`; // 今日之声
|
||||
break;
|
||||
case 14:
|
||||
type = `CICMMGBHwangning`; // 浪潮
|
||||
break;
|
||||
case 15:
|
||||
type = `D5543R68wangning`; // 沸点
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const url = `https://3g.163.com/touch/reconstruct/article/list/${type}/0-20.html`;
|
||||
const response = await got(url);
|
||||
const data = response.data;
|
||||
const matches = data.replaceAll(/\s/g, '').match(/artiList\((.*?)]}\)/);
|
||||
const articlelist0 = matches[1].replace(/".*?wangning/, '"articles') + ']}';
|
||||
const articlelist = JSON.parse(articlelist0);
|
||||
const articles = articlelist.articles;
|
||||
|
||||
const items = await Promise.all(
|
||||
articles.map((article) => {
|
||||
let url = article.url;
|
||||
if (url === null || article.skipType === 'video') {
|
||||
const skipurl = article.skipURL;
|
||||
const vid = skipurl.match(/vid=(.*?)$/);
|
||||
if (vid !== null) {
|
||||
url = `https://3g.163.com/exclusive/video/${vid[1]}.html`;
|
||||
}
|
||||
}
|
||||
return cache.tryGet(url, async () => {
|
||||
const article_response = await got(url);
|
||||
const $ = load(article_response.data);
|
||||
|
||||
article.link = url;
|
||||
article.description = $('.article-body').html() || $('div[class="video"]').html();
|
||||
article.pubDate = parseDate(article.ptime);
|
||||
|
||||
return article;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const selectedTypeName = typeMap[selectedType];
|
||||
|
||||
ctx.set('data', {
|
||||
title: selectedTypeName ? `${selectedTypeName} - 网易专栏` : '网易专栏',
|
||||
link: 'https://3g.163.com/touch/exclusive/?referFrom=163',
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const url = 'https://vip.open.163.com';
|
||||
|
||||
const list_response = await got(url);
|
||||
const $ = load(list_response.data);
|
||||
const initialState = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){var/)[1]
|
||||
);
|
||||
|
||||
const list = Object.values(initialState.courseindex.myModules).flatMap((mod) =>
|
||||
mod.contents.map((item) => ({
|
||||
title: `${item.title} - ${item.subtitle}`,
|
||||
author: item.authorName,
|
||||
pubDate: parseDate(item.publishTime, 'x'),
|
||||
link: `${url}/courses/${item.courseUid}/`,
|
||||
courseUid: item.courseUid,
|
||||
category: mod.name,
|
||||
}))
|
||||
);
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const {
|
||||
data: { data },
|
||||
} = await got.post(`${url}/open/trade/pc/course/getCourseInfo.do`, {
|
||||
form: {
|
||||
courseUid: item.courseUid,
|
||||
version: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const $ = load(data.courseInfo.description, null, false);
|
||||
$('img').each((_, img) => {
|
||||
img.attribs.src = img.attribs.src.split('?')[0];
|
||||
delete img.attribs.width;
|
||||
});
|
||||
|
||||
item.category = [item.category, data.courseInfo.firstClassifyName, data.courseInfo.secondClassifyName];
|
||||
item.description = art(path.join(__dirname, '../templates/open.art'), {
|
||||
data,
|
||||
description: $.html(),
|
||||
});
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: '网易公开课 - 精品课程',
|
||||
link: url,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
const url = 'https://vip.open.163.com';
|
||||
|
||||
const list_response = await got(url);
|
||||
const $ = load(list_response.data);
|
||||
const initialState = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){var/)[1]
|
||||
);
|
||||
|
||||
const list = Object.values(initialState.courseindex.myModules).flatMap((mod) =>
|
||||
mod.contents.map((item) => ({
|
||||
title: `${item.title} - ${item.subtitle}`,
|
||||
author: item.authorName,
|
||||
pubDate: parseDate(item.publishTime, 'x'),
|
||||
link: `${url}/courses/${item.courseUid}/`,
|
||||
courseUid: item.courseUid,
|
||||
category: mod.name,
|
||||
}))
|
||||
);
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const {
|
||||
data: { data },
|
||||
} = await got.post(`${url}/open/trade/pc/course/getCourseInfo.do`, {
|
||||
form: {
|
||||
courseUid: item.courseUid,
|
||||
version: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const $ = load(data.courseInfo.description, null, false);
|
||||
$('img').each((_, img) => {
|
||||
img.attribs.src = img.attribs.src.split('?')[0];
|
||||
delete img.attribs.width;
|
||||
});
|
||||
|
||||
item.category = [item.category, data.courseInfo.firstClassifyName, data.courseInfo.secondClassifyName];
|
||||
item.description = art(path.join(__dirname, '../templates/open.art'), {
|
||||
data,
|
||||
description: $.html(),
|
||||
});
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: '网易公开课 - 精品课程',
|
||||
link: url,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
const titles = {
|
||||
texie: '特写',
|
||||
jishi: '记事',
|
||||
daxie: '大写',
|
||||
haodu: '好读',
|
||||
kanke: '看客',
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') ?? 'texie';
|
||||
|
||||
const rootUrl = 'https://renjian.163.com';
|
||||
const currentUrl = `${rootUrl}/special/renjian_${category}/`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const data = iconv.decode(response.data, 'gbk');
|
||||
|
||||
let items = {};
|
||||
|
||||
const urls = data.match(/url:"(.*)",/g);
|
||||
|
||||
if (urls) {
|
||||
items = urls.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50).map((item) => ({
|
||||
link: item.match(/url:"(.*)",/)[1],
|
||||
}));
|
||||
} else {
|
||||
const $ = load(data);
|
||||
|
||||
items = $('.article h3 a')
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50)
|
||||
.toArray()
|
||||
.map((_, item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
link: item.attr('href'),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.title = content('h1').text();
|
||||
item.author = content('script')
|
||||
.text()
|
||||
.match(/renjian_author = '(.*)'/)[1];
|
||||
item.description = content('#endText').html() ?? content('#content').html();
|
||||
item.pubDate = timezone(parseDate(content('.pub_time').text() ?? content('.post_info').text().split('来源:')[0].trim()), 8);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `人间 - ${titles[category]} - 网易新闻`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
const titles = {
|
||||
texie: '特写',
|
||||
jishi: '记事',
|
||||
daxie: '大写',
|
||||
haodu: '好读',
|
||||
kanke: '看客',
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') ?? 'texie';
|
||||
|
||||
const rootUrl = 'https://renjian.163.com';
|
||||
const currentUrl = `${rootUrl}/special/renjian_${category}/`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const data = iconv.decode(response.data, 'gbk');
|
||||
|
||||
let items = {};
|
||||
|
||||
const urls = data.match(/url:"(.*)",/g);
|
||||
|
||||
if (urls) {
|
||||
items = urls.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50).map((item) => ({
|
||||
link: item.match(/url:"(.*)",/)[1],
|
||||
}));
|
||||
} else {
|
||||
const $ = load(data);
|
||||
|
||||
items = $('.article h3 a')
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50)
|
||||
.toArray()
|
||||
.map((_, item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
link: item.attr('href'),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.title = content('h1').text();
|
||||
item.author = content('script')
|
||||
.text()
|
||||
.match(/renjian_author = '(.*)'/)[1];
|
||||
item.description = content('#endText').html() ?? content('#content').html();
|
||||
item.pubDate = timezone(parseDate(content('.pub_time').text() ?? content('.post_info').text().split('来源:')[0].trim()), 8);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: `人间 - ${titles[category]} - 网易新闻`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export default async (ctx) => {
|
||||
const needContent = /t|y/i.test(ctx.req.param('need_content') ?? 'true');
|
||||
|
||||
const rootUrl = 'https://gw.m.163.com';
|
||||
const currentUrl = `${rootUrl}/nc/api/v1/feed/static/normal-list?start=0&tid=T1573700340788&size=${ctx.req.query('limit') ?? (needContent ? 30 : 200)}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
let items = response.data.data.items.map((item) => ({
|
||||
title: item.title,
|
||||
author: item.source,
|
||||
pubDate: timezone(parseDate(item.ptime), +8),
|
||||
description: `<p>${item.digest}</p><img src="${item.imgsrc}">`,
|
||||
link: item.url || `https://c.m.163.com/news/a/${item.docid}.html`,
|
||||
}));
|
||||
|
||||
if (needContent) {
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.bot_word').remove();
|
||||
|
||||
content('img').each((_, img) => {
|
||||
img.attribs.src = img.attribs['data-src'] ?? img.attribs.src;
|
||||
});
|
||||
|
||||
item.description = content('.content, article').html();
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ctx.set('data', {
|
||||
title: '今日关注 - 网易新闻',
|
||||
link: 'https://wp.m.163.com/163/html/newsapp/todayFocus/index.html',
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export default async (ctx) => {
|
||||
const needContent = /t|y/i.test(ctx.req.param('need_content') ?? 'true');
|
||||
|
||||
const rootUrl = 'https://gw.m.163.com';
|
||||
const currentUrl = `${rootUrl}/nc/api/v1/feed/static/normal-list?start=0&tid=T1573700340788&size=${ctx.req.query('limit') ?? (needContent ? 30 : 200)}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
let items = response.data.data.items.map((item) => ({
|
||||
title: item.title,
|
||||
author: item.source,
|
||||
pubDate: timezone(parseDate(item.ptime), +8),
|
||||
description: `<p>${item.digest}</p><img src="${item.imgsrc}">`,
|
||||
link: item.url || `https://c.m.163.com/news/a/${item.docid}.html`,
|
||||
}));
|
||||
|
||||
if (needContent) {
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.bot_word').remove();
|
||||
|
||||
content('img').each((_, img) => {
|
||||
img.attribs.src = img.attribs['data-src'] ?? img.attribs.src;
|
||||
});
|
||||
|
||||
item.description = content('.content, article').html();
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ctx.set('data', {
|
||||
title: '今日关注 - 网易新闻',
|
||||
link: 'https://wp.m.163.com/163/html/newsapp/todayFocus/index.html',
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const parseDyArticle = (charset, item, tryGet) =>
|
||||
tryGet(item.link, async () => {
|
||||
const response = await got(item.link, {
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const html = iconv.decode(response.data, charset);
|
||||
const $ = load(html);
|
||||
|
||||
$('.post_main img').each((_, i) => {
|
||||
if (!i.attribs.src) {
|
||||
return;
|
||||
}
|
||||
const url = new URL(i.attribs.src);
|
||||
if (url.host === 'nimg.ws.126.net') {
|
||||
i.attribs.src = url.searchParams.get('url');
|
||||
}
|
||||
});
|
||||
|
||||
item.description = art(path.join(__dirname, 'templates/dy.art'), {
|
||||
imgsrc: item.imgsrc?.split('?')[0],
|
||||
postBody: $('.post_body').html(),
|
||||
});
|
||||
|
||||
item.feedLink = $('.post_wemedia_name a').attr('href');
|
||||
item.feedDescription = $('.post_wemedia_title').text();
|
||||
item.feedImage = $('.post_wemedia_avatar img').attr('src');
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
parseDyArticle,
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
const iconv = require('iconv-lite');
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
|
||||
const parseDyArticle = (charset, item, tryGet) =>
|
||||
tryGet(item.link, async () => {
|
||||
const response = await got(item.link, {
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const html = iconv.decode(response.data, charset);
|
||||
const $ = load(html);
|
||||
|
||||
$('.post_main img').each((_, i) => {
|
||||
if (!i.attribs.src) {
|
||||
return;
|
||||
}
|
||||
const url = new URL(i.attribs.src);
|
||||
if (url.host === 'nimg.ws.126.net') {
|
||||
i.attribs.src = url.searchParams.get('url');
|
||||
}
|
||||
});
|
||||
|
||||
item.description = art(path.join(__dirname, 'templates/dy.art'), {
|
||||
imgsrc: item.imgsrc?.split('?')[0],
|
||||
postBody: $('.post_body').html(),
|
||||
});
|
||||
|
||||
item.feedLink = $('.post_wemedia_name a').attr('href');
|
||||
item.feedDescription = $('.post_wemedia_title').text();
|
||||
item.feedImage = $('.post_wemedia_avatar img').attr('src');
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
parseDyArticle,
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const { defaultDomain, getRootUrl } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/album/${id}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
const category = $('span[data-type="tags"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((c) => $(c).text());
|
||||
const author = $('span[data-type="author"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((a) => $(a).text())
|
||||
.join(', ');
|
||||
|
||||
let items = $('.btn-toolbar')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${rootUrl}${item.attr('href')}`,
|
||||
guid: `https://18comic.org${item.attr('href')}`,
|
||||
pubDate: parseDate(item.find('.hidden-xs').text()),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.guid, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.tab-content').remove();
|
||||
|
||||
item.author = author;
|
||||
item.category = category;
|
||||
item.description = `<img src="${content('.thumb-overlay-albums img[data-original]')
|
||||
.toArray()
|
||||
.map((image) => content(image).attr('data-original'))
|
||||
.join('"><img src="')}">`;
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('title').text(),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
description: $('meta[property="og:description"]').attr('content'),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const { defaultDomain, getRootUrl } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/album/${id}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
const category = $('span[data-type="tags"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((c) => $(c).text());
|
||||
const author = $('span[data-type="author"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((a) => $(a).text())
|
||||
.join(', ');
|
||||
|
||||
let items = $('.btn-toolbar')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${rootUrl}${item.attr('href')}`,
|
||||
guid: `https://18comic.org${item.attr('href')}`,
|
||||
pubDate: parseDate(item.find('.hidden-xs').text()),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.guid, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
content('.tab-content').remove();
|
||||
|
||||
item.author = author;
|
||||
item.category = category;
|
||||
item.description = `<img src="${content('.thumb-overlay-albums img[data-original]')
|
||||
.toArray()
|
||||
.map((image) => content(image).attr('data-original'))
|
||||
.join('"><img src="')}">`;
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('title').text(),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
description: $('meta[property="og:description"]').attr('content'),
|
||||
});
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const { defaultDomain, getRootUrl } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') ?? '';
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/blogs${category ? `/${category}` : ''}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
let items = $('.title')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${rootUrl}${item.parent().attr('href')}`,
|
||||
guid: `https://18comic.org${item.parent().attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.guid, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.pubDate = parseDate(content('.date').first().text());
|
||||
|
||||
content('.d-flex').remove();
|
||||
|
||||
item.author = content('.blog_name_id').first().text();
|
||||
item.description = content('.blog_content').html();
|
||||
item.category = content('.panel-heading dropdown-toggle')
|
||||
.toArray()
|
||||
.map((c) => $(c).text());
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('title')
|
||||
.text()
|
||||
.replace(/最新的/, $('.article-nav .active').text()),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
description: $('meta[property="og:description"]').attr('content'),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const { defaultDomain, getRootUrl } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') ?? '';
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/blogs${category ? `/${category}` : ''}`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
let items = $('.title')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${rootUrl}${item.parent().attr('href')}`,
|
||||
guid: `https://18comic.org${item.parent().attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.guid, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.pubDate = parseDate(content('.date').first().text());
|
||||
|
||||
content('.d-flex').remove();
|
||||
|
||||
item.author = content('.blog_name_id').first().text();
|
||||
item.description = content('.blog_content').html();
|
||||
item.category = content('.panel-heading dropdown-toggle')
|
||||
.toArray()
|
||||
.map((c) => $(c).text());
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('title')
|
||||
.text()
|
||||
.replace(/最新的/, $('.article-nav .active').text()),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
description: $('meta[property="og:description"]').attr('content'),
|
||||
});
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
const { defaultDomain, getRootUrl, ProcessItems } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') ?? 'all';
|
||||
const keyword = ctx.req.param('keyword') ?? '';
|
||||
const time = ctx.req.param('time') ?? 'a';
|
||||
const order = ctx.req.param('order') ?? 'mr';
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/albums${category === 'all' ? '' : `/${category}`}${keyword ? `?screen=${keyword}` : '?'}${time === 'a' ? '' : `&t=${time}`}${order === 'mr' ? '' : `&o=${order}`}`;
|
||||
|
||||
ctx.set('data', await ProcessItems(ctx, currentUrl, rootUrl));
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
// @ts-nocheck
|
||||
const { defaultDomain, getRootUrl, ProcessItems } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const category = ctx.req.param('category') ?? 'all';
|
||||
const keyword = ctx.req.param('keyword') ?? '';
|
||||
const time = ctx.req.param('time') ?? 'a';
|
||||
const order = ctx.req.param('order') ?? 'mr';
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/albums${category === 'all' ? '' : `/${category}`}${keyword ? `?screen=${keyword}` : '?'}${time === 'a' ? '' : `&t=${time}`}${order === 'mr' ? '' : `&o=${order}`}`;
|
||||
|
||||
ctx.set('data', await ProcessItems(ctx, currentUrl, rootUrl));
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
const { defaultDomain, getRootUrl, ProcessItems } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const option = ctx.req.param('option') ?? 'photos';
|
||||
const category = ctx.req.param('category') ?? 'all';
|
||||
const keyword = ctx.req.param('keyword') ?? '';
|
||||
const time = ctx.req.param('time') ?? 'a';
|
||||
const order = ctx.req.param('order') ?? 'mr';
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/search/${option}${category === 'all' ? '' : `/${category}`}${keyword ? `?search_query=${keyword}` : '?'}${time === 'a' ? '' : `&t=${time}`}${order === 'mr' ? '' : `&o=${order}`}`;
|
||||
|
||||
ctx.set('data', await ProcessItems(ctx, currentUrl, rootUrl));
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
const { defaultDomain, getRootUrl, ProcessItems } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const option = ctx.req.param('option') ?? 'photos';
|
||||
const category = ctx.req.param('category') ?? 'all';
|
||||
const keyword = ctx.req.param('keyword') ?? '';
|
||||
const time = ctx.req.param('time') ?? 'a';
|
||||
const order = ctx.req.param('order') ?? 'mr';
|
||||
const { domain = defaultDomain } = ctx.req.query();
|
||||
const rootUrl = getRootUrl(domain);
|
||||
|
||||
const currentUrl = `${rootUrl}/search/${option}${category === 'all' ? '' : `/${category}`}${keyword ? `?search_query=${keyword}` : '?'}${time === 'a' ? '' : `&t=${time}`}${order === 'mr' ? '' : `&o=${order}`}`;
|
||||
|
||||
ctx.set('data', await ProcessItems(ctx, currentUrl, rootUrl));
|
||||
};
|
||||
@@ -1,83 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
import { config } from '@/config';
|
||||
|
||||
const defaultDomain = 'jmcomic1.me';
|
||||
// list of address: https://jmcomic2.bet
|
||||
const allowDomain = new Set(['18comic.vip', '18comic.org', 'jmcomic.me', 'jmcomic1.me', 'jm-comic3.art', 'jm-comic.club', 'jm-comic2.ark']);
|
||||
|
||||
const getRootUrl = (domain) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(domain)) {
|
||||
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
return `https://${domain}`;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
defaultDomain,
|
||||
getRootUrl,
|
||||
ProcessItems: async (ctx, currentUrl, rootUrl) => {
|
||||
currentUrl = currentUrl.replace(/\?$/, '');
|
||||
|
||||
const response = await got(currentUrl);
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
let items = $('.video-title')
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text().trim(),
|
||||
link: `${rootUrl}${item.prev().find('a').attr('href')}`,
|
||||
guid: `18comic:${item.prev().find('a').attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.guid, async () => {
|
||||
const detailResponse = await got(item.link);
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.pubDate = parseDate(content('div[itemprop="datePublished"]').first().attr('content'));
|
||||
item.category = content('span[data-type="tags"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((c) => $(c).text());
|
||||
item.author = content('span[data-type="author"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((a) => $(a).text())
|
||||
.join(', ');
|
||||
item.description = art(path.join(__dirname, 'templates/description.art'), {
|
||||
introduction: content('#intro-block .p-t-5').text(),
|
||||
images: content('.img_zoom_img img')
|
||||
.toArray()
|
||||
.map((image) => content(image).attr('data-original')),
|
||||
});
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: $('title').text(),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
description: $('meta[property="og:description"]').attr('content'),
|
||||
allowEmpty: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
import { config } from '@/config';
|
||||
|
||||
const defaultDomain = 'jmcomic1.me';
|
||||
// list of address: https://jmcomic2.bet
|
||||
const allowDomain = new Set(['18comic.vip', '18comic.org', 'jmcomic.me', 'jmcomic1.me', 'jm-comic3.art', 'jm-comic.club', 'jm-comic2.ark']);
|
||||
|
||||
const getRootUrl = (domain) => {
|
||||
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(domain)) {
|
||||
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
|
||||
}
|
||||
|
||||
return `https://${domain}`;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
defaultDomain,
|
||||
getRootUrl,
|
||||
ProcessItems: async (ctx, currentUrl, rootUrl) => {
|
||||
currentUrl = currentUrl.replace(/\?$/, '');
|
||||
|
||||
const response = await got(currentUrl);
|
||||
|
||||
const $ = load(response.data);
|
||||
|
||||
let items = $('.video-title')
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text().trim(),
|
||||
link: `${rootUrl}${item.prev().find('a').attr('href')}`,
|
||||
guid: `18comic:${item.prev().find('a').attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.guid, async () => {
|
||||
const detailResponse = await got(item.link);
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.pubDate = parseDate(content('div[itemprop="datePublished"]').first().attr('content'));
|
||||
item.category = content('span[data-type="tags"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((c) => $(c).text());
|
||||
item.author = content('span[data-type="author"]')
|
||||
.first()
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((a) => $(a).text())
|
||||
.join(', ');
|
||||
item.description = art(path.join(__dirname, 'templates/description.art'), {
|
||||
introduction: content('#intro-block .p-t-5').text(),
|
||||
images: content('.img_zoom_img img')
|
||||
.toArray()
|
||||
.map((image) => content(image).attr('data-original')),
|
||||
});
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: $('title').text(),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
description: $('meta[property="og:description"]').attr('content'),
|
||||
allowEmpty: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
const iconv = require('iconv-lite');
|
||||
import { isValidHost } from '@/utils/valid-host';
|
||||
|
||||
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure) {
|
||||
let expires = null;
|
||||
if (seconds !== -1) {
|
||||
expires = new Date();
|
||||
expires.setTime(expires.getTime() + seconds);
|
||||
}
|
||||
return [encodeURI(cookieName), '=', encodeURI(cookieValue), expires ? '; expires=' + expires.toGMTString() : '', path ? '; path=' + path : '/', domain ? '; domain=' + domain : '', secure ? '; secure' : ''].join('');
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const city = ctx.req.param('city') ?? 'www';
|
||||
if (!isValidHost(city)) {
|
||||
throw new Error('Invalid city');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${city}.19lou.com`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: rootUrl,
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const $ = load(iconv.decode(response.data, 'gbk'));
|
||||
|
||||
$('.title-more').remove();
|
||||
|
||||
let items = $('.center-center-jiazi')
|
||||
.find('a[title]')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.attr('title'),
|
||||
link: `https:${item.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
responseType: 'buffer',
|
||||
headers: {
|
||||
cookie: setCookie('_Z3nY0d4C_', '37XgPK9h', 365, '/', '19lou.com'),
|
||||
referer: rootUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const content = load(iconv.decode(detailResponse.data, 'gbk'));
|
||||
|
||||
content('.name-lz, .postView-pk-mod').remove();
|
||||
|
||||
item.author = content('.uname, .user-name').first().text();
|
||||
item.description = content('.post-cont').first().html() || content('.thread-cont').html();
|
||||
item.pubDate = timezone(parseDate(content('.cont-top-left meta').first().attr('content')), +8);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('title').text().split('-')[0],
|
||||
link: rootUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
const iconv = require('iconv-lite');
|
||||
import { isValidHost } from '@/utils/valid-host';
|
||||
|
||||
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure) {
|
||||
let expires = null;
|
||||
if (seconds !== -1) {
|
||||
expires = new Date();
|
||||
expires.setTime(expires.getTime() + seconds);
|
||||
}
|
||||
return [encodeURI(cookieName), '=', encodeURI(cookieValue), expires ? '; expires=' + expires.toGMTString() : '', path ? '; path=' + path : '/', domain ? '; domain=' + domain : '', secure ? '; secure' : ''].join('');
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const city = ctx.req.param('city') ?? 'www';
|
||||
if (!isValidHost(city)) {
|
||||
throw new Error('Invalid city');
|
||||
}
|
||||
|
||||
const rootUrl = `https://${city}.19lou.com`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: rootUrl,
|
||||
responseType: 'buffer',
|
||||
});
|
||||
|
||||
const $ = load(iconv.decode(response.data, 'gbk'));
|
||||
|
||||
$('.title-more').remove();
|
||||
|
||||
let items = $('.center-center-jiazi')
|
||||
.find('a[title]')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
|
||||
return {
|
||||
title: item.attr('title'),
|
||||
link: `https:${item.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
responseType: 'buffer',
|
||||
headers: {
|
||||
cookie: setCookie('_Z3nY0d4C_', '37XgPK9h', 365, '/', '19lou.com'),
|
||||
referer: rootUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const content = load(iconv.decode(detailResponse.data, 'gbk'));
|
||||
|
||||
content('.name-lz, .postView-pk-mod').remove();
|
||||
|
||||
item.author = content('.uname, .user-name').first().text();
|
||||
item.description = content('.post-cont').first().html() || content('.thread-cont').html();
|
||||
item.pubDate = timezone(parseDate(content('.cont-top-left meta').first().attr('content')), +8);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.set('data', {
|
||||
title: $('title').text().split('-')[0],
|
||||
link: rootUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export default async (ctx) => {
|
||||
const path = ctx.req.param('path') ?? '';
|
||||
const rootUrl = `https://www.1lou.me`;
|
||||
const currentUrl = `${rootUrl}/${path}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
const $ = load(response.data);
|
||||
|
||||
let items = $('li.media.thread.tap:not(.hidden-sm)')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const title = $(item).find('.subject.break-all').children('a').first();
|
||||
const author = $(item).find('.username.text-grey.mr-1').text();
|
||||
const pubDate = $(item).find('.date.text-grey').text();
|
||||
return {
|
||||
title: title.text(),
|
||||
link: `${rootUrl}/${title.attr('href')}`,
|
||||
author,
|
||||
pubDate: timezone(parseDate(pubDate), +8),
|
||||
};
|
||||
});
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const content = load(detailResponse.data);
|
||||
item.description = content('.message.break-all').html();
|
||||
const torrents = content('.attachlist').find('a');
|
||||
if (torrents.length > 0) {
|
||||
item.enclosure_type = 'application/x-bittorrent';
|
||||
item.enclosure_url = `${rootUrl}/${torrents.first().attr('href')}`;
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
ctx.set('data', {
|
||||
title: '1Lou',
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export default async (ctx) => {
|
||||
const path = ctx.req.param('path') ?? '';
|
||||
const rootUrl = `https://www.1lou.me`;
|
||||
const currentUrl = `${rootUrl}/${path}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
const $ = load(response.data);
|
||||
|
||||
let items = $('li.media.thread.tap:not(.hidden-sm)')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const title = $(item).find('.subject.break-all').children('a').first();
|
||||
const author = $(item).find('.username.text-grey.mr-1').text();
|
||||
const pubDate = $(item).find('.date.text-grey').text();
|
||||
return {
|
||||
title: title.text(),
|
||||
link: `${rootUrl}/${title.attr('href')}`,
|
||||
author,
|
||||
pubDate: timezone(parseDate(pubDate), +8),
|
||||
};
|
||||
});
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const content = load(detailResponse.data);
|
||||
item.description = content('.message.break-all').html();
|
||||
const torrents = content('.attachlist').find('a');
|
||||
if (torrents.length > 0) {
|
||||
item.enclosure_type = 'application/x-bittorrent';
|
||||
item.enclosure_url = `${rootUrl}/${torrents.first().attr('href')}`;
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
ctx.set('data', {
|
||||
title: '1Lou',
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export default async (ctx) => {
|
||||
const categoryMap = {
|
||||
studyinusa: {
|
||||
title: '留学申请',
|
||||
id: 18,
|
||||
},
|
||||
career: {
|
||||
title: '找工求职',
|
||||
id: 200,
|
||||
},
|
||||
lifestyle: {
|
||||
title: '生活攻略',
|
||||
id: 370,
|
||||
},
|
||||
invest: {
|
||||
title: '投资理财',
|
||||
id: 371,
|
||||
},
|
||||
visa: {
|
||||
title: '签证移民',
|
||||
id: 194,
|
||||
},
|
||||
news: {
|
||||
title: '时政要闻',
|
||||
id: 366,
|
||||
},
|
||||
};
|
||||
|
||||
const category = ctx.req.param('category');
|
||||
|
||||
const rootUrl = 'https://blog.1point3acres.com';
|
||||
const currentUrl = `${rootUrl}/${category}/`;
|
||||
const { data } = await got(`${rootUrl}/wp-json/wp/v2/posts`, {
|
||||
searchParams: {
|
||||
categories: category ? categoryMap[category].id : undefined,
|
||||
per_page: ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 100,
|
||||
},
|
||||
});
|
||||
|
||||
const items = data.map((item) => {
|
||||
const $ = load(item.content.rendered, null, false);
|
||||
$('h2').nextAll().remove();
|
||||
$('[powered-by="1p3a"], h2').remove();
|
||||
$('img').each((_, img) => {
|
||||
if (/wp-content\/uploads/.test(img.attribs.src)) {
|
||||
img.attribs.src = img.attribs.src.replace(/(-\d+x\d+)/, '');
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
title: item.title.rendered,
|
||||
description: $.html(),
|
||||
link: item.link,
|
||||
pubDate: parseDate(item.date_gmt),
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${category ? `${categoryMap[category].title} | ` : ''}美国留学就业生活攻略`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export default async (ctx) => {
|
||||
const categoryMap = {
|
||||
studyinusa: {
|
||||
title: '留学申请',
|
||||
id: 18,
|
||||
},
|
||||
career: {
|
||||
title: '找工求职',
|
||||
id: 200,
|
||||
},
|
||||
lifestyle: {
|
||||
title: '生活攻略',
|
||||
id: 370,
|
||||
},
|
||||
invest: {
|
||||
title: '投资理财',
|
||||
id: 371,
|
||||
},
|
||||
visa: {
|
||||
title: '签证移民',
|
||||
id: 194,
|
||||
},
|
||||
news: {
|
||||
title: '时政要闻',
|
||||
id: 366,
|
||||
},
|
||||
};
|
||||
|
||||
const category = ctx.req.param('category');
|
||||
|
||||
const rootUrl = 'https://blog.1point3acres.com';
|
||||
const currentUrl = `${rootUrl}/${category}/`;
|
||||
const { data } = await got(`${rootUrl}/wp-json/wp/v2/posts`, {
|
||||
searchParams: {
|
||||
categories: category ? categoryMap[category].id : undefined,
|
||||
per_page: ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 100,
|
||||
},
|
||||
});
|
||||
|
||||
const items = data.map((item) => {
|
||||
const $ = load(item.content.rendered, null, false);
|
||||
$('h2').nextAll().remove();
|
||||
$('[powered-by="1p3a"], h2').remove();
|
||||
$('img').each((_, img) => {
|
||||
if (/wp-content\/uploads/.test(img.attribs.src)) {
|
||||
img.attribs.src = img.attribs.src.replace(/(-\d+x\d+)/, '');
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
title: item.title.rendered,
|
||||
description: $.html(),
|
||||
link: item.link,
|
||||
pubDate: parseDate(item.date_gmt),
|
||||
};
|
||||
});
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${category ? `${categoryMap[category].title} | ` : ''}美国留学就业生活攻略`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
});
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
const { rootUrl, apiRootUrl, types, ProcessThreads } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') ?? '';
|
||||
const type = ctx.req.param('type') ?? 'hot';
|
||||
const order = ctx.req.param('order') ?? '';
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
|
||||
|
||||
const currentUrl = `${rootUrl}${id ? `/category/${id}` : ''}`;
|
||||
const apiUrl = `${apiRootUrl}/api${id ? `/tags/${id}/` : ''}threads?type=${type}&includes=tags,forum_name,summary&ps=${limit}&pg=1&order=${order === '' ? '' : 'time_desc'}&is_groupid=1`;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `一亩三分地 - ${id}${types[type]}`,
|
||||
link: currentUrl,
|
||||
item: await ProcessThreads(cache.tryGet, apiUrl, order),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
const { rootUrl, apiRootUrl, types, ProcessThreads } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') ?? '';
|
||||
const type = ctx.req.param('type') ?? 'hot';
|
||||
const order = ctx.req.param('order') ?? '';
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
|
||||
|
||||
const currentUrl = `${rootUrl}${id ? `/category/${id}` : ''}`;
|
||||
const apiUrl = `${apiRootUrl}/api${id ? `/tags/${id}/` : ''}threads?type=${type}&includes=tags,forum_name,summary&ps=${limit}&pg=1&order=${order === '' ? '' : 'time_desc'}&is_groupid=1`;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `一亩三分地 - ${id}${types[type]}`,
|
||||
link: currentUrl,
|
||||
item: await ProcessThreads(cache.tryGet, apiUrl, order),
|
||||
});
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
// year 2017-2022
|
||||
// 2017:6 2018:11 2019:12 2020:13 2021:14 2022:15
|
||||
// CS:1 MIS:2
|
||||
const { year = 'null', major = 'null', school = 'null' } = ctx.req.param();
|
||||
// const filter = 'filters: {planyr: "12", planmajor: "1", outname_w: "CMU"}';
|
||||
const responseBasic = await got.post('https://api.1point3acres.com/offer/results', {
|
||||
searchParams: {
|
||||
ps: 15,
|
||||
pg: 1,
|
||||
},
|
||||
json: {
|
||||
filters: {
|
||||
planyr: year === 'null' ? undefined : year,
|
||||
planmajor: major === 'null' ? undefined : major,
|
||||
outname_w: school === 'null' ? undefined : school,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const data = responseBasic.data.results;
|
||||
// data.id-> 访问offer具体信息->获取 data.tid
|
||||
// if (data.id !== 0) {
|
||||
// out = await Promise.all(
|
||||
// data.map(async (item) => {
|
||||
// var gettidresponse = await got({
|
||||
// method: 'get',
|
||||
// url: 'https://api.1point3acres.com/offer/results/'+ item.id + '/backgrounds',
|
||||
// headers: {
|
||||
// authorization: 'eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Njk5Njc5OSwiZXhwIjoxNTg0ODU5MTk5fQ.eyJ1aWQiOjQ1NzQyN30.0ei5UE6OgLBzN2_IS7xUIbIfW_S1Wzl42q2UeusbboxuzvctO_4Mz6YRr6f0PBLUVZMETxt8F0_4-yqIJ3_kUQ',
|
||||
// },
|
||||
// });
|
||||
// var tid = gettidresponse.data.background.tid;
|
||||
// //https: //www.1point3acres.com/bbs/thread-581177-1-1.html
|
||||
// console.log(tid);
|
||||
// const threadlink = 'https://www.1point3acres.com/bbs/thread-' + tid + '-1-1.html';
|
||||
// console.log(threadlink);
|
||||
// return threadlink;
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
// let responseBasic_1;
|
||||
// responseBasic_1 = await got({
|
||||
// method: 'get',
|
||||
// url: `https://api.1point3acres.com/offer/results/A7m20e4g/backgrounds`,
|
||||
// headers: {
|
||||
// authorization: `eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Njk5Njc5OSwiZXhwIjoxNTg0ODU5MTk5fQ.eyJ1aWQiOjQ1NzQyN30.0ei5UE6OgLBzN2_IS7xUIbIfW_S1Wzl42q2UeusbboxuzvctO_4Mz6YRr6f0PBLUVZMETxt8F0_4-yqIJ3_kUQ`,
|
||||
// },
|
||||
// });
|
||||
// const tid = responseBasic_1.data.background.tid;
|
||||
ctx.set('data', {
|
||||
title: '录取结果 - 一亩三分地',
|
||||
link: 'https://offer.1point3acres.com',
|
||||
item: data.map((item) => ({
|
||||
title: `${item.planyr}年${item.planmajor}@${item.outname_w}:${item.result} - 一亩三分地`,
|
||||
description: art(path.join(__dirname, 'templates/offer.art'), {
|
||||
item,
|
||||
}),
|
||||
pubDate: parseDate(item.dateline, 'X'),
|
||||
link: 'https://offer.1point3acres.com',
|
||||
guid: `1point3acres:offer:${year}:${major}:${school}:${item.id}`,
|
||||
})),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
import { art } from '@/utils/render';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import * as path from 'node:path';
|
||||
|
||||
export default async (ctx) => {
|
||||
// year 2017-2022
|
||||
// 2017:6 2018:11 2019:12 2020:13 2021:14 2022:15
|
||||
// CS:1 MIS:2
|
||||
const { year = 'null', major = 'null', school = 'null' } = ctx.req.param();
|
||||
// const filter = 'filters: {planyr: "12", planmajor: "1", outname_w: "CMU"}';
|
||||
const responseBasic = await got.post('https://api.1point3acres.com/offer/results', {
|
||||
searchParams: {
|
||||
ps: 15,
|
||||
pg: 1,
|
||||
},
|
||||
json: {
|
||||
filters: {
|
||||
planyr: year === 'null' ? undefined : year,
|
||||
planmajor: major === 'null' ? undefined : major,
|
||||
outname_w: school === 'null' ? undefined : school,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const data = responseBasic.data.results;
|
||||
// data.id-> 访问offer具体信息->获取 data.tid
|
||||
// if (data.id !== 0) {
|
||||
// out = await Promise.all(
|
||||
// data.map(async (item) => {
|
||||
// var gettidresponse = await got({
|
||||
// method: 'get',
|
||||
// url: 'https://api.1point3acres.com/offer/results/'+ item.id + '/backgrounds',
|
||||
// headers: {
|
||||
// authorization: 'eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Njk5Njc5OSwiZXhwIjoxNTg0ODU5MTk5fQ.eyJ1aWQiOjQ1NzQyN30.0ei5UE6OgLBzN2_IS7xUIbIfW_S1Wzl42q2UeusbboxuzvctO_4Mz6YRr6f0PBLUVZMETxt8F0_4-yqIJ3_kUQ',
|
||||
// },
|
||||
// });
|
||||
// var tid = gettidresponse.data.background.tid;
|
||||
// //https: //www.1point3acres.com/bbs/thread-581177-1-1.html
|
||||
// console.log(tid);
|
||||
// const threadlink = 'https://www.1point3acres.com/bbs/thread-' + tid + '-1-1.html';
|
||||
// console.log(threadlink);
|
||||
// return threadlink;
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
// let responseBasic_1;
|
||||
// responseBasic_1 = await got({
|
||||
// method: 'get',
|
||||
// url: `https://api.1point3acres.com/offer/results/A7m20e4g/backgrounds`,
|
||||
// headers: {
|
||||
// authorization: `eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Njk5Njc5OSwiZXhwIjoxNTg0ODU5MTk5fQ.eyJ1aWQiOjQ1NzQyN30.0ei5UE6OgLBzN2_IS7xUIbIfW_S1Wzl42q2UeusbboxuzvctO_4Mz6YRr6f0PBLUVZMETxt8F0_4-yqIJ3_kUQ`,
|
||||
// },
|
||||
// });
|
||||
// const tid = responseBasic_1.data.background.tid;
|
||||
ctx.set('data', {
|
||||
title: '录取结果 - 一亩三分地',
|
||||
link: 'https://offer.1point3acres.com',
|
||||
item: data.map((item) => ({
|
||||
title: `${item.planyr}年${item.planmajor}@${item.outname_w}:${item.result} - 一亩三分地`,
|
||||
description: art(path.join(__dirname, 'templates/offer.art'), {
|
||||
item,
|
||||
}),
|
||||
pubDate: parseDate(item.dateline, 'X'),
|
||||
link: 'https://offer.1point3acres.com',
|
||||
guid: `1point3acres:offer:${year}:${major}:${school}:${item.id}`,
|
||||
})),
|
||||
});
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
const { rootUrl, apiRootUrl, types, ProcessThreads } = require('./utils');
|
||||
|
||||
const sections = {
|
||||
257: '留学申请',
|
||||
379: '世界公民',
|
||||
400: '投资理财',
|
||||
31: '生活干货',
|
||||
345: '职场达人',
|
||||
391: '人际关系',
|
||||
38: '海外求职',
|
||||
265: '签证移民',
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') ?? '';
|
||||
const type = ctx.req.param('type') ?? 'hot';
|
||||
const order = ctx.req.param('order') ?? '';
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
|
||||
|
||||
const currentUrl = `${rootUrl}${id ? (isNaN(id) ? `/category/${id}` : `/section/${id}`) : ''}`;
|
||||
const apiUrl = `${apiRootUrl}/api${id ? (isNaN(id) ? `/tags/${id}/` : `/forums/${id}/`) : ''}threads?type=${type}&includes=tags,forum_name,summary&ps=${limit}&pg=1&order=${order === '' ? '' : 'time_desc'}&is_groupid=1`;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `一亩三分地 - ${Object.hasOwn(sections, id) ? sections[id] : id}${types[type]}`,
|
||||
link: currentUrl,
|
||||
item: await ProcessThreads(cache.tryGet, apiUrl, order),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
const { rootUrl, apiRootUrl, types, ProcessThreads } = require('./utils');
|
||||
|
||||
const sections = {
|
||||
257: '留学申请',
|
||||
379: '世界公民',
|
||||
400: '投资理财',
|
||||
31: '生活干货',
|
||||
345: '职场达人',
|
||||
391: '人际关系',
|
||||
38: '海外求职',
|
||||
265: '签证移民',
|
||||
};
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id') ?? '';
|
||||
const type = ctx.req.param('type') ?? 'hot';
|
||||
const order = ctx.req.param('order') ?? '';
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
|
||||
|
||||
const currentUrl = `${rootUrl}${id ? (isNaN(id) ? `/category/${id}` : `/section/${id}`) : ''}`;
|
||||
const apiUrl = `${apiRootUrl}/api${id ? (isNaN(id) ? `/tags/${id}/` : `/forums/${id}/`) : ''}threads?type=${type}&includes=tags,forum_name,summary&ps=${limit}&pg=1&order=${order === '' ? '' : 'time_desc'}&is_groupid=1`;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `一亩三分地 - ${Object.hasOwn(sections, id) ? sections[id] : id}${types[type]}`,
|
||||
link: currentUrl,
|
||||
item: await ProcessThreads(cache.tryGet, apiUrl, order),
|
||||
});
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
import cache from '@/utils/cache';
|
||||
const { rootUrl, apiRootUrl, types, ProcessThreads } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const type = ctx.req.param('type') ?? 'hot';
|
||||
const order = ctx.req.param('order') ?? '';
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
|
||||
|
||||
const apiUrl = `${apiRootUrl}/api/threads?type=${type}&includes=tags,forum_name,summary&ps=${limit}&pg=1&order=${order === '' ? '' : 'time_desc'}&is_groupid=1`;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `一亩三分地 - ${types[type]}`,
|
||||
link: rootUrl,
|
||||
item: await ProcessThreads(cache.tryGet, apiUrl, order),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
// @ts-nocheck
|
||||
import cache from '@/utils/cache';
|
||||
const { rootUrl, apiRootUrl, types, ProcessThreads } = require('./utils');
|
||||
|
||||
export default async (ctx) => {
|
||||
const type = ctx.req.param('type') ?? 'hot';
|
||||
const order = ctx.req.param('order') ?? '';
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
|
||||
|
||||
const apiUrl = `${apiRootUrl}/api/threads?type=${type}&includes=tags,forum_name,summary&ps=${limit}&pg=1&order=${order === '' ? '' : 'time_desc'}&is_groupid=1`;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `一亩三分地 - ${types[type]}`,
|
||||
link: rootUrl,
|
||||
item: await ProcessThreads(cache.tryGet, apiUrl, order),
|
||||
});
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const { posts } = (await got.get(`https://instant.1point3acres.com/v2/api/user/post?pg=1&ps=10&user_id=${id}`)).data;
|
||||
const [{ author_name: author }] = posts;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${author}的回复 - 一亩三分地`,
|
||||
link: `https://instant.1point3acres.com/profile/${id}`,
|
||||
description: `${author}的回复 - 一亩三分地`,
|
||||
item: posts.map((item) => ({
|
||||
title: item.message,
|
||||
author,
|
||||
description: item.message,
|
||||
pubDate: new Date(item.create_time + ' GMT+8').toUTCString(),
|
||||
link: `https://instant.1point3acres.com/thread/${item.thread_id}/post/${item.id}`,
|
||||
})),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import got from '@/utils/got';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const { posts } = (await got.get(`https://instant.1point3acres.com/v2/api/user/post?pg=1&ps=10&user_id=${id}`)).data;
|
||||
const [{ author_name: author }] = posts;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${author}的回复 - 一亩三分地`,
|
||||
link: `https://instant.1point3acres.com/profile/${id}`,
|
||||
description: `${author}的回复 - 一亩三分地`,
|
||||
item: posts.map((item) => ({
|
||||
title: item.message,
|
||||
author,
|
||||
description: item.message,
|
||||
pubDate: new Date(item.create_time + ' GMT+8').toUTCString(),
|
||||
link: `https://instant.1point3acres.com/thread/${item.thread_id}/post/${item.id}`,
|
||||
})),
|
||||
});
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import got from '@/utils/got';
|
||||
|
||||
export default async (ctx) => {
|
||||
const id = ctx.req.param('id');
|
||||
|
||||
const { threads } = (await got.get(`https://instant.1point3acres.com/v2/api/user/thread?pg=1&ps=10&user_id=${id}`)).data;
|
||||
const [{ author_name: author }] = threads;
|
||||
|
||||
ctx.set('data', {
|
||||
title: `${author}的主题帖 - 一亩三分地`,
|
||||
link: `https://instant.1point3acres.com/profile/${id}`,
|
||||
description: `${author}的主题帖 - 一亩三分地`,
|
||||
item: threads.map((item) => ({
|
||||
title: item.title,
|
||||
author,
|
||||
description: item.description,
|
||||
pubDate: new Date(item.update_time + ' GMT+8').toUTCString(),
|
||||
link: `https://instant.1point3acres.com/thread/${item.id}`,
|
||||
})),
|
||||
});
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user