From f43d78c7c606ea093913214fc07e976098bc9ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E5=88=80=E9=B1=BC?= <9903082+qdyovo@user.noreply.gitee.com> Date: Tue, 15 Oct 2024 14:22:12 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=BD=91=E6=98=93=E4=BA=91=E6=89=AB=E7=A0=81=E7=99=BB=E5=BD=95?= =?UTF-8?q?/=E7=BD=91=E6=98=93=E4=BA=91=E7=99=BB=E5=BD=95=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 145 ++++++++++++++++++++++++++++++++++++++++-- config/tools.yaml | 5 ++ constants/constant.js | 12 ++++ guoba.support.js | 42 +++++++++++- 4 files changed, 199 insertions(+), 5 deletions(-) diff --git a/apps/tools.js b/apps/tools.js index 5dcdf86..8d4f7a6 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -23,7 +23,7 @@ import { SUMMARY_PROMPT, transMap, TWITTER_BEARER_TOKEN, - XHS_NO_WATERMARK_HEADER, + XHS_NO_WATERMARK_HEADER } from "../constants/constant.js"; import { ANIME_SERIES_SEARCH_LINK, @@ -123,7 +123,7 @@ export class tools extends plugin { priority: 300, rule: [ { - reg: `^(翻|trans)[${ tools.Constants.existsTransKey }]`, + reg: `^(翻|trans)[${tools.Constants.existsTransKey}]`, fnc: "trans", }, { @@ -214,7 +214,18 @@ export class tools extends plugin { { reg: '^#验车(.*?)', fnc: 'yc' - } + }, + { + reg: "^#(网易云登录状态|网易状态|网易云状态)$", + fnc: "neteaseStatus", + permission: 'master', + }, + { + reg: "^#(网易云扫码登录|网易扫码登录)$", + fnc: 'netease_scan', + permission: 'master', + }, + ], }); // 配置文件 @@ -226,7 +237,7 @@ export class tools extends plugin { // 魔法接口 this.proxyAddr = this.toolsConfig.proxyAddr; this.proxyPort = this.toolsConfig.proxyPort; - this.myProxy = `http://${ this.proxyAddr }:${ this.proxyPort }`; + this.myProxy = `http://${this.proxyAddr}:${this.proxyPort}`; // 加载识别前缀 this.identifyPrefix = this.toolsConfig.identifyPrefix; // 加载直播录制时长 @@ -251,6 +262,14 @@ export class tools extends plugin { this.biliUseBBDown = this.toolsConfig.biliUseBBDown; // 加载 BBDown 的CDN配置 this.biliCDN = this.toolsConfig.biliCDN; + // 加载网易云Cookie + this.neteaseCookie = this.toolsConfig.neteaseCookie + // 加载是否自建服务器 + this.useLocalNeteaseAPI = this.toolsConfig.useLocalNeteaseAPI + // 加载自建服务器API + this.neteaseCloudAPIServer = this.toolsConfig.neteaseCloudAPIServer + // 加载网易云解析最高音质 + this.neteaseCloudAudioQuality = this.toolsConfig.neteaseCloudAudioQuality // 加载哔哩哔哩是否使用Aria2 this.biliDownloadMethod = this.toolsConfig.biliDownloadMethod; // 加载哔哩哔哩最高分辨率 @@ -1361,6 +1380,124 @@ export class tools extends plugin { return true; } + // 网易云登录状态 + async neteaseStatus(e) { + // 优先判断是否使用自建 API + let autoSelectNeteaseApi + // 判断海外 + const isOversea = await this.isOverseasServer(); + if (this.useLocalNeteaseAPI) { + // 使用自建 API + autoSelectNeteaseApi = this.neteaseCloudAPIServer + } else { + // 自动选择 API + autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN; + } + const statusUrl = autoSelectNeteaseApi + '/login/status' + axios.get(statusUrl, { + headers: { + "User-Agent": COMMON_USER_AGENT, + "Cookie": this.neteaseCookie + }, + }).then(res => { + // logger.info('登录状态', res.data) + const userInfo = res.data.data.profile + if (userInfo) { + axios.get(`${autoSelectNeteaseApi}/vip/info?uid=${userInfo.userId}`, { + headers: { + "User-Agent": COMMON_USER_AGENT, + "Cookie": this.neteaseCookie + }, + }).then(res => { + // logger.info('vip信息', res.data) + const vipInfo = res.data.data + if (vipInfo.redplus.code != 0) { + const expireTime = new Date(vipInfo.redplus.expireTime).toLocaleString(); + e.reply([segment.image(`${userInfo.avatarUrl}?param=158y158`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nSVIP${vipInfo.redplus.vipLevel}\n最高解析音质:\njymaster(超清母带)\n会员到期时间:\n${expireTime}`]); + } else if (vipInfo.associator.code != 0) { + const expireTime = new Date(vipInfo.associator.expireTime).toLocaleString(); + e.reply([segment.image(`${userInfo.avatarUrl}?param=158y158`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP${vipInfo.associator.vipLevel}\n最高解析音质:\lossless(无损)\n会员到期时间:\n${expireTime}`]); + } else { + e.reply([segment.image(`${userInfo.avatarUrl}?param=158y158`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\n暂无VIP\n最高解析音质:\exhigh(极高)`]); + } + }) + } else { + e.reply('暂未登录,请发#网易云扫码登陆进行登陆绑定ck') + } + }) + } + // 网易扫码登录 + async netease_scan(e) { + // 优先判断是否使用自建 API + let autoSelectNeteaseApi + // 判断海外 + const isOversea = await this.isOverseasServer(); + if (this.useLocalNeteaseAPI) { + // 使用自建 API + autoSelectNeteaseApi = this.neteaseCloudAPIServer + } else { + // 自动选择 API + autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN; + } + // 获取登录key + let keyUrl = autoSelectNeteaseApi + '/login/qr/key' + axios.get(keyUrl, { + headers: { + "User-Agent": COMMON_USER_AGENT + }, + }).then(res => { + // 获取登录二维码 + const unikey = res.data.data.unikey + let url = autoSelectNeteaseApi + '/login/qr/create?key=' + unikey + "&qrimg=true" + axios.get(url, { + headers: { + "User-Agent": COMMON_USER_AGENT, + }, + }).then(res => { + e.reply([segment.image(res.data.data.qrimg), '请在30秒内使用网易云APP进行扫码']); + }) + + //最大轮询次数 5s/check + let pollCount = 0; // 轮询计数器 + const maxPolls = 6; // 最大轮询次数 + + function pollRequest() { + let pollUrl = autoSelectNeteaseApi + '/login/qr/check?key=' + unikey + '×tamp=' + Date.now() + axios.get(pollUrl, { + headers: { + "User-Agent": COMMON_USER_AGENT, + }, + }).then(res => { + if (res.data.code == '800') { + e.reply(`二维码过期,请重新获取`); + clearInterval(intervalId); + return + } + if (res.data.code == '803') { + config.updateField("tools", "neteaseCookie", res.data.cookie) + const regex = /music_u=([^;]+)/i; // 使用 'i' 进行不区分大小写匹配 + const match = res.data.cookie.match(regex); + if (match) { + config.updateField("tools", "neteaseCookie", match[0]) + } + // logger.info('ck------', match[0]) + e.reply(`扫码登录成功,ck已自动保存`); + clearInterval(intervalId); + return + } + pollCount++ + // logger.info('登录erweima',res) + }) + if (pollCount >= maxPolls) { + clearInterval(intervalId); // 停止轮询 + logger.info('超时轮询已停止'); + e.reply('扫码超时,请重新获取'); + } + } + const intervalId = setInterval(pollRequest, 5000); + }) + } + // 网易云解析 async netease(e) { let message = diff --git a/config/tools.yaml b/config/tools.yaml index 96b57cd..019c01f 100644 --- a/config/tools.yaml +++ b/config/tools.yaml @@ -22,6 +22,11 @@ biliCDN: 0 # 哔哩哔哩 CDN,默认为0表示不使用 biliDownloadMethod: 0 # 哔哩哔哩的下载方式:0默认使用原生稳定的下载方式,如果你在乎内存可以使用轻量的wget和axel下载方式,如果在乎性能可以使用Aria2下载 biliResolution: 1 # 哔哩哔哩的下载画质,0为原画,1为清晰画,2为流畅画(默认为0) +useLocalNeteaseAPI: false #是否使用网易云解析自建API +neteaseCookie: '' #网易云ck +neteaseCloudAPIServer: '' #网易云自建服务器地址 +neteaseCloudAudioQuality: exhigh #网易云解析最高音质 默认exhigh(极高) 分类:standard => 标准,higher => 较高, exhigh=>极高, lossless=>无损, hires=>Hi-Res, jyeffect => 高清环绕声, sky => 沉浸环绕声, dolby => 杜比全景声, jymaster => 超清母带 + YouTubeGraphicsOptions: 720 #YouTobe的下载画质,0为原画,1080,720,480,自定义画面高度(默认为720) douyinCookie: '' # douyin's cookie, 格式:odin_tt=xxx;passport_fe_beating_status=xxx;sid_guard=xxx;uid_tt=xxx;uid_tt_ss=xxx;sid_tt=xxx;sessionid=xxx;sessionid_ss=xxx;sid_ucp_v1=xxx;ssid_ucp_v1=xxx;passport_assist_user=xxx;ttwid=xxx; diff --git a/constants/constant.js b/constants/constant.js index 15c7a99..da62f8f 100644 --- a/constants/constant.js +++ b/constants/constant.js @@ -193,6 +193,18 @@ export const YOUTUBE_GRAPHICS_LIST = Object.freeze([ { label: '720P 高清', value: 720 }, { label: '480P 清晰', value: 480 }, ]); + +export const NETEASECLOUD_QUALITY_LIST = Object.freeze([ + { label: '标准', value: 'standard' }, + { label: '较高', value: 'higher' }, + { label: '极高', value: 'exhigh' }, + { label: '无损', value: 'lossless' }, + { label: 'Hi-Res', value: 'hires' }, + { label: '高清环绕声', value: 'jyeffect' }, + { label: '沉浸环绕声', value: 'sky' }, + { label: '杜比全景声', value: 'dolby' }, + { label: '超清母带', value: 'jymaster' }, +]); /** * 消息撤回时间 * @type {number} diff --git a/guoba.support.js b/guoba.support.js index 257c5f2..774a632 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -1,6 +1,6 @@ import _ from "lodash"; import path from "path"; -import { BILI_CDN_SELECT_LIST, BILI_DOWNLOAD_METHOD, BILI_RESOLUTION_LIST, YOUTUBE_GRAPHICS_LIST } from "./constants/constant.js"; +import { BILI_CDN_SELECT_LIST, BILI_DOWNLOAD_METHOD, BILI_RESOLUTION_LIST, YOUTUBE_GRAPHICS_LIST, NETEASECLOUD_QUALITY_LIST } from "./constants/constant.js"; import model from "./model/config.js"; const pluginName = `rconsole-plugin`; @@ -230,6 +230,46 @@ export function supportGuoba() { options: YOUTUBE_GRAPHICS_LIST, } }, + { + field: "tools.useLocalNeteaseAPI", + label: "使用自建网易云API", + bottomHelpMessage: + "默认不开启,有条件可以查看https://gitlab.com/Binaryify/neteasecloudmusicapi进行搭建", + component: "Switch", + required: false, + }, + { + field: "tools.neteaseCloudAPIServer", + label: "自建网易云API地址", + bottomHelpMessage: + "填入自建API地址,例:http://xxxxxxxx", + component: "Input", + required: false, + componentProps: { + placeholder: "填入自建API地址", + }, + }, + { + field: "tools.neteaseCookie", + label: "网易云Cookie", + bottomHelpMessage: + "可以发送 #网易云扫码登陆 快捷获取 或 者在网易云官网自己获取", + component: "Input", + required: false, + componentProps: { + placeholder: "使用vip账号登陆获取更高音质解析", + }, + }, + { + field: "tools.neteaseCloudAudioQuality", + label: "网易云解析最高音质", + bottomHelpMessage: + "网易云解析最高音质(需vip账号ck!!! 默认极高,更高请根据登陆的账号和服务器承载能力进行选择)", + component: "Select", + componentProps: { + options: NETEASECLOUD_QUALITY_LIST, + } + }, { field: "tools.douyinCookie", label: "抖音的Cookie", From 25a7c39d9164938b2281d72c02c533ca0ac0d2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E5=88=80=E9=B1=BC?= <9903082+qdyovo@user.noreply.gitee.com> Date: Tue, 15 Oct 2024 16:05:41 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=90=9E=20fix=EF=BC=9A=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DVIP=E8=BF=87=E6=9C=9F=E7=BD=91=E6=98=93=E4=BA=91?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF/?= =?UTF-8?q?=F0=9F=8E=88=20pref:=20=E4=BC=98=E5=8C=96=E6=89=AB=E7=A0=81?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=88=90=E5=8A=9F=E5=90=8E=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 77 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/apps/tools.js b/apps/tools.js index 8d4f7a6..cffe4c6 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -1380,8 +1380,8 @@ export class tools extends plugin { return true; } - // 网易云登录状态 - async neteaseStatus(e) { + // 网易云登录状态 + async neteaseStatus(e, reck) { // 优先判断是否使用自建 API let autoSelectNeteaseApi // 判断海外 @@ -1397,7 +1397,7 @@ export class tools extends plugin { axios.get(statusUrl, { headers: { "User-Agent": COMMON_USER_AGENT, - "Cookie": this.neteaseCookie + "Cookie": reck ? reck : this.neteaseCookie }, }).then(res => { // logger.info('登录状态', res.data) @@ -1406,21 +1406,30 @@ export class tools extends plugin { axios.get(`${autoSelectNeteaseApi}/vip/info?uid=${userInfo.userId}`, { headers: { "User-Agent": COMMON_USER_AGENT, - "Cookie": this.neteaseCookie + "Cookie": reck ? reck : this.neteaseCookie }, }).then(res => { // logger.info('vip信息', res.data) const vipInfo = res.data.data - if (vipInfo.redplus.code != 0) { - const expireTime = new Date(vipInfo.redplus.expireTime).toLocaleString(); - e.reply([segment.image(`${userInfo.avatarUrl}?param=158y158`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nSVIP${vipInfo.redplus.vipLevel}\n最高解析音质:\njymaster(超清母带)\n会员到期时间:\n${expireTime}`]); - } else if (vipInfo.associator.code != 0) { - const expireTime = new Date(vipInfo.associator.expireTime).toLocaleString(); - e.reply([segment.image(`${userInfo.avatarUrl}?param=158y158`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP${vipInfo.associator.vipLevel}\n最高解析音质:\lossless(无损)\n会员到期时间:\n${expireTime}`]); + if (vipInfo.redplus.vipCode != 0) { + const expireTime = new Date(vipInfo.redplus.expireTime); + if (expireTime > Date.now()) { + e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nSVIP${vipInfo.redplus.vipLevel}\n最高解析音质:\njymaster(超清母带)\n会员到期时间:\n${expireTime.toLocaleString()}`]); + } else { + e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\standard(标准)`]); + } + } else if (vipInfo.associator.vipCode != 0) { + const expireTime = new Date(vipInfo.associator.expireTime); + if (expireTime > Date.now()) { + e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP${vipInfo.associator.vipLevel}\n最高解析音质:\nlossless(无损)\n会员到期时间:\n${expireTime.toLocaleString()}`]); + } else { + e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\standard(标准)`]); + } } else { - e.reply([segment.image(`${userInfo.avatarUrl}?param=158y158`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\n暂无VIP\n最高解析音质:\exhigh(极高)`]); + e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\standard(标准)`]); } }) + // e.reply([segment.image(userInfo.avatarUrl), `网易云已登录:${userInfo.nickname}\n会员等级:\n`,segment.image(vipInfo.iconUrl)]); } else { e.reply('暂未登录,请发#网易云扫码登陆进行登陆绑定ck') } @@ -1461,33 +1470,47 @@ export class tools extends plugin { let pollCount = 0; // 轮询计数器 const maxPolls = 6; // 最大轮询次数 - function pollRequest() { - let pollUrl = autoSelectNeteaseApi + '/login/qr/check?key=' + unikey + '×tamp=' + Date.now() - axios.get(pollUrl, { - headers: { - "User-Agent": COMMON_USER_AGENT, - }, - }).then(res => { + const pollRequest = async () => { + let pollUrl = autoSelectNeteaseApi + '/login/qr/check?key=' + unikey + '×tamp=' + Date.now(); + try { + const res = await axios.get(pollUrl, { + headers: { + "User-Agent": COMMON_USER_AGENT, + }, + }); + logger.info('轮询状态', res.data); if (res.data.code == '800') { - e.reply(`二维码过期,请重新获取`); + e.reply("二维码过期,请重新获取"); clearInterval(intervalId); - return + return; } if (res.data.code == '803') { - config.updateField("tools", "neteaseCookie", res.data.cookie) const regex = /music_u=([^;]+)/i; // 使用 'i' 进行不区分大小写匹配 const match = res.data.cookie.match(regex); if (match) { - config.updateField("tools", "neteaseCookie", match[0]) + try { + await config.updateField("tools", "neteaseCookie", match[0]); + // logger.info('ck------', match[0]); + this.neteaseStatus(e, match[0]) + } catch (error) { + logger.error('更新ck时出错:', error); + e.reply('更新ck时出错,请稍后重试'); + return; + } } - // logger.info('ck------', match[0]) e.reply(`扫码登录成功,ck已自动保存`); clearInterval(intervalId); - return + return; } - pollCount++ - // logger.info('登录erweima',res) - }) + + pollCount++; + + } catch (error) { + logger.error('轮询过程中出错:', error); + clearInterval(intervalId); + e.reply('轮询过程中发生错误,请稍后再试'); + } + if (pollCount >= maxPolls) { clearInterval(intervalId); // 停止轮询 logger.info('超时轮询已停止'); From 6f809cd6ee3a3348895ee9da3c652824da293604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E5=88=80=E9=B1=BC?= <9903082+qdyovo@user.noreply.gitee.com> Date: Tue, 15 Oct 2024 16:45:19 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=8E=88=20pref:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 109 +++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/apps/tools.js b/apps/tools.js index cffe4c6..6c538ad 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -1380,61 +1380,62 @@ export class tools extends plugin { return true; } - // 网易云登录状态 - async neteaseStatus(e, reck) { - // 优先判断是否使用自建 API - let autoSelectNeteaseApi - // 判断海外 - const isOversea = await this.isOverseasServer(); - if (this.useLocalNeteaseAPI) { - // 使用自建 API - autoSelectNeteaseApi = this.neteaseCloudAPIServer - } else { - // 自动选择 API - autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN; - } - const statusUrl = autoSelectNeteaseApi + '/login/status' - axios.get(statusUrl, { - headers: { - "User-Agent": COMMON_USER_AGENT, - "Cookie": reck ? reck : this.neteaseCookie - }, - }).then(res => { - // logger.info('登录状态', res.data) - const userInfo = res.data.data.profile - if (userInfo) { - axios.get(`${autoSelectNeteaseApi}/vip/info?uid=${userInfo.userId}`, { - headers: { - "User-Agent": COMMON_USER_AGENT, - "Cookie": reck ? reck : this.neteaseCookie - }, - }).then(res => { - // logger.info('vip信息', res.data) - const vipInfo = res.data.data - if (vipInfo.redplus.vipCode != 0) { - const expireTime = new Date(vipInfo.redplus.expireTime); - if (expireTime > Date.now()) { - e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nSVIP${vipInfo.redplus.vipLevel}\n最高解析音质:\njymaster(超清母带)\n会员到期时间:\n${expireTime.toLocaleString()}`]); - } else { - e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\standard(标准)`]); - } - } else if (vipInfo.associator.vipCode != 0) { - const expireTime = new Date(vipInfo.associator.expireTime); - if (expireTime > Date.now()) { - e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP${vipInfo.associator.vipLevel}\n最高解析音质:\nlossless(无损)\n会员到期时间:\n${expireTime.toLocaleString()}`]); - } else { - e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\standard(标准)`]); - } - } else { - e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\standard(标准)`]); - } - }) - // e.reply([segment.image(userInfo.avatarUrl), `网易云已登录:${userInfo.nickname}\n会员等级:\n`,segment.image(vipInfo.iconUrl)]); - } else { - e.reply('暂未登录,请发#网易云扫码登陆进行登陆绑定ck') - } - }) +// 网易云登录状态 +async neteaseStatus(e, reck) { + // 优先判断是否使用自建 API + let autoSelectNeteaseApi + // 判断海外 + const isOversea = await this.isOverseasServer(); + if (this.useLocalNeteaseAPI) { + // 使用自建 API + autoSelectNeteaseApi = this.neteaseCloudAPIServer + } else { + // 自动选择 API + autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN; } + const statusUrl = autoSelectNeteaseApi + '/login/status' + axios.get(statusUrl, { + headers: { + "User-Agent": COMMON_USER_AGENT, + "Cookie": reck ? reck : this.neteaseCookie + }, + }).then(res => { + logger.info('登录状态', res.data) + const userInfo = res.data.data.profile + if (userInfo) { + axios.get(`${autoSelectNeteaseApi}/vip/info?uid=${userInfo.userId}`, { + headers: { + "User-Agent": COMMON_USER_AGENT, + "Cookie": reck ? reck : this.neteaseCookie + }, + }).then(res => { + logger.info('vip信息', res.data) + const vipInfo = res.data.data + const checkVipStatus = (vipLevel, expireTime, nickname, avatarUrl, e) => { + const expireDate = new Date(expireTime); + if (expireDate > Date.now()) { + e.reply([segment.image(`${avatarUrl}?param=170y170`), `网易云已登录:\n${nickname}\n会员等级:\n${vipLevel}\n会员到期时间:\n${expireDate.toLocaleString()}`]); + } else { + return false; // 返回 false 以继续检查下一个 VIP 状态 + } + return true; + }; + + if (vipInfo.redplus.vipCode != 0 && checkVipStatus(`SVIP${vipInfo.redplus.vipLevel}\n最高解析音质:\n jymaster(超清母带)`, vipInfo.redplus.expireTime, userInfo.nickname, userInfo.avatarUrl, e)) { + // SVIP 有效,不执行后续逻辑 + } else if (vipInfo.associator.vipCode != 0 && checkVipStatus(`VIP${vipInfo.associator.vipLevel}\n最高解析音质:\n jyeffect(高清环绕音)`, vipInfo.associator.expireTime, userInfo.nickname, userInfo.avatarUrl, e)) { + // VIP 有效,不执行后续逻辑 + } else { + // 如果都已过期,发送 VIP 已过期信息 + e.reply([segment.image(`${userInfo.avatarUrl}?param=170y170`), `网易云已登录:\n${userInfo.nickname}\n会员等级:\nVIP已过期\n最高解析音质:\nstandard(标准)`]); + } + }) + // e.reply([segment.image(userInfo.avatarUrl), `网易云已登录:${userInfo.nickname}\n会员等级:\n`,segment.image(vipInfo.iconUrl)]); + } else { + e.reply('暂未登录,请发#网易云扫码登陆进行登陆绑定ck') + } + }) +} // 网易扫码登录 async netease_scan(e) { // 优先判断是否使用自建 API From 8241707af4eb8015e3f79b6b7a1e278d8aaa99a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E5=88=80=E9=B1=BC?= <9903082+qdyovo@user.noreply.gitee.com> Date: Tue, 15 Oct 2024 16:52:31 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=8E=88=20pref:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=BD=91=E6=98=93=E4=BA=91=E6=AD=8C=E6=9B=B2=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E7=AD=96=E7=95=A5=EF=BC=8C=E6=94=AF=E6=8C=81=E6=9B=B4=E9=AB=98?= =?UTF-8?q?=E9=9F=B3=E8=B4=A8=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 96 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 16 deletions(-) diff --git a/apps/tools.js b/apps/tools.js index 6c538ad..7b10b52 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -1400,7 +1400,7 @@ async neteaseStatus(e, reck) { "Cookie": reck ? reck : this.neteaseCookie }, }).then(res => { - logger.info('登录状态', res.data) + // logger.info('登录状态', res.data) const userInfo = res.data.data.profile if (userInfo) { axios.get(`${autoSelectNeteaseApi}/vip/info?uid=${userInfo.userId}`, { @@ -1409,7 +1409,7 @@ async neteaseStatus(e, reck) { "Cookie": reck ? reck : this.neteaseCookie }, }).then(res => { - logger.info('vip信息', res.data) + // logger.info('vip信息', res.data) const vipInfo = res.data.data const checkVipStatus = (vipLevel, expireTime, nickname, avatarUrl, e) => { const expireDate = new Date(expireTime); @@ -1479,7 +1479,7 @@ async neteaseStatus(e, reck) { "User-Agent": COMMON_USER_AGENT, }, }); - logger.info('轮询状态', res.data); + // logger.info('轮询状态', res.data); if (res.data.code == '800') { e.reply("二维码过期,请重新获取"); clearInterval(intervalId); @@ -1512,7 +1512,7 @@ async neteaseStatus(e, reck) { e.reply('轮询过程中发生错误,请稍后再试'); } - if (pollCount >= maxPolls) { + if (pollCount > maxPolls) { clearInterval(intervalId); // 停止轮询 logger.info('超时轮询已停止'); e.reply('扫码超时,请重新获取'); @@ -1547,10 +1547,34 @@ async neteaseStatus(e, reck) { logger.error("[R插件][网易云解析] 没有找到id,无法进行下一步!") return } + // 优先判断是否使用自建 API + let autoSelectNeteaseApi // 判断海外 const isOversea = await this.isOverseasServer(); - // 自动选择 API - const autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN; + if (this.useLocalNeteaseAPI) { + // 使用自建 API + autoSelectNeteaseApi = this.neteaseCloudAPIServer + } else { + // 自动选择 API + autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN; + } + // 检测ck可用性 + const statusUrl = autoSelectNeteaseApi + '/login/status' + const isCkExpired = await axios.get(statusUrl, { + headers: { + "User-Agent": COMMON_USER_AGENT, + "Cookie": this.neteaseCookie + }, + }).then(res => { + const userInfo = res.data.data.profile + if (userInfo) { + logger.info('ck活着,使用ck进行高音质下载') + return true + } else { + logger.info('ck失效,将启用临时接口下载') + return false + } + }) // mv截断 if (message.includes("mv")) { const AUTO_NETEASE_MV_DETAIL = autoSelectNeteaseApi + "/mv/detail?mvid={}"; @@ -1561,50 +1585,90 @@ async neteaseStatus(e, reck) { axios.get(AUTO_NETEASE_MV_DETAIL.replace("{}", id), { headers: { "User-Agent": COMMON_USER_AGENT, + "Cookie": this.neteaseCookie } }), axios.get(AUTO_NETEASE_MV_URL.replace("{}", id), { headers: { "User-Agent": COMMON_USER_AGENT, + "Cookie": this.neteaseCookie } }) ]); const { name: mvName, artistName: mvArtist, cover: mvCover } = mvDetailData.data?.data; - e.reply([segment.image(mvCover), `${ this.identifyPrefix }识别:网易云MV,${ mvName } - ${ mvArtist }`]); + e.reply([segment.image(mvCover), `${this.identifyPrefix}识别:网易云MV,${mvName} - ${mvArtist}`]); // logger.info(mvUrlData.data) const { url: mvUrl } = mvUrlData.data?.data; this.downloadVideo(mvUrl).then(path => { - this.sendVideoToUpload(e, `${ path }/temp.mp4`) + this.sendVideoToUpload(e, `${path}/temp.mp4`) }); return; } // 国内解决方案,替换为国内API (其中,NETEASE_API_CN是国内基址) - const AUTO_NETEASE_SONG_DOWNLOAD = autoSelectNeteaseApi + "/song/url?id={}"; + const AUTO_NETEASE_SONG_DOWNLOAD = autoSelectNeteaseApi + "/song/url/v1?id={}&level=" + this.neteaseCloudAudioQuality; const AUTO_NETEASE_SONG_DETAIL = autoSelectNeteaseApi + "/song/detail?ids={}"; // logger.info(AUTO_NETEASE_SONG_DOWNLOAD.replace("{}", id)); + const downloadUrl = AUTO_NETEASE_SONG_DOWNLOAD.replace("{}", id) + const detailUrl = AUTO_NETEASE_SONG_DETAIL.replace("{}", id) // 请求netease数据 - axios.get(AUTO_NETEASE_SONG_DOWNLOAD.replace("{}", id), { + axios.get(downloadUrl, { headers: { "User-Agent": COMMON_USER_AGENT, + "Cookie": this.neteaseCookie }, }).then(async resp => { // 国内解决方案,替换API后这里也需要修改 + + // 英转中字典匹配 + const translationDict = { + 'standard': '标准', + 'higher': '较高', + 'exhigh': '极高', + 'lossless': '无损', + 'hires': 'Hi-Res', + 'jyeffect': '高清环绕声', + 'sky': '沉浸环绕声', + 'dolby': '杜比全景声', + 'jymaster': '超清母带' + }; + + // 英转中 + function translateToChinese(word) { + return translationDict[word] || word; // 如果找不到对应翻译,返回原词 + } + + // 字节转MB + function bytesToMB(sizeInBytes) { + const sizeInMB = sizeInBytes / (1024 * 1024); // 1 MB = 1024 * 1024 bytes + return sizeInMB.toFixed(2); // 保留两位小数 + } + let url = await resp.data.data?.[0]?.url || null; + // logger.info('获取信息url', resp.data.data?.[0]?.url); + // logger.info('获取信息', resp.data.data?.[0]); + const AudioLevel = translateToChinese(resp.data.data?.[0]?.level) + const AudioSize = bytesToMB(resp.data.data?.[0]?.size) // 获取歌曲信息 - let title = await axios.get(AUTO_NETEASE_SONG_DETAIL.replace("{}", id)).then(res => { + let title = await axios.get(detailUrl).then(res => { + // logger.info('歌曲详情---', res.data.songs[0]) const song = res.data.songs[0]; - return cleanFilename(`${ song?.name }-${ song?.ar?.[0].name }`); + return cleanFilename(`${song?.name}-${song?.ar?.[0].name}`); + }); + // 获取歌曲封面 + let coverUrl = await axios.get(detailUrl).then(res => { + const song = res.data.songs[0]; + return song?.al?.picUrl }); // 一般这个情况是VIP歌曲 (如果没有url或者是国内, 国内全走临时接口,后续如果不要删除逻辑'!isOversea ||') - if (!isOversea || url == null) { + if (!isCkExpired || url == null) { url = await this.musicTempApi(e, title, "网易云音乐"); } else { // 不是VIP歌曲,直接识别完就下一步 - e.reply(`${ this.identifyPrefix }识别:网易云音乐,${ title }`); + e.reply([segment.image(coverUrl), `${this.identifyPrefix}识别:网易云音乐,${title}\n当前下载音质: ${AudioLevel}\n预估大小: ${AudioSize}MB`]); } // 动态判断后缀名 const extensionPattern = /\.([a-zA-Z0-9]+)$/; - const musicExt = url.match(extensionPattern)?.[0].replace("\.", ""); + let musicExt = url.match(extensionPattern)?.[0].replace("\.", ""); // 下载音乐 downloadAudio(url, this.getCurDownloadPath(e), title, 'follow', musicExt).then(async path => { // 发送语音 @@ -1614,7 +1678,7 @@ async neteaseStatus(e, reck) { // 删除文件 await checkAndRemoveFile(path); }).catch(err => { - logger.error(`下载音乐失败,错误信息为: ${ err.message }`); + logger.error(`下载音乐失败,错误信息为: ${err}`); }); }); return true; From 131c2ca16f93de8596e3b255243a6444fdfdc39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E5=88=80=E9=B1=BC?= <9903082+qdyovo@user.noreply.gitee.com> Date: Tue, 15 Oct 2024 16:56:21 +0800 Subject: [PATCH 5/6] =?UTF-8?q?pref:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/tools.js b/apps/tools.js index 7b10b52..a97d5e4 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -1644,8 +1644,6 @@ async neteaseStatus(e, reck) { } let url = await resp.data.data?.[0]?.url || null; - // logger.info('获取信息url', resp.data.data?.[0]?.url); - // logger.info('获取信息', resp.data.data?.[0]); const AudioLevel = translateToChinese(resp.data.data?.[0]?.level) const AudioSize = bytesToMB(resp.data.data?.[0]?.size) // 获取歌曲信息 @@ -1659,11 +1657,11 @@ async neteaseStatus(e, reck) { const song = res.data.songs[0]; return song?.al?.picUrl }); - // 一般这个情况是VIP歌曲 (如果没有url或者是国内, 国内全走临时接口,后续如果不要删除逻辑'!isOversea ||') + // 一般这个情况是VIP歌曲 (如果没有url或者是国内,没有ck的走临时接口) if (!isCkExpired || url == null) { url = await this.musicTempApi(e, title, "网易云音乐"); } else { - // 不是VIP歌曲,直接识别完就下一步 + // 拥有ck,并且有效,直接进行解析 e.reply([segment.image(coverUrl), `${this.identifyPrefix}识别:网易云音乐,${title}\n当前下载音质: ${AudioLevel}\n预估大小: ${AudioSize}MB`]); } // 动态判断后缀名 From 1c651b8df139f29ad42f8696c8dbc447b12f51e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E5=88=80=E9=B1=BC?= <9903082+qdyovo@user.noreply.gitee.com> Date: Tue, 15 Oct 2024 17:06:35 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=8E=88=20pref:=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tools.js b/apps/tools.js index a97d5e4..766553a 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -221,7 +221,7 @@ export class tools extends plugin { permission: 'master', }, { - reg: "^#(网易云扫码登录|网易扫码登录)$", + reg: "^#(网易云扫码登录|网易扫码登录|网易登录|网易云登录)$", fnc: 'netease_scan', permission: 'master', },