🦄 refactor: Refactoring using hono

This commit is contained in:
imsyy
2024-04-08 16:35:58 +08:00
parent 7459858767
commit 34ab73a3f1
95 changed files with 3555 additions and 6345 deletions

74
src/routes/36kr.ts Normal file
View File

@@ -0,0 +1,74 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { post } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "hot";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "36kr",
title: "36氪",
type: "热榜",
parameData: {
type: {
name: "热榜分类",
type: {
hot: "人气榜",
video: "视频榜",
comment: "热议榜",
collect: "收藏榜",
},
},
},
link: "https://m.36kr.com/hot-list-m",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://gateway.36kr.com/api/mis/nav/home/nav/rank/${type}`;
const result = await post({
url,
noCache,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: {
partner_id: "wap",
param: {
siteId: 1,
platformId: 2,
},
timestamp: new Date().getTime(),
},
});
const listType = {
hot: "hotRankList",
video: "videoList",
comment: "remarkList",
collect: "collectList",
};
const list =
result.data.data[(listType as Record<string, keyof typeof result.data.data>)[type || "hot"]];
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["36kr"]) => {
const item = v.templateMaterial;
return {
id: v.itemId,
title: item.widgetTitle,
cover: item.widgetImage,
author: item.authorName,
hot: item.statCollect,
url: `https://www.36kr.com/p/${v.itemId}`,
mobileUrl: `https://m.36kr.com/p/${v.itemId}`,
};
}),
};
};

75
src/routes/acfun.ts Normal file
View File

@@ -0,0 +1,75 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "-1";
const range = c.req.query("range") || "DAY";
const { fromCache, data, updateTime } = await getList({ type, range }, noCache);
const routeData: RouterData = {
name: "acfun",
title: "AcFun",
type: "排行榜",
description: "AcFun是一家弹幕视频网站致力于为每一个人带来欢乐。",
parameData: {
type: {
name: "频道",
type: {
"-1": "全站综合",
"155": "番剧",
"1": "动画",
"60": "娱乐",
"201": "生活",
"58": "音乐",
"123": "舞蹈·偶像",
"59": "游戏",
"70": "科技",
"68": "影视",
"69": "体育",
"125": "鱼塘",
},
},
range: {
name: "时间",
type: {
DAY: "今日",
THREE_DAYS: "三日",
WEEK: "本周",
},
},
},
link: "https://www.acfun.cn/rank/list/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type, range } = options;
const url = `https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=${type === "-1" ? "" : type}&rankLimit=30&rankPeriod=${range}`;
const result = await get({
url,
headers: {
Referer: `https://www.acfun.cn/rank/list/?cid=-1&pcid=${type}&range=${range}`,
},
noCache,
});
const list = result.data.rankList;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["acfun"]) => ({
id: v.dougaId,
title: v.contentTitle,
desc: v.contentDesc,
cover: v.coverUrl,
author: v.userName,
hot: v.likeCount,
url: `https://www.acfun.cn/v/ac${v.dougaId}`,
mobileUrl: `https://m.acfun.cn/v/?ac=${v.dougaId}`,
})),
};
};

63
src/routes/baidu.ts Normal file
View File

@@ -0,0 +1,63 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "realtime";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "baidu",
title: "百度",
type: "热搜榜",
parameData: {
type: {
name: "热搜类别",
type: {
realtime: "热搜",
novel: "小说",
movie: "电影",
teleplay: "电视剧",
car: "汽车",
game: "游戏",
},
},
},
link: "https://top.baidu.com/board",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://top.baidu.com/board?tab=${type}`;
const result = await get({
url,
noCache,
headers: {
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 14_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/605.1.15",
},
});
// 正则查找
const pattern = /<!--s-data:(.*?)-->/s;
const matchResult = result.data.match(pattern);
const jsonObject = JSON.parse(matchResult[1]).cards[0].content;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: jsonObject.map((v: RouterType["baidu"]) => ({
id: v.index,
title: v.word,
desc: v.desc,
cover: v.img,
author: v.show?.length ? v.show : "",
hot: Number(v.hotScore),
url: `https://www.baidu.com/s?wd=${encodeURIComponent(v.query)}`,
mobileUrl: v.rawUrl,
})),
};
};

67
src/routes/bilibili.ts Normal file
View File

@@ -0,0 +1,67 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "0";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "bilibili",
title: "哔哩哔哩",
type: "热门榜",
description: "你所热爱的,就是你的生活",
parameData: {
type: {
name: "排行榜分区",
type: {
0: "全站",
1: "动画",
3: "音乐",
4: "游戏",
5: "娱乐",
36: "科技",
119: "鬼畜",
129: "舞蹈",
155: "时尚",
160: "生活",
168: "国创相关",
188: "数码",
181: "影视",
},
},
},
link: "https://www.bilibili.com/v/popular/rank/all",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://api.bilibili.com/x/web-interface/ranking/v2?rid=${type}`;
const result = await get({
url,
headers: {
Referer: `https://www.bilibili.com/ranking/all`,
},
noCache,
});
const list = result.data.data.list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["bilibili"]) => ({
id: v.bvid,
title: v.title,
desc: v.desc,
cover: v.pic.replace(/http:/, "https:"),
author: v.owner.name,
hot: v.stat.view,
url: v.short_link_v2 || `https://www.bilibili.com/video/${v.bvid}`,
mobileUrl: `https://m.bilibili.com/video/${v.bvid}`,
})),
};
};

View File

@@ -0,0 +1,54 @@
import type { RouterData } from "../types.js";
import { load } from "cheerio";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "douban-group",
title: "豆瓣讨论",
type: "讨论精选",
link: "https://www.douban.com/group/explore",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
// 数据处理
const getNumbers = (text: string | undefined) => {
if (!text) return 100000000;
const regex = /\d+/;
const match = text.match(regex);
if (match) {
return Number(match[0]);
} else {
return 100000000;
}
};
const getList = async (noCache: boolean) => {
const url = `https://www.douban.com/group/explore`;
const result = await get({ url, noCache });
const $ = load(result.data);
const listDom = $(".article .channel-item");
const listData = listDom.toArray().map((item) => {
const dom = $(item);
const url = dom.find("h3 a").attr("href") || undefined;
return {
id: getNumbers(url),
title: dom.find("h3 a").text().trim(),
cover: dom.find(".pic-wrap img").attr("src"),
desc: dom.find(".block p").text().trim(),
url,
mobileUrl: `https://m.douban.com/group/topic/${getNumbers(url)}/`,
};
});
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: listData,
};
};

View File

@@ -0,0 +1,63 @@
import type { RouterData } from "../types.js";
import { load } from "cheerio";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "douban-movie",
title: "豆瓣电影",
type: "新片排行榜",
link: "https://movie.douban.com/chart",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
// 数据处理
const getNumbers = (text: string | undefined) => {
if (!text) return 10000000;
const regex = /\d+/;
const match = text.match(regex);
if (match) {
return Number(match[0]);
} else {
return 10000000;
}
};
const getList = async (noCache: boolean) => {
const url = `https://movie.douban.com/chart/`;
const result = await get({
url,
noCache,
headers: {
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
},
});
const $ = load(result.data);
const listDom = $(".article tr.item");
const listData = listDom.toArray().map((item) => {
const dom = $(item);
const url = dom.find("a").attr("href") || undefined;
const score = dom.find(".rating_nums").text() ?? "0.0";
return {
id: getNumbers(url),
title: `${score}${dom.find("a").attr("title")}`,
cover: dom.find("img").attr("src"),
desc: dom.find("p.pl").text(),
hot: getNumbers(dom.find("span.pl").text()),
url,
mobileUrl:`https://m.douban.com/movie/subject/${getNumbers(url)}/`,
};
});
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: listData,
};
};

59
src/routes/douyin.ts Normal file
View File

@@ -0,0 +1,59 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "douyin",
title: "抖音",
type: "热榜",
description: "实时上升热点",
link: "https://www.douyin.com",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
// 获取抖音临时 Cookis
const getDyCookies = async () => {
try {
const cookisUrl = "https://www.douyin.com/passport/general/login_guiding_strategy/?aid=6383";
const { data } = await get({ url: cookisUrl, originaInfo: true });
const pattern = /passport_csrf_token=(.*); Path/s;
const matchResult = data.headers["set-cookie"][0].match(pattern);
const cookieData = matchResult[1];
return cookieData;
} catch (error) {
console.error("获取抖音 Cookie 出错" + error);
return null;
}
};
const getList = async (noCache: boolean) => {
const url =
"https://www.douyin.com/aweme/v1/web/hot/search/list/?device_platform=webapp&aid=6383&channel=channel_pc_web&detail_list=1";
const cookie = await getDyCookies();
const result = await get({
url,
noCache,
headers: {
Cookie: `passport_csrf_token=${cookie}`,
},
});
const list = result.data.data.word_list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["douyin"]) => ({
id: v.sentence_id,
title: v.word,
hot: v.hot_value,
url: `https://www.douyin.com/hot/${encodeURIComponent(v.sentence_id)}`,
mobileUrl: `https://www.douyin.com/hot/${encodeURIComponent(v.sentence_id)}`,
})),
};
};

53
src/routes/genshin.ts Normal file
View File

@@ -0,0 +1,53 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "1";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "genshin",
title: "原神",
type: "最新动态",
parameData: {
type: {
name: "榜单分类",
type: {
1: "公告",
2: "活动",
3: "资讯",
},
},
},
link: "https://www.miyoushe.com/ys/home/28",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://bbs-api.miyoushe.com/post/wapi/getNewsList?gids=2&page_size=20&type=${type}`;
const result = await get({ url, noCache });
const list = result.data.data.list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["miyoushe"]) => {
const data = v.post;
return {
id: data.post_id,
title: data.subject,
desc: data.content,
cover: data.cover,
author: v.user.nickname,
hot: v.stat.view_num,
url: `https://www.miyoushe.com/ys/article/${data.post_id}`,
mobileUrl: `https://m.miyoushe.com/ys/#/article/${data.post_id}`,
};
}),
};
};

49
src/routes/hellogithub.ts Normal file
View File

@@ -0,0 +1,49 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const sort = c.req.query("sort") || "hot";
const { fromCache, data, updateTime } = await getList({ sort }, noCache);
const routeData: RouterData = {
name: "hellogithub",
title: "HelloGitHub",
type: "热门仓库",
description: "分享 GitHub 上有趣、入门级的开源项目",
parameData: {
sort: {
name: "排行榜分区",
type: {
hot: "热门",
last: "最新",
},
},
},
link: "https://hellogithub.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { sort } = options;
const url = `https://abroad.hellogithub.com/v1/?sort_by=${sort}&tid=&page=1`;
const result = await get({ url, noCache });
const list = result.data.data;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["hellogithub"]) => ({
id: v.item_id,
title: v.title,
desc: v.summary,
author: v.author,
hot: v.clicks_total,
url: `https://hellogithub.com/repository/${v.item_id}`,
mobileUrl: `https://hellogithub.com/repository/${v.item_id}`,
})),
};
};

53
src/routes/honkai.ts Normal file
View File

@@ -0,0 +1,53 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "1";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "honkai",
title: "崩坏3",
type: "最新动态",
parameData: {
type: {
name: "榜单分类",
type: {
1: "公告",
2: "活动",
3: "资讯",
},
},
},
link: "https://www.miyoushe.com/bh3/home/6",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://bbs-api.miyoushe.com/post/wapi/getNewsList?gids=1&page_size=20&type=${type}`;
const result = await get({ url, noCache });
const list = result.data.data.list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["miyoushe"]) => {
const data = v.post;
return {
id: data.post_id,
title: data.subject,
desc: data.content,
cover: data.cover || v.image_list[0].url,
author: v.user.nickname,
hot: v.stat.view_num,
url: `https://www.miyoushe.com/bh3/article/${data.post_id}`,
mobileUrl: `https://m.miyoushe.com/bh3/#/article/${data.post_id}`,
};
}),
};
};

56
src/routes/ithome.ts Normal file
View File

@@ -0,0 +1,56 @@
import type { RouterData } from "../types.js";
import { load } from "cheerio";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "ithome",
title: "IT之家",
type: "热榜",
description: "爱科技,爱这里 - 前沿科技新闻网站",
link: "https://m.ithome.com/rankm/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
// 链接处理
const replaceLink = (url: string, getId: boolean = false) => {
const match = url.match(/[html|live]\/(\d+)\.htm/);
// 是否匹配成功
if (match && match[1]) {
return getId
? match[1]
: `https://www.ithome.com/0/${match[1].slice(0, 3)}/${match[1].slice(3)}.htm`;
}
// 返回原始 URL
return url;
};
const getList = async (noCache: boolean) => {
const url = `https://m.ithome.com/rankm/`;
const result = await get({ url, noCache });
const $ = load(result.data);
const listDom = $(".rank-box .placeholder");
const listData = listDom.toArray().map((item) => {
const dom = $(item);
const href = dom.find("a").attr("href");
return {
id: href ? Number(replaceLink(href, true)) : 100000,
title: dom.find(".plc-title").text().trim(),
cover: dom.find("img").attr("data-original"),
hot: Number(dom.find(".review-num").text().replace(/\D/g, "")),
url: href ? replaceLink(href) : undefined,
mobileUrl: href || undefined,
};
});
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: listData,
};
};

57
src/routes/jianshu.ts Normal file
View File

@@ -0,0 +1,57 @@
import type { RouterData } from "../types.js";
import { load } from "cheerio";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "jianshu",
title: "简书",
type: "热门推荐",
description: "一个优质的创作社区",
link: "https://www.jianshu.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
// 获取 ID
const getID = (url: string) => {
if (!url) return "undefined";
const match = url.match(/([^/]+)$/);
return match ? match[1] : "undefined";
};
const getList = async (noCache: boolean) => {
const url = `https://www.jianshu.com/`;
const result = await get({
url,
noCache,
headers: {
Referer: "https://www.jianshu.com",
},
});
const $ = load(result.data);
const listDom = $("ul.note-list li");
const listData = listDom.toArray().map((item) => {
const dom = $(item);
const href = dom.find("a").attr("href") || "";
return {
id: getID(href),
title: dom.find("a.title").text()?.trim(),
cover: dom.find("img").attr("src"),
desc: dom.find("p.abstract").text()?.trim(),
author: dom.find("a.nickname").text()?.trim(),
url: `https://www.jianshu.com${href}`,
mobileUrl: `https://www.jianshu.com${href}`,
};
});
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: listData,
};
};

36
src/routes/juejin.ts Normal file
View File

@@ -0,0 +1,36 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "juejin",
title: "稀土掘金",
type: "文章榜",
link: "https://juejin.cn/hot/articles",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://api.juejin.cn/content_api/v1/content/article_rank?category_id=1&type=hot`;
const result = await get({ url, noCache });
const list = result.data.data;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["juejin"]) => ({
id: v.content.content_id,
title: v.content.title,
author: v.author.name,
hot: v.content_counter.hot_rank,
url: `https://juejin.cn/post/${v.content.content_id}`,
mobileUrl: `https://juejin.cn/post/${v.content.content_id}`,
})),
};
};

38
src/routes/lol.ts Normal file
View File

@@ -0,0 +1,38 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "lol",
title: "英雄联盟",
type: "更新公告",
link: "https://lol.qq.com/gicp/news/423/2/1334/1.html",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url =
"https://apps.game.qq.com/cmc/zmMcnTargetContentList?r0=json&page=1&num=30&target=24&source=web_pc";
const result = await get({ url, noCache });
const list = result.data.data.result;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["lol"]) => ({
id: v.iDocID,
title: v.sTitle,
cover: `https:${v.sIMG}`,
author: v.sAuthor,
hot: Number(v.iTotalPlay),
url: `https://lol.qq.com/news/detail.shtml?docid=${encodeURIComponent(v.iDocID)}`,
mobileUrl: `https://lol.qq.com/news/detail.shtml?docid=${encodeURIComponent(v.iDocID)}`,
})),
};
};

View File

@@ -0,0 +1,36 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "netease-news",
title: "网易新闻",
type: "热点榜",
link: "https://m.163.com/hot",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://m.163.com/fe/api/hot/news/flow`;
const result = await get({ url, noCache });
const list = result.data.data.list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["netease-news"]) => ({
id: v.docid,
title: v.title,
cover: v.imgsrc,
author: v.source,
url: `https://www.163.com/dy/article/${v.docid}.html`,
mobileUrl: `https://m.163.com/dy/article/${v.docid}.html`,
})),
};
};

55
src/routes/ngabbs.ts Normal file
View File

@@ -0,0 +1,55 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { post } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "ngabbs",
title: "NGA",
type: "论坛热帖",
description: "精英玩家俱乐部",
link: "https://ngabbs.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://ngabbs.com/nuke.php?__lib=load_topic&__act=load_topic_reply_ladder2&opt=1&all=1`;
const result = await post({
url,
noCache,
headers: {
Accept: "*/*",
Host: "ngabbs.com",
Referer: "https://ngabbs.com/",
Connection: "keep-alive",
"Content-Length": "11",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-Hans-CN;q=1",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Apifox/1.0.0 (https://apifox.com)",
"X-User-Agent": "NGA_skull/7.3.1(iPhone13,2;iOS 17.2.1)",
},
body: {
__output: "14",
},
});
const list = result.data.result[0];
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["ngabbs"]) => ({
id: v.tid,
title: v.subject,
author: v.author,
hot: v.replies,
url: `https://bbs.nga.cn${v.tpcurl}`,
mobileUrl: `https://bbs.nga.cn${v.tpcurl}`,
})),
};
};

37
src/routes/qq-news.ts Normal file
View File

@@ -0,0 +1,37 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "qq-news",
title: "腾讯新闻",
type: "热点榜",
link: "https://news.qq.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://r.inews.qq.com/gw/event/hot_ranking_list?page_size=50`;
const result = await get({ url, noCache });const list = result.data.idlist[0].newslist.slice(1);
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["qq-news"]) => ({
id: v.id,
title: v.title,
desc: v.abstract,
cover: v.miniProShareImage,
author: v.source,
hot: v.hotEvent.hotScore,
url: `https://new.qq.com/rain/a/${v.id}`,
mobileUrl: `https://view.inews.qq.com/k/${v.id}`,
})),
};
};

46
src/routes/sspai.ts Normal file
View File

@@ -0,0 +1,46 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "热门文章";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "sspai",
title: "少数派",
type: "热榜",
parameData: {
type: {
name: "分类",
type: ["热门文章", "应用推荐", "生活方式", "效率技巧", "少数派播客"],
},
},
link: "https://sspai.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://sspai.com/api/v1/article/tag/page/get?limit=40&tag=${type}`;
const result = await get({ url, noCache });
const list = result.data.data;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["sspai"]) => ({
id: v.id,
title: v.title,
desc: v.summary,
cover: v.banner,
author: v.author.nickname,
hot: v.like_count,
url: `https://sspai.com/post/${v.id}`,
mobileUrl: `https://sspai.com/post/${v.id}`,
})),
};
};

53
src/routes/starrail.ts Normal file
View File

@@ -0,0 +1,53 @@
import type { RouterData, ListContext, Options } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (c: ListContext, noCache: boolean) => {
const type = c.req.query("type") || "1";
const { fromCache, data, updateTime } = await getList({ type }, noCache);
const routeData: RouterData = {
name: "starrail",
title: "崩坏:星穹铁道",
type: "最新动态",
parameData: {
type: {
name: "榜单分类",
type: {
1: "公告",
2: "活动",
3: "资讯",
},
},
},
link: "https://www.miyoushe.com/sr/home/53",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (options: Options, noCache: boolean) => {
const { type } = options;
const url = `https://bbs-api.miyoushe.com/post/wapi/getNewsList?gids=6&page_size=20&type=${type}`;
const result = await get({ url, noCache });
const list = result.data.data.list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["miyoushe"]) => {
const data = v.post;
return {
id: data.post_id,
title: data.subject,
desc: data.content,
cover: data.cover,
author: v.user.nickname,
hot: v.stat.view_num,
url: `https://www.miyoushe.com/sr/article/${data.post_id}`,
mobileUrl: `https://m.miyoushe.com/sr/#/article/${data.post_id}`,
};
}),
};
};

36
src/routes/thepaper.ts Normal file
View File

@@ -0,0 +1,36 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "thepaper",
title: "澎湃新闻",
type: "热榜",
link: "https://www.thepaper.cn/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://cache.thepaper.cn/contentapi/wwwIndex/rightSidebar`;
const result = await get({ url, noCache });
const list = result.data.data.hotNews;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["thepaper"]) => ({
id: v.contId,
title: v.name,
cover: v.pic,
hot: Number(v.praiseTimes),
url: `https://www.thepaper.cn/newsDetail_forward_${v.contId}`,
mobileUrl: `https://m.thepaper.cn/newsDetail_forward_${v.contId}`,
})),
};
};

38
src/routes/tieba.ts Normal file
View File

@@ -0,0 +1,38 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "tieba",
title: "百度贴吧",
type: "热议榜",
description: "全球领先的中文社区",
link: "https://tieba.baidu.com/hottopic/browse/topicList",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://tieba.baidu.com/hottopic/browse/topicList`;
const result = await get({ url, noCache });
const list = result.data.data.bang_topic.topic_list;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["tieba"]) => ({
id: v.topic_id,
title: v.topic_name,
desc: v.topic_desc,
cover: v.topic_pic,
hot: v.discuss_num,
url: v.topic_url,
mobileUrl: v.topic_url,
})),
};
};

36
src/routes/toutiao.ts Normal file
View File

@@ -0,0 +1,36 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "toutiao",
title: "今日头条",
type: "热榜",
link: "https://www.toutiao.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc`;
const result = await get({ url, noCache });
const list = result.data.data;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["toutiao"]) => ({
id: v.ClusterIdStr,
title: v.Title,
cover: v.Image.url,
hot: Number(v.HotValue),
url: `https://www.toutiao.com/trending/${v.ClusterIdStr}/`,
mobileUrl: `https://api.toutiaoapi.com/feoffline/amos_land/new/html/main/index.html?topic_id=${v.ClusterIdStr}`,
})),
};
};

43
src/routes/weibo.ts Normal file
View File

@@ -0,0 +1,43 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "weibo",
title: "微博",
type: "热搜榜",
description: "实时热点,每分钟更新一次",
link: "https://s.weibo.com/top/summary/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://weibo.com/ajax/side/hotSearch`;
const result = await get({ url, noCache, ttl: 60 });
const list = result.data.data.realtime;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["weibo"]) => {
const key = v.word_scheme ? v.word_scheme : `#${v.word}`;
return {
id: v.mid,
title: v.word,
desc: v.note || key,
author: v.category,
hot: v.raw_hot,
url: `https://s.weibo.com/weibo?q=${encodeURIComponent(key)}&t=31&band_rank=1&Refer=top`,
mobileUrl: `https://s.weibo.com/weibo?q=${encodeURIComponent(
key,
)}&t=31&band_rank=1&Refer=top`,
};
}),
};
};

49
src/routes/weread.ts Normal file
View File

@@ -0,0 +1,49 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
import getWereadID from "../utils/getWereadID.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "weread",
title: "微信读书",
type: "飙升榜",
link: "https://weread.qq.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://weread.qq.com/web/bookListInCategory/rising?rank=1`;
const result = await get({
url,
noCache,
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67",
},
});
const list = result.data.books;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["weread"]) => {
const data = v.bookInfo;
return {
id: data.bookId,
title: data.title,
author: data.author,
desc: data.intro,
cover: data.cover.replace("s_", "t9_"),
hot: v.readingCount,
url: `https://weread.qq.com/web/bookDetail/${getWereadID(data.bookId)}`,
mobileUrl: `https://weread.qq.com/web/bookDetail/${getWereadID(data.bookId)}`,
};
}),
};
};

44
src/routes/zhihu-daily.ts Normal file
View File

@@ -0,0 +1,44 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "zhihu-daily",
title: "知乎日报",
type: "推荐榜",
description: "每天三次,每次七分钟",
link: "https://daily.zhihu.com/",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://news-at.zhihu.com/api/4/news/latest`;
const result = await get({
url,
noCache,
headers: {
Referer: "https://news-at.zhihu.com/api/4/news/latest",
Host: "news-at.zhihu.com",
},
});
const list = result.data.stories.filter((el: RouterType["zhihu-daily"]) => el.type === 0);
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["zhihu-daily"]) => ({
id: v.id,
title: v.title,
cover: v.images[0],
author: v.hint,
url: v.url,
mobileUrl: v.url,
})),
};
};

40
src/routes/zhihu.ts Normal file
View File

@@ -0,0 +1,40 @@
import type { RouterData } from "../types.js";
import type { RouterType } from "../router.types.js";
import { get } from "../utils/getData.js";
export const handleRoute = async (_: undefined, noCache: boolean) => {
const { fromCache, data, updateTime } = await getList(noCache);
const routeData: RouterData = {
name: "zhihu",
title: "知乎",
type: "热榜",
link: "https://www.zhihu.com/hot",
total: data?.length || 0,
updateTime,
fromCache,
data,
};
return routeData;
};
const getList = async (noCache: boolean) => {
const url = `https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=50&desktop=true`;
const result = await get({ url, noCache });
const list = result.data.data;
return {
fromCache: result.fromCache,
updateTime: result.updateTime,
data: list.map((v: RouterType["zhihu"]) => {
const data = v.target;
return {
id: data.id,
title: data.title,
desc: data.excerpt,
cover: v.children[0].thumbnail,
hot: parseInt(v.detail_text.replace(/[^\d]/g, "")) * 10000,
url: `https://www.zhihu.com/question/${data.id}`,
mobileUrl: `https://www.zhihu.com/question/${data.id}`,
};
}),
};
};