From 2b91f3f32b24bc537dd01039e6d908603dd30a91 Mon Sep 17 00:00:00 2001 From: imsyy Date: Tue, 2 Jan 2024 11:20:50 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=96=B0=E5=A2=9E=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 97 ++++++++---- package.json | 4 +- routes/douban_group.js | 58 ++++--- routes/douban_new.js | 2 +- routes/douyin_music.js | 2 +- routes/ithome.js | 2 +- routes/netease_music.js | 169 -------------------- routes/netease_music_toplist.js | 198 ++++++++++++++++++++++++ routes/ngabbs.js | 230 ++++++++++++++-------------- routes/qq_music.js | 170 --------------------- routes/qq_music_toplist.js | 211 +++++++++++++++++++++++++ routes/v2ex.js | 263 ++++++++++++++++---------------- 12 files changed, 754 insertions(+), 652 deletions(-) delete mode 100644 routes/netease_music.js create mode 100644 routes/netease_music_toplist.js delete mode 100644 routes/qq_music.js create mode 100644 routes/qq_music_toplist.js diff --git a/README.md b/README.md index b520689..c6794b2 100644 --- a/README.md +++ b/README.md @@ -16,33 +16,70 @@ > 🟠 可能失效 > ❌ 无法使用 -| **站点** | **类别** | **调用名称** | **状态** | -| ------------ | -------- | ------------------- | -------- | -| 哔哩哔哩 | 热门榜 | bilibili | 🟢 | -| 微博 | 热搜榜 | weibo | 🟢 | -| 知乎 | 热榜 | zhihu | 🟢 | -| 百度 | 热搜榜 | baidu | 🟢 | -| 抖音 | 热点榜 | douyin / douyin_new | 🟢 | -| 抖音 | 热歌榜 | douyin_music | 🟢 | -| 豆瓣 | 新片榜 | douban_new | 🟢 | -| 百度贴吧 | 热议榜 | tieba | 🟢 | -| 少数派 | 热榜 | sspai | 🟢 | -| IT 之家 | 热榜 | ithome | 🟠 | -| 澎湃新闻 | 热榜 | thepaper | 🟢 | -| 今日头条 | 热榜 | toutiao | 🟢 | -| 36 氪 | 热榜 | 36kr | 🟢 | -| 稀土掘金 | 热榜 | juejin | 🟢 | -| 腾讯新闻 | 热点榜 | newsqq | 🟢 | -| 网易新闻 | 热点榜 | netease | 🟢 | -| 英雄联盟 | 更新公告 | lol | 🟢 | -| 原神 | 最新消息 | genshin | 🟢 | -| 微信读书 | 飙升榜 | weread | 🟢 | -| 快手 | 热榜 | kuaishou | 🟢 | -| Github | Trending | github | 🟢 | -| 历史上的今天 | 指定日期 | calendar | 🟢 | +| **站点** | **类别** | **调用名称** | **状态** | +| ------------ | -------- | --------------------- | -------- | +| 哔哩哔哩 | 热门榜 | bilibili | 🟢 | +| 微博 | 热搜榜 | weibo | 🟢 | +| 知乎 | 热榜 | zhihu | 🟢 | +| 百度 | 热搜榜 | baidu | 🟢 | +| 抖音 | 热点榜 | douyin / douyin_new | 🟢 | +| 抖音 | 热歌榜 | douyin_music | 🟢 | +| 豆瓣 | 新片榜 | douban_new | 🟢 | +| 豆瓣讨论小组 | 讨论精选 | douban_group | 🟢 | +| 百度贴吧 | 热议榜 | tieba | 🟢 | +| 少数派 | 热榜 | sspai | 🟢 | +| IT 之家 | 热榜 | ithome | 🟠 | +| 澎湃新闻 | 热榜 | thepaper | 🟢 | +| 今日头条 | 热榜 | toutiao | 🟢 | +| 36 氪 | 热榜 | 36kr | 🟢 | +| 稀土掘金 | 热榜 | juejin | 🟢 | +| 腾讯新闻 | 热点榜 | newsqq | 🟢 | +| 网易新闻 | 热点榜 | netease | 🟢 | +| 英雄联盟 | 更新公告 | lol | 🟢 | +| 原神 | 最新消息 | genshin | 🟢 | +| 微信读书 | 飙升榜 | weread | 🟢 | +| 快手 | 热榜 | kuaishou | 🟢 | +| 网易云音乐 | 排行榜 | netease_music_toplist | 🟢 | +| QQ音乐 | 排行榜 | qq_music_toplist | 🟢 | +| NGA | 热帖 | ngabbs | 🟢 | +| Github | Trending | github | 🟢 | +| V2EX | 热榜 | v2ex | 🟠 | +| 历史上的今天 | 指定日期 | calendar | 🟢 | ### 特殊接口说明 +#### 网易云音乐 + +调用网易云音乐排行榜需要传入指定榜单类别 + +| 参数名 | 参数值 | 说明 | +| ------ | ------ | ------ | +| type | 1 | 飙升榜 | +| type | 2 | 新歌榜 | +| type | 3 | 原创榜 | +| type | 4 | 热歌榜 | + +```http +GET https://example.com/netease_music_toplist?type=1 +``` + +#### QQ音乐 + +调用QQ音乐排行榜需要传入指定榜单类别 + +| 参数名 | 参数值 | 说明 | +| ------ | ------ | ---------------- | +| type | 1 | 飙升榜 | +| type | 2 | 热歌榜 | +| type | 3 | 新歌榜 | +| type | 4 | 流行指数榜 | +| type | 5 | 腾讯音乐人原创榜 | +| type | 6 | 听歌识曲榜 | + +```http +GET https://example.com/qq_music_toplist?type=1 +``` + #### 获取全部接口信息 获取除了下方特殊接口外的全部接口列表 @@ -62,10 +99,10 @@ GET https://example.com/calendar/date?month=06&day=01 ## 部署 ```bash -// 安装依赖 +# 安装依赖 pnpm install -// 运行 +# 运行 pnpm start ``` @@ -76,18 +113,18 @@ pnpm start ### 本地构建 ```bash -// 构建 +# 构建 docker build -t dailyhot-api . -// 运行 +# 运行 docker run -p 6688:6688 -d dailyhot-api ``` ### 在线部署 ```bash -// 拉取 +# 拉取 docker pull imsyy/dailyhot-api:1.0.5 -// 运行 +# 运行 docker run -p 6688:6688 -d imsyy/dailyhot-api:1.0.5 ``` diff --git a/package.json b/package.json index 3da3f5c..bd06e56 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "dailyhot_api", - "version": "1.0.5", - "description": "一个今日热榜", + "version": "1.0.7", + "description": "An api on Today's Hot list", "main": "index.js", "scripts": { "format": "prettier --write .", diff --git a/routes/douban_group.js b/routes/douban_group.js index 75c8d75..f084162 100644 --- a/routes/douban_group.js +++ b/routes/douban_group.js @@ -1,10 +1,10 @@ /** - * @author: x-dr - * @date: 2023年12月26日 - * @tags: [豆瓣讨论精选] + * @author: x-dr + * @date: 2023-12-26 + * @customEditors: imsyy + * @lastEditTime: 2024-01-02 */ - const Router = require("koa-router"); const doubanGroupNewRouter = new Router(); const axios = require("axios"); @@ -13,13 +13,11 @@ const { get, set, del } = require("../utils/cacheData"); // 接口信息 const routerInfo = { - name: "doubangroup", + name: "douban_group", title: "豆瓣讨论小组", subtitle: "精选", }; - - // 缓存键名 const cacheKey = "doubanGroupData"; @@ -29,12 +27,13 @@ let updateTime = new Date().toISOString(); const url = "https://www.douban.com/group/explore"; const headers = { - "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + accept: + "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8", "cache-control": "max-age=0", - "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", + "sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', "sec-ch-ua-mobile": "?0", - "sec-ch-ua-platform": "\"Windows\"", + "sec-ch-ua-platform": '"Windows"', "sec-fetch-dest": "document", "sec-fetch-mode": "navigate", "sec-fetch-site": "none", @@ -43,27 +42,31 @@ const headers = { // "cookie": "bid=lLpb6D1JLuw; douban-fav-remind=1; _pk_id.100001.8cb4=e7d91ae46530fd1d.1680518589.; ll=\"118281\"; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1703602972%2C%22http%3A%2F%2Fnew.xianbao.fun%2F%22%5D; _pk_ses.100001.8cb4=1; ap_v=0,6.0" }; - - // 数据处理 const getData = (data) => { if (!data) return false; const dataList = []; const $ = cheerio.load(data); try { - $(`.channel-item`).each((i, e) => { // console.log($(e).html()); - const item= cheerio.load($(e).html()) - const title = item("h3").text().replace(/(^\s*)|(\s*$)/g, "") - const url = item("h3 a").attr('href') - const hot= item('div[class="likes"]').text().replace(/(^\s*)|(\s*$)/g, "") - const desc = item('div[class="block"]').text().replace(/(^\s*)|(\s*$|\n)/g, "") - const source = item('div[class="source"] a').text().replace(/(^\s*)|(\s*$)/g, "") + const item = cheerio.load($(e).html()); + const title = item("h3") + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const url = item("h3 a").attr("href"); + const hot = item('div[class="likes"]') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const desc = item('div[class="block"]') + .text() + .replace(/(^\s*)|(\s*$|\n)/g, ""); + const source = item('div[class="source"] a') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); // const excerpt = item('.channel-item-desc').text().replace(/(^\s*)|(\s*$)/g, "") // console.log(title); // console.log(url); - dataList.push({ title: title, desc: desc, @@ -71,9 +74,7 @@ const getData = (data) => { mobileUrl: url, hot: hot, source: source, - - }); - + }); }); return dataList; } catch (error) { @@ -82,10 +83,8 @@ const getData = (data) => { } }; - - // trending -doubanGroupNewRouter.get("/doubangroup", async (ctx) => { +doubanGroupNewRouter.get("/douban_group", async (ctx) => { console.log("获取豆瓣讨论小组精选"); try { // 从缓存中获取数据 @@ -130,11 +129,8 @@ doubanGroupNewRouter.get("/doubangroup", async (ctx) => { } }); - - - // 豆瓣新片榜 - 获取最新数据 -doubanGroupNewRouter.get("/doubangroup/new", async (ctx) => { +doubanGroupNewRouter.get("/douban_group/new", async (ctx) => { console.log("获取豆瓣讨论小组精选 - 最新数据"); try { // 从服务器拉取最新数据 @@ -182,4 +178,4 @@ doubanGroupNewRouter.get("/doubangroup/new", async (ctx) => { }); doubanGroupNewRouter.info = routerInfo; -module.exports = doubanGroupNewRouter; \ No newline at end of file +module.exports = doubanGroupNewRouter; diff --git a/routes/douban_new.js b/routes/douban_new.js index 81e6039..356d85a 100644 --- a/routes/douban_new.js +++ b/routes/douban_new.js @@ -13,7 +13,7 @@ const { get, set, del } = require("../utils/cacheData"); // 接口信息 const routerInfo = { - name: "douban", + name: "douban_new", title: "豆瓣", subtitle: "新片榜", }; diff --git a/routes/douyin_music.js b/routes/douyin_music.js index fd4696d..c00844e 100644 --- a/routes/douyin_music.js +++ b/routes/douyin_music.js @@ -12,7 +12,7 @@ const { get, set, del } = require("../utils/cacheData"); // 接口信息 const routerInfo = { - name: "douyin", + name: "douyin_music", title: "抖音", subtitle: "热歌榜", }; diff --git a/routes/ithome.js b/routes/ithome.js index d1a0c81..04ee196 100644 --- a/routes/ithome.js +++ b/routes/ithome.js @@ -36,7 +36,7 @@ const getData = (data) => { const dataList = []; const $ = cheerio.load(data); try { - $(".rank-name").each(function () { + $(".rank-name").each(() => { const type = $(this).data("rank-type"); const newListHtml = $(this).next(".rank-box").html(); cheerio diff --git a/routes/netease_music.js b/routes/netease_music.js deleted file mode 100644 index f49dbcd..0000000 --- a/routes/netease_music.js +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @author: x-dr - * @date: 2023年12月27日 - * @tags: [网易云音乐飙升榜] - */ - - -const URL = require('url'); -const Router = require("koa-router"); -const neteaseMusicRouter = new Router(); -const axios = require("axios"); -const cheerio = require("cheerio"); -const { get, set, del } = require("../utils/cacheData"); - -// 接口信息 -const routerInfo = { - name: "neteasemusic", - title: "网易云音乐", - subtitle: "飙升榜", -}; - - -// 缓存键名 -const cacheKey = "neteasemusicData"; - -// 调用时间 -let updateTime = new Date().toISOString(); - -const url = "https://music.163.com/discover/toplist?id=19723756"; -// const url = "https://music.163.com/#/discover/toplist?id=19723756"; - -const headers = { - 'authority': 'music.163.com', - 'referer': 'https://music.163.com/', -}; - - - -// 数据处理 -const getData = (data) => { - if (!data) return false; - const dataList = []; - const $ = cheerio.load(data); - try { - $('.m-sgitem').each((i, e) => { - const urlString = $(e).attr('href') - const parsedUrl = URL.parse(urlString, true); - const urlidValue = parsedUrl.query.id; - const item = cheerio.load($(e).html()) - const author = item('div[class="f-thide sginfo"]').text().replace(/(^\s*)|(\s*$)/g, "") - const title = item('div[class="f-thide sgtl"]').text().replace(/(^\s*)|(\s*$)/g, "") - dataList.push({ - title: title, - desc: author, - url: `https://music.163.com/#/song?id=${urlidValue}`, - mobileUrl: `https://music.163.com/m/song?id=${urlidValue}`, - }); - - - - }); - return dataList; - } catch (error) { - console.error("数据处理出错" + error); - return false; - } -}; - - - -// -neteaseMusicRouter.get("/neteasemusic", async (ctx) => { - console.log("获取neteasemusic "); - try { - // 从缓存中获取数据 - let data = await get(cacheKey); - const from = data ? "cache" : "server"; - if (!data) { - // 如果缓存中不存在数据 - console.log("从服务端重新neteasemusic "); - // 从服务器拉取数据 - const response = await axios.get(url, { headers }); - // console.log(response.data); - data = getData(response.data); - - updateTime = new Date().toISOString(); - if (!data) { - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - return false; - } - // 将数据写入缓存 - await set(cacheKey, data); - } - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - from, - total: data.length, - updateTime, - data, - }; - } catch (error) { - console.error(error); - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - } -}); - - - - -// 豆瓣新片榜 - 获取最新数据 -neteaseMusicRouter.get("/neteasemusic/new", async (ctx) => { - console.log("获取neteasemusic - 最新数据"); - try { - // 从服务器拉取最新数据 - const response = await axios.get(url, { headers }); - const newData = getData(response.data); - updateTime = new Date().toISOString(); - console.log("从服务端重新neteasemusic "); - - // 返回最新数据 - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - updateTime, - total: newData.length, - data: newData, - }; - - // 删除旧数据 - await del(cacheKey); - // 将最新数据写入缓存 - await set(cacheKey, newData); - } catch (error) { - // 如果拉取最新数据失败,尝试从缓存中获取数据 - console.error(error); - const cachedData = await get(cacheKey); - if (cachedData) { - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - total: cachedData.length, - updateTime, - data: cachedData, - }; - } else { - // 如果缓存中也没有数据,则返回错误信息 - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - } - } -}); - -neteaseMusicRouter.info = routerInfo; -module.exports = neteaseMusicRouter; \ No newline at end of file diff --git a/routes/netease_music_toplist.js b/routes/netease_music_toplist.js new file mode 100644 index 0000000..1772d27 --- /dev/null +++ b/routes/netease_music_toplist.js @@ -0,0 +1,198 @@ +/** + * @author: x-dr + * @date: 2023-12-27 + * @customEditors: imsyy + * @lastEditTime: 2024-01-02 + */ + +const URL = require("url"); +const Router = require("koa-router"); +const neteaseMusicRouter = new Router(); +const axios = require("axios"); +const cheerio = require("cheerio"); +const { get, set, del } = require("../utils/cacheData"); + +// 接口信息 +const routerInfo = { + name: "netease_music_toplist", + title: "网易云音乐", + subtitle: "排行榜", +}; + +// 缓存键名 +const cacheKey = "neteasemusicToplistData"; + +// 调用时间 +let updateTime = new Date().toISOString(); + +const url = "https://music.163.com/discover/toplist?id="; + +const headers = { + authority: "music.163.com", + referer: "https://music.163.com/", +}; + +// 榜单类别 +const listType = { + 1: { + id: 19723756, + name: "飙升榜", + }, + 2: { + id: 3779629, + name: "新歌榜", + }, + 3: { + id: 2884035, + name: "原创榜", + }, + 4: { + id: 3778678, + name: "热歌榜", + }, +}; + +// 数据处理 +const getData = (data) => { + if (!data) return false; + const dataList = []; + const $ = cheerio.load(data); + try { + $(".m-sgitem").each((i, e) => { + const urlString = $(e).attr("href"); + const parsedUrl = URL.parse(urlString, true); + const urlidValue = parsedUrl.query.id; + const item = cheerio.load($(e).html()); + const author = item('div[class="f-thide sginfo"]') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const title = item('div[class="f-thide sgtl"]') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + dataList.push({ + title: title, + desc: author, + url: `https://music.163.com/#/song?id=${urlidValue}`, + mobileUrl: `https://music.163.com/m/song?id=${urlidValue}`, + }); + }); + return dataList; + } catch (error) { + console.error("数据处理出错" + error); + return false; + } +}; + +// 网易云音乐排行榜 +neteaseMusicRouter.get("/netease_music_toplist", async (ctx) => { + console.log("获取网易云音乐排行榜"); + try { + // 获取参数 + const { type } = ctx.query; + const typeNum = Number(type); + if (!typeNum || typeNum > 4 || typeNum < 1) { + ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" }; + return false; + } + // 更改名称 + routerInfo.subtitle = listType[typeNum].name; + // 从缓存中获取数据 + let data = await get(cacheKey + listType[typeNum].id); + const from = data ? "cache" : "server"; + if (!data) { + // 如果缓存中不存在数据 + console.log("从服务端重新获取网易云音乐排行榜"); + // 从服务器拉取数据 + const response = await axios.get(url + listType[typeNum].id, { headers }); + // console.log(response.data); + data = getData(response.data); + updateTime = new Date().toISOString(); + if (!data) { + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + return false; + } + // 将数据写入缓存 + await set(cacheKey + listType[typeNum].id, data); + } + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + from, + total: data.length, + updateTime, + data, + }; + } catch (error) { + console.error(error); + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + } +}); + +// 网易云音乐排行榜 - 获取最新数据 +neteaseMusicRouter.get("/netease_music_toplist/new", async (ctx) => { + console.log("获取网易云音乐排行榜 - 最新数据"); + try { + // 获取参数 + const { type } = ctx.query; + const typeNum = Number(type); + if (!typeNum || typeNum > 4 || typeNum < 1) { + ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" }; + return false; + } + // 更改名称 + routerInfo.subtitle = listType[typeNum].name; + // 从服务器拉取最新数据 + const response = await axios.get(url + listType[typeNum].id, { headers }); + const newData = getData(response.data); + updateTime = new Date().toISOString(); + console.log("从服务端重新获取网易云音乐排行榜"); + + // 返回最新数据 + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + updateTime, + total: newData.length, + data: newData, + }; + + // 删除旧数据 + await del(cacheKey + listType[typeNum].id); + // 将最新数据写入缓存 + await set(cacheKey + listType[typeNum].id, newData); + } catch (error) { + // 如果拉取最新数据失败,尝试从缓存中获取数据 + console.error(error); + const cachedData = await get(cacheKey); + if (cachedData) { + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + total: cachedData.length, + updateTime, + data: cachedData, + }; + } else { + // 如果缓存中也没有数据,则返回错误信息 + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + } + } +}); + +neteaseMusicRouter.info = routerInfo; +module.exports = neteaseMusicRouter; diff --git a/routes/ngabbs.js b/routes/ngabbs.js index 81e06a4..c4d9132 100644 --- a/routes/ngabbs.js +++ b/routes/ngabbs.js @@ -1,7 +1,8 @@ /** - * @author: x-dr - * @date: 2023年12月25日 - * @tags: [NGA论坛热帖] + * @author: x-dr + * @date: 2023-12-25 + * @customEditors: imsyy + * @lastEditTime: 2024-01-02 */ const Router = require("koa-router"); @@ -9,7 +10,6 @@ const ngabbsRouter = new Router(); const axios = require("axios"); const { get, set, del } = require("../utils/cacheData"); - // 接口信息 const routerInfo = { name: "ngabbs", title: "NGA", subtitle: "论坛热帖" }; @@ -19,136 +19,136 @@ const cacheKey = "ngabbsData"; // 调用时间 let updateTime = new Date().toISOString(); -const url = 'https://ngabbs.com/nuke.php?__lib=load_topic&__act=load_topic_reply_ladder2&opt=1&all=1'; +const url = + "https://ngabbs.com/nuke.php?__lib=load_topic&__act=load_topic_reply_ladder2&opt=1&all=1"; const headers = { - 'Host': 'ngabbs.com', - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': '*/*', - 'Accept-Encoding': 'gzip, deflate, br', - 'Connection': 'keep-alive', - 'Content-Length': '11', - 'User-Agent': 'NGA/7.3.1 (iPhone; iOS 17.2.1; Scale/3.00)', - 'Accept-Language': 'zh-Hans-CN;q=1', - 'Referer': 'https://ngabbs.com/', - 'X-User-Agent': 'NGA_skull/7.3.1(iPhone13,2;iOS 17.2.1)', + Host: "ngabbs.com", + "Content-Type": "application/x-www-form-urlencoded", + Accept: "*/*", + "Accept-Encoding": "gzip, deflate, br", + Connection: "keep-alive", + "Content-Length": "11", + "User-Agent": "NGA/7.3.1 (iPhone; iOS 17.2.1; Scale/3.00)", + "Accept-Language": "zh-Hans-CN;q=1", + Referer: "https://ngabbs.com/", + "X-User-Agent": "NGA_skull/7.3.1(iPhone13,2;iOS 17.2.1)", }; -const postData = { '__output': '14' }; +const postData = { __output: "14" }; + // 数据处理 const getData = (data) => { - if (!data) return []; - const dataList = []; - try { - - const result = data.result[0]; - result.forEach((result) => { - dataList.push({ - author: result.author, - desc: result.subject, - parent: result.parent['2'], - tid: result.tid, - comments: Number(result.replies), - url: `https://bbs.nga.cn/read.php?tid=${result.tid}`, - mobileUrl: `https://bbs.nga.cn/read.php?tid=${result.tid}`, - - }); - }); - return dataList; - } catch (error) { - console.error("数据处理出错" + error); - return false; - } + if (!data) return []; + const dataList = []; + try { + const result = data.result[0]; + result.forEach((result) => { + dataList.push({ + author: result.author, + desc: result.subject, + parent: result.parent["2"], + tid: result.tid, + comments: Number(result.replies), + url: `https://bbs.nga.cn/read.php?tid=${result.tid}`, + mobileUrl: `https://bbs.nga.cn/read.php?tid=${result.tid}`, + }); + }); + return dataList; + } catch (error) { + console.error("数据处理出错" + error); + return false; + } }; // NGA论坛热帖 ngabbsRouter.get("/ngabbs", async (ctx) => { - console.log("获取NGA论坛热帖"); - try { - // 从缓存中获取数据 - let data = await get(cacheKey); - const from = data ? "cache" : "server"; - if (!data) { - // 如果缓存中不存在数据 - console.log("从服务端重新获取NGA论坛热帖"); - // 从服务器拉取数据 - const response = await axios.post(url, postData, { headers }); - data = getData(response.data); - updateTime = new Date().toISOString(); - if (!data) { - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - return false; - } - // 将数据写入缓存 - await set(cacheKey, data); - } + console.log("获取NGA论坛热帖"); + try { + // 从缓存中获取数据 + let data = await get(cacheKey); + const from = data ? "cache" : "server"; + if (!data) { + // 如果缓存中不存在数据 + console.log("从服务端重新获取NGA论坛热帖"); + // 从服务器拉取数据 + const response = await axios.post(url, postData, { headers }); + data = getData(response.data); + updateTime = new Date().toISOString(); + if (!data) { ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - from, - total: data.length, - updateTime, - data, - }; - } catch (error) { - console.error(error); - ctx.body = { - code: 500, - message: "获取失败", + code: 500, + ...routerInfo, + message: "获取失败", }; + return false; + } + // 将数据写入缓存 + await set(cacheKey, data); } + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + from, + total: data.length, + updateTime, + data, + }; + } catch (error) { + console.error(error); + ctx.body = { + code: 500, + message: "获取失败", + }; + } }); // NGA论坛热帖 - 获取最新数据 ngabbsRouter.get("/ngabbs/new", async (ctx) => { - console.log("获取NGA论坛热帖 - 最新数据"); - try { - // 从服务器拉取最新数据 - const response = await axios.post(url, postData, { headers }); - const newData = getData(response.data); - updateTime = new Date().toISOString(); - console.log("从服务端重新获取NGA论坛热帖"); + console.log("获取NGA论坛热帖 - 最新数据"); + try { + // 从服务器拉取最新数据 + const response = await axios.post(url, postData, { headers }); + const newData = getData(response.data); + updateTime = new Date().toISOString(); + console.log("从服务端重新获取NGA论坛热帖"); - // 返回最新数据 - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - total: newData.length, - updateTime, - data: newData, - }; + // 返回最新数据 + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + total: newData.length, + updateTime, + data: newData, + }; - // 删除旧数据 - await del(cacheKey); - // 将最新数据写入缓存 - await set(cacheKey, newData); - } catch (error) { - // 如果拉取最新数据失败,尝试从缓存中获取数据 - console.error(error); - const cachedData = await get(cacheKey); - if (cachedData) { - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - total: cachedData.length, - updateTime, - data: cachedData, - }; - } else { - // 如果缓存中也没有数据,则返回错误信息 - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - } + // 删除旧数据 + await del(cacheKey); + // 将最新数据写入缓存 + await set(cacheKey, newData); + } catch (error) { + // 如果拉取最新数据失败,尝试从缓存中获取数据 + console.error(error); + const cachedData = await get(cacheKey); + if (cachedData) { + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + total: cachedData.length, + updateTime, + data: cachedData, + }; + } else { + // 如果缓存中也没有数据,则返回错误信息 + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; } + } }); ngabbsRouter.info = routerInfo; diff --git a/routes/qq_music.js b/routes/qq_music.js deleted file mode 100644 index d924d9a..0000000 --- a/routes/qq_music.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @author: x-dr - * @date: 2023年12月27日 - * @tags: [QQ音乐热歌榜] - */ - -// const fs = require("fs"); -const Router = require("koa-router"); -const qqMusicRouter = new Router(); -const axios = require("axios"); -const cheerio = require("cheerio"); -const { get, set, del } = require("../utils/cacheData"); - -// 接口信息 -const routerInfo = { - name: "qqmusic", - title: "QQ音乐", - subtitle: "热歌榜", -}; - - -// 缓存键名 -const cacheKey = "qqmusicData"; - -// 调用时间 -let updateTime = new Date().toISOString(); - -const url = "https://y.qq.com/n/ryqq/toplist/26"; - -const headers = { - 'authority': 'y.qq.com', - 'referer': 'https://www.google.com/', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' -}; - - - -// 数据处理 -const getData = (data) => { - if (!data) return false; - const dataList = []; - const $ = cheerio.load(data); - // fs.writeFileSync('qq.html', $.html()); - try { - $('.songlist__item').each((i, e) => { - const item = cheerio.load($(e).html()) - const title = item('a[class="songlist__cover"]').attr('title') - const urlPath = item('a[class="songlist__cover"]').attr('href') - const author = item('div[class="songlist__artist"]').text().replace(/(^\s*)|(\s*$)/g, "") - const songtime = item('div[class="songlist__time"]').text().replace(/(^\s*)|(\s*$)/g, "") - // const title = item('div[class="f-thide sgtl"]').text().replace(/(^\s*)|(\s*$)/g, "") - dataList.push({ - title: title, - desc: author, - songtime: songtime, - url: `https://y.qq.com${urlPath}`, - mobileUrl: `https://y.qq.com${urlPath}`, - }); - - - - }); - return dataList; - } catch (error) { - console.error("数据处理出错" + error); - return false; - } -}; - - - -// -qqMusicRouter.get("/qqmusic", async (ctx) => { - console.log("获取QQ音乐热歌榜 "); - try { - // 从缓存中获取数据 - let data = await get(cacheKey); - const from = data ? "cache" : "server"; - if (!data) { - // 如果缓存中不存在数据 - console.log("从服务端重新QQ音乐热歌榜 "); - // 从服务器拉取数据 - const response = await axios.get(url, { headers }); - // console.log(response.data); - data = getData(response.data); - - updateTime = new Date().toISOString(); - if (!data) { - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - return false; - } - // 将数据写入缓存 - await set(cacheKey, data); - } - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - from, - total: data.length, - updateTime, - data, - }; - } catch (error) { - console.error(error); - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - } -}); - - - - -// 豆瓣新片榜 - 获取最新数据 -qqMusicRouter.get("/qqmusic/new", async (ctx) => { - console.log("获取QQ音乐热歌榜 - 最新数据"); - try { - // 从服务器拉取最新数据 - const response = await axios.get(url, { headers }); - const newData = getData(response.data); - updateTime = new Date().toISOString(); - console.log("从服务端重新QQ音乐热歌榜 "); - - // 返回最新数据 - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - updateTime, - total: newData.length, - data: newData, - }; - - // 删除旧数据 - await del(cacheKey); - // 将最新数据写入缓存 - await set(cacheKey, newData); - } catch (error) { - // 如果拉取最新数据失败,尝试从缓存中获取数据 - console.error(error); - const cachedData = await get(cacheKey); - if (cachedData) { - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - total: cachedData.length, - updateTime, - data: cachedData, - }; - } else { - // 如果缓存中也没有数据,则返回错误信息 - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - } - } -}); - -qqMusicRouter.info = routerInfo; -module.exports = qqMusicRouter; \ No newline at end of file diff --git a/routes/qq_music_toplist.js b/routes/qq_music_toplist.js new file mode 100644 index 0000000..3c577e6 --- /dev/null +++ b/routes/qq_music_toplist.js @@ -0,0 +1,211 @@ +/** + * @author: x-dr + * @date: 2023-12-27 + * @customEditors: imsyy + * @lastEditTime: 2024-01-02 + */ + +// const fs = require("fs"); +const Router = require("koa-router"); +const qqMusicRouter = new Router(); +const axios = require("axios"); +const cheerio = require("cheerio"); +const { get, set, del } = require("../utils/cacheData"); + +// 接口信息 +const routerInfo = { + name: "qq_music_toplist", + title: "QQ音乐", + subtitle: "排行榜", +}; + +// 缓存键名 +const cacheKey = "qqmusicData"; + +// 调用时间 +let updateTime = new Date().toISOString(); + +const url = "https://y.qq.com/n/ryqq/toplist/"; + +const headers = { + authority: "y.qq.com", + referer: "https://www.google.com/", + "user-agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", +}; + +// 榜单类别 +const listType = { + 1: { + id: 62, + name: "飙升榜", + }, + 2: { + id: 26, + name: "热歌榜", + }, + 3: { + id: 27, + name: "新歌榜", + }, + 4: { + id: 4, + name: "流行指数榜", + }, + 5: { + id: 52, + name: "腾讯音乐人原创榜", + }, + 6: { + id: 67, + name: "听歌识曲榜", + }, +}; + +// 数据处理 +const getData = (data) => { + if (!data) return false; + const dataList = []; + const $ = cheerio.load(data); + // fs.writeFileSync('qq.html', $.html()); + try { + $(".songlist__item").each((i, e) => { + const item = cheerio.load($(e).html()); + const title = item('a[class="songlist__cover"]').attr("title"); + const urlPath = item('a[class="songlist__cover"]').attr("href"); + const author = item('div[class="songlist__artist"]') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const songtime = item('div[class="songlist__time"]') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + // const title = item('div[class="f-thide sgtl"]').text().replace(/(^\s*)|(\s*$)/g, "") + dataList.push({ + title: title, + desc: author, + songtime: songtime, + url: `https://y.qq.com${urlPath}`, + mobileUrl: `https://y.qq.com${urlPath}`, + }); + }); + return dataList; + } catch (error) { + console.error("数据处理出错" + error); + return false; + } +}; + +// 获取QQ音乐排行榜 +qqMusicRouter.get("/qq_music_toplist", async (ctx) => { + console.log("获取QQ音乐排行榜"); + try { + // 获取参数 + const { type } = ctx.query; + const typeNum = Number(type); + if (!typeNum || typeNum > 6 || typeNum < 1) { + ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" }; + return false; + } + // 更改名称 + routerInfo.subtitle = listType[typeNum].name; + // 从缓存中获取数据 + let data = await get(cacheKey + listType[typeNum].id); + const from = data ? "cache" : "server"; + if (!data) { + // 如果缓存中不存在数据 + console.log("从服务端重新QQ音乐排行榜"); + // 从服务器拉取数据 + const response = await axios.get(url + listType[typeNum].id, { headers }); + // console.log(response.data); + data = getData(response.data); + + updateTime = new Date().toISOString(); + if (!data) { + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + return false; + } + // 将数据写入缓存 + await set(cacheKey + listType[typeNum].id, data); + } + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + from, + total: data.length, + updateTime, + data, + }; + } catch (error) { + console.error(error); + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + } +}); + +// 获取QQ音乐排行榜 - 获取最新数据 +qqMusicRouter.get("/qq_music_toplist/new", async (ctx) => { + console.log("获取QQ音乐排行榜 - 最新数据"); + try { + // 获取参数 + const { type } = ctx.query; + const typeNum = Number(type); + if (!typeNum || typeNum > 4 || typeNum < 1) { + ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" }; + return false; + } + // 更改名称 + routerInfo.subtitle = listType[typeNum].name; + // 从服务器拉取最新数据 + const response = await axios.get(url + listType[typeNum].id, { headers }); + const newData = getData(response.data); + updateTime = new Date().toISOString(); + console.log("从服务端重新QQ音乐排行榜"); + + // 返回最新数据 + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + updateTime, + total: newData.length, + data: newData, + }; + + // 删除旧数据 + await del(cacheKey + listType[typeNum].id); + // 将最新数据写入缓存 + await set(cacheKey + listType[typeNum].id, newData); + } catch (error) { + // 如果拉取最新数据失败,尝试从缓存中获取数据 + console.error(error); + const cachedData = await get(cacheKey); + if (cachedData) { + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + total: cachedData.length, + updateTime, + data: cachedData, + }; + } else { + // 如果缓存中也没有数据,则返回错误信息 + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + } + } +}); + +qqMusicRouter.info = routerInfo; +module.exports = qqMusicRouter; diff --git a/routes/v2ex.js b/routes/v2ex.js index ab7354e..3a60b30 100644 --- a/routes/v2ex.js +++ b/routes/v2ex.js @@ -1,7 +1,8 @@ /** * @author: x-dr - * @date: 2023年12月25日 - * @tags: [V2EX热帖] + * @date: 2023-12-25 + * @customEditors: imsyy + * @lastEditTime: 2024-01-02 */ const Router = require("koa-router"); @@ -12,14 +13,13 @@ const { get, set, del } = require("../utils/cacheData"); // 接口信息 const routerInfo = { - name: "v2ex", - title: "V2EX", - subtitle: "hot", + name: "v2ex", + title: "V2EX", + subtitle: "hot", }; - // 缓存键名 -const cacheKey = "v2exbData"; +const cacheKey = "v2exData"; // 调用时间 let updateTime = new Date().toISOString(); @@ -27,150 +27,149 @@ let updateTime = new Date().toISOString(); const url = "https://www.v2ex.com/?tab=hot"; const headers = { - "Content-Type": "application/json", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", - 'authority': 'www.v2ex.com', - 'referer': 'https://www.v2ex.com/' + "Content-Type": "application/json", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", + authority: "www.v2ex.com", + referer: "https://www.v2ex.com/", }; - - // 数据处理 const getData = (data) => { - if (!data) return false; - const dataList = []; - const $ = cheerio.load(data); - try { - $(`div[class="cell item"]`).each((i, e) => { - const item = cheerio.load($(e).html()) - const title = item('span[class="item_title"]').text().replace(/(^\s*)|(\s*$)/g, "") - const href = item('.item_title a').attr('href'); - const url = `https://www.v2ex.com${href}` - const comments = item('.count_livid').text().replace(/(^\s*)|(\s*$)/g, "") - const member = item('.topic_info strong a:first').text().replace(/(^\s*)|(\s*$)/g, "") - const node = item('.topic_info .node').text().replace(/(^\s*)|(\s*$)/g, "") - const avatar_img = item('.avatar').attr('src'); - // console.log( url); + if (!data) return false; + const dataList = []; + const $ = cheerio.load(data); + try { + $(`div[class="cell item"]`).each((i, e) => { + const item = cheerio.load($(e).html()); + const title = item('span[class="item_title"]') + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const href = item(".item_title a").attr("href"); + const url = `https://www.v2ex.com${href}`; + const comments = item(".count_livid") + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const member = item(".topic_info strong a:first") + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const node = item(".topic_info .node") + .text() + .replace(/(^\s*)|(\s*$)/g, ""); + const avatar_img = item(".avatar").attr("src"); + // console.log( url); - dataList.push({ - title: title, - url: url, - mobileUrl: url, - comments: comments, - member: member, - node: node, - avatar: avatar_img + dataList.push({ + title: title, + url: url, + mobileUrl: url, + comments: comments, + member: member, + node: node, + avatar: avatar_img, + }); + }); - }); - - - }) - - return dataList; - } catch (error) { - console.error("数据处理出错" + error); - return false; - } + return dataList; + } catch (error) { + console.error("数据处理出错" + error); + return false; + } }; - - -// trending +// v2ex v2exRouter.get("/v2ex", async (ctx) => { - console.log("获取v2ex"); - try { - // 从缓存中获取数据 - let data = await get(cacheKey); - const from = data ? "cache" : "server"; - if (!data) { - // 如果缓存中不存在数据 - console.log("从服务端重新v2ex"); - // 从服务器拉取数据 - const response = await axios.get(url, { headers }); - // console.log(response.data); - data = getData(response.data); + console.log("获取v2ex"); + try { + // 从缓存中获取数据 + let data = await get(cacheKey); + const from = data ? "cache" : "server"; + if (!data) { + // 如果缓存中不存在数据 + console.log("从服务端重新获取v2ex"); + // 从服务器拉取数据 + const response = await axios.get(url, { headers }); + // console.log(response.data); + data = getData(response.data); - updateTime = new Date().toISOString(); - if (!data) { - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - return false; - } - // 将数据写入缓存 - await set(cacheKey, data); - } + updateTime = new Date().toISOString(); + if (!data) { ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - from, - total: data.length, - updateTime, - data, - }; - } catch (error) { - console.error(error); - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", + code: 500, + ...routerInfo, + message: "获取失败", }; + return false; + } + // 将数据写入缓存 + await set(cacheKey, data); } + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + from, + total: data.length, + updateTime, + data, + }; + } catch (error) { + console.error(error); + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; + } }); - - - -// 豆瓣新片榜 - 获取最新数据 +// v2ex - 获取最新数据 v2exRouter.get("/v2ex/new", async (ctx) => { - console.log("获取v2ex - 最新数据"); - try { - // 从服务器拉取最新数据 - const response = await axios.get(url, { headers }); - const newData = getData(response.data); - updateTime = new Date().toISOString(); - console.log("从服务端重新v2ex"); + console.log("获取v2ex - 最新数据"); + try { + // 从服务器拉取最新数据 + const response = await axios.get(url, { headers }); + const newData = getData(response.data); + updateTime = new Date().toISOString(); + console.log("从服务端重新获取v2ex"); - // 返回最新数据 - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - updateTime, - total: newData.length, - data: newData, - }; + // 返回最新数据 + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + updateTime, + total: newData.length, + data: newData, + }; - // 删除旧数据 - await del(cacheKey); - // 将最新数据写入缓存 - await set(cacheKey, newData); - } catch (error) { - // 如果拉取最新数据失败,尝试从缓存中获取数据 - console.error(error); - const cachedData = await get(cacheKey); - if (cachedData) { - ctx.body = { - code: 200, - message: "获取成功", - ...routerInfo, - total: cachedData.length, - updateTime, - data: cachedData, - }; - } else { - // 如果缓存中也没有数据,则返回错误信息 - ctx.body = { - code: 500, - ...routerInfo, - message: "获取失败", - }; - } + // 删除旧数据 + await del(cacheKey); + // 将最新数据写入缓存 + await set(cacheKey, newData); + } catch (error) { + // 如果拉取最新数据失败,尝试从缓存中获取数据 + console.error(error); + const cachedData = await get(cacheKey); + if (cachedData) { + ctx.body = { + code: 200, + message: "获取成功", + ...routerInfo, + total: cachedData.length, + updateTime, + data: cachedData, + }; + } else { + // 如果缓存中也没有数据,则返回错误信息 + ctx.body = { + code: 500, + ...routerInfo, + message: "获取失败", + }; } + } }); v2exRouter.info = routerInfo; -module.exports = v2exRouter; \ No newline at end of file +module.exports = v2exRouter;