diff --git a/apps/check-car.js b/apps/check-car.js
new file mode 100644
index 0000000..63843ae
--- /dev/null
+++ b/apps/check-car.js
@@ -0,0 +1,137 @@
+import _ from 'lodash'
+import { createRequire } from 'module'
+
+const setimetu = 60 //消息撤回时间
+
+//作者MiX
+//使用前请用电脑浏览器打开https://whatslink.info/,然后获取到cookie填入第45行以获得更高的请求。
+
+export class checkCar extends plugin {
+ constructor() {
+ super({
+ name: '验车',
+ dsc: '验车',
+ event: 'message',
+ priority: -100,
+ rule: [
+ {
+ reg: '^#验车(.*?)',
+ fnc: 'yc'
+ },
+ ]
+ })
+ }
+
+
+ async yc(e) {
+ // 检查用户是否为管理员,如果不是则回复相应消息并返回。取消注释即仅主人可用
+ //if (!e.isMaster) {
+ // e.reply("涩批!不给你看😡", true);
+ // return true;
+ //}
+
+ // 从消息中提取关键词
+ let tag = e.msg.replace(/#验车/g, "");
+ const tags = `磁力:${tag}`;
+
+ // 构造获取涩图的URL
+ const api = `https://whatslink.info/api/v1/link?url=${tag}`;
+ const options = {
+ method: 'GET',
+ headers: ({
+ 'Accept': 'application/json, text/plain, */*',
+ 'Accept-Encoding': 'gzip, deflate, br',
+ 'Accept-Language': 'zh-CN,zh;q=0.9',
+ 'Connection': 'keep-alive',
+ 'Cookie': 'aliyungf_tc=786a8710254a682250630ad426a4b444be3d405cfbdaa1e6e9b98f6d94487eb1',
+ 'Host': 'whatslink.info',
+ 'Referer': 'https://whatslink.info/',
+ 'Sec-Ch-Ua': '"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"',
+ 'Sec-Ch-Ua-Mobile': '?0',
+ 'Sec-Ch-Ua-Platform': '"Windows"',
+ 'Sec-Fetch-Dest': 'empty',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Sec-Fetch-Site': 'same-origin',
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
+ })
+ };
+
+ // 使用fetch获取数据
+ const response = await fetch(api, options);
+ const data = await response.json();
+ logger.info('验车data----------', data)
+ const screenshots = data.screenshots
+ if (screenshots === null) {
+ await e.reply(data.name, false, { recallMsg: setimetu })
+ return true
+ } else {
+ const jsonusedata = data.screenshots.map(item => ({
+ url: item.screenshot,
+ }));
+ const image = []
+ for (const { url } of jsonusedata) {
+ image.push({
+ urls: segment.image(url),
+ }
+ );
+ }
+
+ // 构造回复消息
+ let type = `文件类型:${data.file_type}`
+ let Msg = await this.makeForwardMsg(e, [tags, data.name, type, image]);
+ // e.reply(await Bot.makeForwardMsg(image))
+ await e.reply(Msg);
+ // await e.reply(Msg, false, { recallMsg: setimetu });
+ return true;
+ }
+ }
+
+ async makeForwardMsg(e, msg = [], dec = '') {
+ let userInfo = {
+ nickname: e.nickname,
+ user_id: e.user_id
+ }
+
+ let forwardMsg = []
+ msg.forEach(v => {
+ if (Array.isArray(v)) {
+ v.forEach(vv => {
+ forwardMsg.push({
+ ...userInfo,
+ message: vv.urls
+ })
+ })
+ } else {
+ forwardMsg.push({
+ ...userInfo,
+ message: v
+ })
+ }
+ })
+
+ if (e.isGroup) {
+ forwardMsg = await e.group.makeForwardMsg(forwardMsg)
+ } else if (e.friend) {
+ forwardMsg = await e.friend.makeForwardMsg(forwardMsg)
+ } else {
+ return false
+ }
+
+ if (dec) {
+ if (typeof (forwardMsg.data) === 'object') {
+ let detail = forwardMsg.data?.meta?.detail
+ if (detail) {
+ detail.news = [{ text: dec }]
+ }
+ } else {
+ forwardMsg.data = forwardMsg.data
+ .replace('', '')
+ .replace(/\n/g, '')
+ .replace(/
(.+?)<\/title>/g, '___')
+ .replace(/___+/, `${dec}`)
+ }
+
+ }
+ return forwardMsg
+ }
+}
diff --git a/apps/deep-faker2.js b/apps/deep-faker2.js
new file mode 100644
index 0000000..5f1b9a3
--- /dev/null
+++ b/apps/deep-faker2.js
@@ -0,0 +1,72 @@
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
+
+import fs from "fs";
+import axios from 'axios'
+
+const DOWNLOAD_PATH = "./data/";
+const GPTSOVITS_HOST = "https://cn-sy-bgp-plustmp1.natfrp.cloud:49918"
+
+const voiceList = Object.freeze([
+ "雷军",
+])
+
+export class example extends plugin {
+ constructor () {
+ super({
+ name: '语音包',
+ dsc: '语音包',
+ // 匹配的消息类型,参考https://oicqjs.github.io/oicq/#events
+ event: 'message',
+ priority: 5000,
+ rule: [
+ {
+ reg: `^(${voiceList.join('|')})说(.*)`,
+ fnc: 'voicePack'
+ },
+ {
+ reg: "^语音列表$",
+ fnc: 'voiceList'
+ }
+ ]
+ })
+ }
+
+ async voicePack(e) {
+ const parts = e.msg.trim()
+ const part1 = parts.split("说", 1)[0];
+ const part2 = parts.substring(parts.indexOf("说") + 1).replaceAll(" ", ",");
+
+ // Data payload
+ const data = {
+ text: part2,
+ text_language: "zh"
+ };
+
+ // Make the POST request
+ axios.post(GPTSOVITS_HOST, data, { responseType: 'arraybuffer' })
+ .then(response => {
+ if (response.status === 400) {
+ throw new Error(`请求GPTSoVITS出现错误: ${response.data.message}`);
+ }
+
+ // Write the content to a file
+ fs.writeFile(DOWNLOAD_PATH + "voicePack.wav", response.data, (err) => {
+ if (err) throw err;
+ e.reply(segment.record(fs.readFileSync(DOWNLOAD_PATH + "voicePack.wav")));
+ });
+ })
+ .catch(error => {
+ console.error('Error:', error.message);
+ });
+ return true
+ }
+
+ async voiceList(e) {
+ e.reply(Bot.makeForwardMsg([{
+ message: { type: "text", text: voiceList.join("\n") },
+ nickname: e.sender.card || e.user_id,
+ user_id: e.user_id,
+ }]));
+ return true
+ }
+}
diff --git a/apps/kimi.js b/apps/kimi.js
new file mode 100644
index 0000000..5919952
--- /dev/null
+++ b/apps/kimi.js
@@ -0,0 +1,177 @@
+import config from "../model/config.js";
+import puppeteer from "../../../lib/puppeteer/puppeteer.js";
+import fs from "fs";
+import { marked } from "marked"
+
+async function markdownRender(e, query, aiContent) {
+ // 打开一个新的页面
+ const browser = await puppeteer.browserInit();
+ const page = await browser.newPage();
+
+ if (aiContent.indexOf("搜索结果来自:") !== -1) {
+ aiContent = aiContent.split("搜索结果来自:")[0];
+ }
+
+ const htmlContent = `
+
+
+
+
+ Kimi Chat Interface
+
+
+
+
+
+

+
+
+
+

+
+
+

+
+
${ marked.parse(aiContent) }
+
+
+
+
+`;
+ await page.setViewport({
+ width: 1280,
+ height: 720,
+ deviceScaleFactor: 10, // 根据显示器的分辨率调整比例,2 是常见的 Retina 显示比例
+ });
+ // 设置页面内容为包含 Base64 图片的 HTML
+ await page.setContent(htmlContent, {
+ waitUntil: "networkidle0",
+ });
+ // 获取页面上特定元素的位置和尺寸
+ const element = await page.$(".chat-container"); // 可以用CSS选择器选中你要截取的部分
+ // 直接截图该元素
+ await element.screenshot({
+ path: "./chat.png",
+ type: "jpeg",
+ fullPage: false,
+ omitBackground: false,
+ quality: 50,
+ });
+ await e.reply(segment.image(fs.readFileSync("./chat.png")));
+}
+
+export class kimiJS extends plugin {
+ constructor() {
+ super({
+ name: 'Moonshot AI',
+ dsc: 'Moonshot AI Assistant',
+ event: 'message',
+ priority: 1,
+ rule: [
+ {
+ reg: '^#kimi(.*)$',
+ fnc: 'chat'
+ }
+ ]
+ });
+ // 配置文件
+ this.toolsConfig = config.getConfig("tools");
+ // 设置基础 URL 和 headers
+ this.baseURL = this.toolsConfig.aiBaseURL;
+ this.headers = {
+ "Content-Type": "application/json",
+ "Authorization": "Bearer " + this.toolsConfig.aiApiKey
+ };
+ }
+
+ async chat(e) {
+ const query = e.msg.replace(/^#kimi/, '').trim();
+ // 请求Kimi
+ const completion = await fetch(this.baseURL + "/v1/chat/completions", {
+ method: 'POST',
+ headers: this.headers,
+ body: JSON.stringify({
+ model: "moonshot-v1-8k",
+ messages: [
+ {
+ "role": "system",
+ "content": this.prompt,
+ },
+ {
+ role: "user",
+ content: query
+ },
+ ],
+ }),
+ timeout: 100000
+ });
+ await markdownRender(e, query, (await completion.json()).choices[0].message.content, true);
+ return true;
+ }
+}
diff --git a/apps/songRequest.js b/apps/songRequest.js
new file mode 100644
index 0000000..a4f058a
--- /dev/null
+++ b/apps/songRequest.js
@@ -0,0 +1,238 @@
+import axios from "axios";
+import { formatTime } from '../utils/other.js'
+import puppeteer from "../../../lib/puppeteer/puppeteer.js";
+import PickSongList from "../model/pick-song.js";
+import { NETEASE_API_CN, NETEASE_SONG_DOWNLOAD, NETEASE_TEMP_API } from "../constants/tools.js";
+import { COMMON_USER_AGENT, REDIS_YUNZAI_ISOVERSEA, REDIS_YUNZAI_SONGINFO } from "../constants/constant.js";
+import { } from "../utils/common.js";
+import { redisExistKey, redisGetKey, redisSetKey } from "../utils/redis-util.js";
+import { checkAndRemoveFile } from "../utils/file.js";
+import config from "../model/config.js";
+
+export class songRequest extends plugin {
+ constructor() {
+ super({
+ name: "R插件点歌",
+ dsc: "实现快捷点歌",
+ priority: 300,
+ rule: [
+ {
+ reg: '^点歌|#听[1-9][0-9]|#听[0-9]*$',
+ fnc: 'pickSong'
+ },
+ {
+ reg: "^播放(.*)",
+ fnc: "playSong"
+ },
+ ]
+ });
+ this.toolsConfig = config.getConfig("tools");
+ // 加载网易云Cookie
+ this.neteaseCookie = this.toolsConfig.neteaseCookie
+ // 加载是否自建服务器
+ this.useLocalNeteaseAPI = this.toolsConfig.useLocalNeteaseAPI
+ // 加载自建服务器API
+ this.neteaseCloudAPIServer = this.toolsConfig.neteaseCloudAPIServer
+ // 加载网易云解析最高音质
+ this.neteaseCloudAudioQuality = this.toolsConfig.neteaseCloudAudioQuality
+ // 加载识别前缀
+ this.identifyPrefix = this.toolsConfig.identifyPrefix;
+ }
+
+ // 判断是否海外服务器
+ async isOverseasServer() {
+ // 如果第一次使用没有值就设置
+ if (!(await redisExistKey(REDIS_YUNZAI_ISOVERSEA))) {
+ await redisSetKey(REDIS_YUNZAI_ISOVERSEA, {
+ os: false,
+ })
+ return true;
+ }
+ // 如果有就取出来
+ return (await redisGetKey(REDIS_YUNZAI_ISOVERSEA)).os;
+ }
+
+ async pickSong(e) {
+ const isOversea = await this.isOverseasServer();
+ let autoSelectNeteaseApi
+ if (this.useLocalNeteaseAPI) {
+ // 使用自建 API
+ autoSelectNeteaseApi = this.neteaseCloudAPIServer
+ } else {
+ // 自动选择 API
+ autoSelectNeteaseApi = isOversea ? NETEASE_SONG_DOWNLOAD : NETEASE_API_CN;
+ }
+ let songInfo = []
+
+ // 获取搜索歌曲列表信息
+
+ let searchUrl = autoSelectNeteaseApi + '/search?keywords={}&limit=10' //搜索API
+ let detailUrl = autoSelectNeteaseApi + "/song/detail?ids={}" //歌曲详情API
+ if (e.msg.replace(/\s+/g, "").match(/点歌(.+)/)) {
+ const songKeyWord = e.msg.replace(/\s+/g, "").match(/点歌(.+)/)[1]
+ searchUrl = searchUrl.replace("{}", songKeyWord)
+ await axios.get(searchUrl, {
+ headers: {
+ "User-Agent": COMMON_USER_AGENT
+ },
+ }).then(async res => {
+ if (res.data.result.songs) {
+ for (const info of res.data.result.songs) {
+ songInfo.push({
+ 'id': info.id,
+ 'songName': info.name,
+ 'singerName': info.artists[0]?.name,
+ 'duration': formatTime(info.duration)
+ });
+ }
+ const ids = songInfo.map(item => item.id).join(',');
+ detailUrl = detailUrl.replace("{}", ids)
+ await axios.get(detailUrl, {
+ headers: {
+ "User-Agent": COMMON_USER_AGENT
+ },
+ }).then(res => {
+ for (let i = 0; i < res.data.songs.length; i++) {
+ songInfo[i].cover = res.data.songs[i].al.picUrl
+ }
+ })
+ await redisSetKey(REDIS_YUNZAI_SONGINFO, songInfo)
+ const data = await new PickSongList(e).getData(songInfo)
+ let img = await puppeteer.screenshot("pick-song", data);
+ e.reply(img, true);
+ } else {
+ e.reply('暂未找到你想听的歌哦~')
+ }
+ })
+ } else if (await redisGetKey(REDIS_YUNZAI_SONGINFO) != []) {
+ if (e.msg.match(/#听(\d+)/)) {
+ const pickNumber = e.msg.match(/#听(\d+)/)[1] - 1
+ let songInfo = await redisGetKey(REDIS_YUNZAI_SONGINFO)
+ const AUTO_NETEASE_SONG_DOWNLOAD = autoSelectNeteaseApi + "/song/url/v1?id={}&level=" + this.neteaseCloudAudioQuality;
+ const pickSongUrl = AUTO_NETEASE_SONG_DOWNLOAD.replace("{}", songInfo[pickNumber].id)
+ const statusUrl = autoSelectNeteaseApi + '/login/status' //用户状态API
+ 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
+ }
+ })
+ // // 请求netease数据
+ axios.get(pickSongUrl, {
+ 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); // 保留两位小数
+ }
+ logger.info('下载歌曲详情-----------', resp.data.data)
+ let url = await resp.data.data?.[0]?.url || null;
+ const AudioLevel = translateToChinese(resp.data.data?.[0]?.level)
+ const AudioSize = bytesToMB(resp.data.data?.[0]?.size)
+ // 获取歌曲信息
+ let title = songInfo[pickNumber].songName + '-' + songInfo[pickNumber].singerName
+ // 一般这个情况是VIP歌曲 (如果没有url或者是国内,公用接口暂时不可用,必须自建并且ck可用状态才能进行高质量解析)
+ if (!isCkExpired || !this.useLocalNeteaseAPI || url == null) {
+ url = await this.musicTempApi(e, title, "网易云音乐");
+ } else {
+ // 拥有ck,并且有效,直接进行解析
+ let audioInfo = AudioLevel;
+ if (AudioLevel == '杜比全景声') {
+ audioInfo += '\n(杜比下载文件为MP4,编码格式为AC-4,需要设备支持才可播放)';
+ }
+ e.reply([segment.image(songInfo[pickNumber].cover), `${this.identifyPrefix}识别:网易云音乐,${title}\n当前下载音质: ${audioInfo}\n预估大小: ${AudioSize}MB`]);
+ }
+ // 动态判断后缀名
+ let musicExt = resp.data.data?.[0]?.type
+ // 下载音乐
+ downloadAudio(url, this.getCurDownloadPath(e), title, 'follow', musicExt).then(async path => {
+ // 发送语音
+ if (musicExt != 'mp4') {
+ await e.reply(segment.record(path));
+ }
+ // 上传群文件
+ await this.uploadGroupFile(e, path);
+ // 删除文件
+ await checkAndRemoveFile(path);
+ }).catch(err => {
+ logger.error(`下载音乐失败,错误信息为: ${err}`);
+ });
+ });
+ }
+ }
+
+ }
+
+ async musicTempApi(e, title, musicType) {
+ let musicReqApi = NETEASE_TEMP_API;
+ // 临时接口,title经过变换后搜索到的音乐质量提升
+ const vipMusicData = await axios.get(musicReqApi.replace("{}", title.replace("-", " ")), {
+ headers: {
+ "User-Agent": COMMON_USER_AGENT,
+ },
+ });
+ const messageTitle = title + "\nR插件检测到当前为VIP音乐,正在转换...";
+ // ??后的内容是适配`QQ_MUSIC_TEMP_API`、最后是汽水
+ const url = vipMusicData.data?.music_url ?? vipMusicData.data?.data?.music_url ?? vipMusicData.data?.music;
+ const cover = vipMusicData.data?.cover ?? vipMusicData.data?.data?.cover ?? vipMusicData.data?.cover;
+ await e.reply([segment.image(cover), `${this.identifyPrefix}识别:${musicType},${messageTitle}`]);
+ return url;
+ }
+
+ /**
+ * 获取当前发送人/群的下载路径
+ * @param e Yunzai 机器人事件
+ * @returns {string}
+ */
+ getCurDownloadPath(e) {
+ return `${this.defaultPath}${e.group_id || e.user_id}`
+ }
+
+ /**
+ * 上传到群文件
+ * @param e 交互事件
+ * @param path 上传的文件所在路径
+ * @return {Promise}
+ */
+ async uploadGroupFile(e, path) {
+ // 判断是否是ICQQ
+ if (e.bot?.sendUni) {
+ await e.group.fs.upload(path);
+ } else {
+ await e.group.sendFile(path);
+ }
+ }
+}
\ No newline at end of file
diff --git a/config/help.yaml b/config/help.yaml
index cadb3fd..d65fc7e 100644
--- a/config/help.yaml
+++ b/config/help.yaml
@@ -21,61 +21,61 @@
- group: 工具类合集
list:
- icon: translate
- title: "翻中/英/日 xxx"
+ title: 翻中/英/日 xxx
desc: R插件翻译引擎
- icon: tiktok
- title: "douyin"
+ title: douyin
desc: 抖音分享实时下载
- icon: bilibili
- title: "哔哩哔哩"
+ title: 哔哩哔哩
desc: 哔哩哔哩分享实时下载
- icon: bqrcode
title: "#rbq/#RBQ"
desc: R插件B站扫码
- icon: applemusic
- title: "Apple Music"
+ title: Apple Music
desc: Apple Music音乐分享实时下载
- icon: youtube
- title: "油管"
+ title: 油管
desc: 油管学习版分享实时下载
- icon: twitter
- title: "小蓝鸟"
+ title: 小蓝鸟
desc: 推特学习版分享实时下载
- icon: acfun
- title: "acfun"
+ title: acfun
desc: 猴山分享实时下载
- icon: redbook
- title: "小红书"
+ title: 小红书
desc: 小红书分享实时下载
- icon: kuaishou
- title: "快手(测试阶段)"
+ title: 快手(测试阶段)
desc: 快手分享实时下载
- icon: xigua
- title: "西瓜(测试阶段)"
+ title: 西瓜(测试阶段)
desc: 西瓜分享实时下载
- icon: miyoushe
- title: "米游社"
+ title: 米游社
desc: 米游社文章分享实时下载
- icon: weibo
- title: "微博"
+ title: 微博
desc: 微博文章分享实时下载
- icon: zuiyou
- title: "最右(测试阶段)"
+ title: 最右(测试阶段)
desc: 最右分享实时下载
- icon: pipi
- title: "皮皮虾(测试阶段)"
+ title: 皮皮虾(测试阶段)
desc: 皮皮虾分享实时下载
- icon: bodian
- title: "波点音乐"
+ title: 波点音乐
desc: 波点云音乐点解析
- icon: spotify
- title: "Spotify"
+ title: Spotify
desc: 解析Spotify音乐
- icon: telegram
- title: "小飞机(学习版)"
+ title: 小飞机(学习版)
desc: 解析小飞机
- group: 其他指令
list:
- icon: update
title: "#R插件更新"
- desc: "进行更新R插件"
\ No newline at end of file
+ desc: 进行更新R插件
diff --git a/config/tools.yaml b/config/tools.yaml
index f3f0c8b..267ebdf 100644
--- a/config/tools.yaml
+++ b/config/tools.yaml
@@ -1,50 +1,87 @@
-defaultPath: './data/rcmp4/' # 保存视频的位置
-videoSizeLimit: 70 # 视频大小限制(单位MB),超过大小则转换成群文件上传
-proxyAddr: '127.0.0.1' # 魔法地址
-proxyPort: '7890' # 魔法端口
-identifyPrefix: '' # 识别前缀,比如你识别哔哩哔哩,那么就有:✅ 识别:哔哩哔哩
-
-deeplApiUrls: 'http://www.gptspt.cn/translate,http://gptspt.top/translate,http://8.134.135.4:1188/translate,http://120.76.141.173:1188/translate,http://bit.x7ys.com:1188/translate,http://deeplxapi.x7ys.com:1188/translate'
-
-streamDuration: 10 # 视频最大时长(单位秒)
-streamCompatibility: false # 兼容模式,NCQQ不用开,其他ICQQ、LLO需要开启
-
-biliSessData: '' # 哔哩哔哩的SESSDATA
-biliIntroLenLimit: 50 # 哔哩哔哩简介长度限制,填 0 或者 -1 可以不做任何限制,显示完整简介
-biliDuration: 480 # 哔哩哔哩限制的最大视频时长(默认8分钟),单位:秒
-biliDisplayCover: true # 是否显示哔哩哔哩的封面
-biliDisplayInfo: true # 是否显示哔哩哔哩的视频信息
-biliDisplayIntro: true # 是否显示哔哩哔哩的简介
-biliDisplayOnline: true # 是否显示哔哩哔哩的在线人数
-biliDisplaySummary: false # 是否显示哔哩哔哩的总结
-biliUseBBDown: false # 是否使用BBDown,默认不开启,开启后使用强劲的BBDown下载最高画质
-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)
-youtubeClipTime: 0 # YouTobe限制的最大视频时长(默认不开启),单位:秒 最好不要超过5分钟,否则截取效率非常低
-youtubeDuration: 480 # YouTobe限制的最大视频时长(默认8分钟),单位:秒 最好不要超过30分钟,否则截取效率非常低
-
-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;
-douyinCompression: true # true-压缩,false-不压缩;是否使用压缩视频格式的抖音(默认使用),使用后加速视频发送
-douyinComments: false # true-开启评论,false-关闭评论
-
-xiaohongshuCookie: '' # 2024-8-2后反馈必须使用ck,不然无法解析
-
-queueConcurrency: 1 # 【目前只涉及哔哩哔哩的下载】根据服务器性能设置可以并发下载的个数,如果你的服务器比较强劲,就选择4~12,较弱就一个一个下载,选择1
-
-videoDownloadConcurrency: 1 # 下载视频是否使用多线程,如果不使用默认是1,如果使用根据服务器进行选择,如果不确定是否可以用4即可,高性能服务器随意4~12都可以,看CPU的实力
-
-lagrangeForwardWebSocket: 'ws://127.0.0.1:9091/' # 格式:ws://地址:端口/,拉格朗日正向连接地址,用于适配拉格朗日上传群文件,解决部分用户无法查看视频问题
-
-autoclearTrashtime: '0 0 8 * * ?' #每天早上8点自动清理视频缓存,cron可自定义时间
-
-aiBaseURL: '' # 用于识图的接口,kimi默认接口为:https://api.moonshot.cn,其他服务商自己填写
-aiApiKey: '' # 用于识图的api key,kimi接口申请:https://platform.moonshot.cn/console/api-keys
-aiModel: 'moonshot-v1-8k' # 模型,使用kimi不用填写,其他要填写
+defaultPath: ./data/rcmp4/
+videoSizeLimit: 100
+proxyAddr: 127.0.0.1
+proxyPort: "7890"
+identifyPrefix: ✅
+deeplApiUrls: http://www.gptspt.cn/translate,http://gptspt.top/translate,http://8.134.135.4:1188/translate,http://120.76.141.173:1188/translate,http://bit.x7ys.com:1188/translate,http://deeplxapi.x7ys.com:1188/translate
+streamDuration: 10
+streamCompatibility: false
+biliSessData: a56d470f%2C1744730590%2C813e6%2Aa2CjAD_PFOxMcmeZ40kSD03f6j1kTArPuM-cpVjnSK_5azosYAuZxGAeQ3RzK7Eh0O40ESVlJsUkxTWDlFVEY3VGNTU1dtWEFEQmh4TER3OW5UQ3FOTzBWSkx5WXYzTFBoai1nTEpwMVprek5BNlJic3g2RWhYVTRqNXJFME9WX1p1U1RoMGQ1Qkh3IIEC
+biliIntroLenLimit: 50
+biliDuration: 900
+biliDisplayCover: true
+biliDisplayInfo: true
+biliDisplayIntro: true
+biliDisplayOnline: true
+biliDisplaySummary: false
+biliUseBBDown: true
+biliCDN: 0
+biliDownloadMethod: 0
+biliResolution: 2
+useLocalNeteaseAPI: true
+neteaseCookie: MUSIC_U=000B6FB760D4DD0C8FF579D22EF13F4631A662365882A1DCB227B306A50E274E5A93061745A36AB27D85F9EFF82699A34BA6DF9B311AF9C52EF096F512D8BE274001B1D0064FEE95158AD7BDE28CD277212FA99569D0B94ADB14281355C80E2C0A730F49304C257AD0E16492F253EA47B91D64206344527DD9768454C27343D73ACFB59B13830B6FD6F367B69EDE875796CED7958CFF653AF87E7F3FEFCF43B8D9E7C75C9494F8C31C553B64A23357E2B59A07B8D7AFFAC1234589DD0C338C7DAD7A36407D36933A6DA7F21F7E975A271E65D5C38805CFE3AE3D7E55588E64DDB2D94A719FABA9464A54E78F699182728206C72D5A10FF9D1E5BF2C4DDFB7E47F61723DDE3ABF47A5D6352E2EDC984BA1A4767B7BB4F8E8D018E6ACDB1D71D85694D29B8C4DBF0C6072CD2127EA7D94348;
+ os=pc
+neteaseCloudAPIServer: http://www.qdy.ink:55522
+neteaseCloudAudioQuality: jymaster
+youtubeGraphicsOptions: 1080
+youtubeClipTime: null
+youtubeDuration: 900
+douyinCookie: ttwid=1%7CGlKor0s7yJTURXYA5X9sbAgunYFVfBoVLX9v2mfAyhQ%7C1694051452%7C80e7c98a8473faed6f881b7379f7e29405be10e9ac35b7618cc43adf8a1a2f41;
+ SEARCH_RESULT_LIST_TYPE=%22single%22;
+ UIFID_TEMP=1ee16134db40129a5ff28e6a352dddaa8524f48fc5e4ea6d697d6a182d7836e449f664cfb29d1099cfb2fb62ce7db5e6a4fd0aeafe0c2afd30fa1e97fa68fc67ff8e51c3904b654300f5021c7159cd6a;
+ s_v_web_id=verify_m0up87e5_t8ChctxF_3HK0_4e2k_9UKg_49HT0IC3Hsab;
+ hevc_supported=true; passport_csrf_token=0197d3b34f027df28862da61991c0eb7;
+ passport_csrf_token_default=0197d3b34f027df28862da61991c0eb7;
+ bd_ticket_guard_client_web_domain=2;
+ fpk1=U2FsdGVkX19oyd9PX2fmFVaSJiFDZTknfNeDgrBL+oovtUMKhA6vexuXHj6gEF9IWKs8iyFJc5r4PmS7QmyiKQ==;
+ fpk2=e8db1a910ee088b469ecfd2b6a9b9da5;
+ UIFID=1ee16134db40129a5ff28e6a352dddaa8524f48fc5e4ea6d697d6a182d7836e4b80abacd6e9013b4a4043a401aab353263551bdef6fcabc5b1891e33448cae02c056b0c65c2758ee92ffbde2996c98ba87eddf939a7e91224bfc962944ab939cefb96fb42fb2482f40658d2ca65e0ee68131f8082f360cbcec35bb06f7d444bb5ef3e84cacc65df726cc55e14e3d6a959699a997c4f9a9a39cbfe63f07bd93ad;
+ d_ticket=22c8797c4bb92fa7f9198fff1c949b98a0750;
+ passport_assist_user=Cj8lyV9Z6D9MR1YIPSuyBTmq-MkkfDC_ino72STrLztUelhMSlxQmhu1hWD4SKT5fXqnn9h8Pf-2PoTcZD7AYesaSgo8CWitJ5ebWoBSMtxmNtbczFA-fU49bNw_ESDcASSVeTGd74mnRUFwlknjTqR-OKcWuJGtiWTCmdLeFF1WEMjR2w0Yia_WVCABIgEDk97NRw%3D%3D;
+ n_mh=6PqAsBDwpWzjjhyh0DJxbjfHwLWX-QGpUHXGB71culA;
+ sso_uid_tt=17ce377d8953b76136b51d2c8c476936;
+ sso_uid_tt_ss=17ce377d8953b76136b51d2c8c476936;
+ toutiao_sso_user=cc92e6a4f4c0e72e261228be675000cc;
+ toutiao_sso_user_ss=cc92e6a4f4c0e72e261228be675000cc;
+ sid_ucp_sso_v1=1.0.0-KGU2MTMxNDkyZDY0MzM3YjJhOWI1Mzg2NzYyYTM0Yzk5OTc5YTcwZTYKIAi50eCEpM0CEOTP-rYGGO8xIAwwyZKQrQY4AkDxB0gGGgJsZiIgY2M5MmU2YTRmNGMwZTcyZTI2MTIyOGJlNjc1MDAwY2M;
+ ssid_ucp_sso_v1=1.0.0-KGU2MTMxNDkyZDY0MzM3YjJhOWI1Mzg2NzYyYTM0Yzk5OTc5YTcwZTYKIAi50eCEpM0CEOTP-rYGGO8xIAwwyZKQrQY4AkDxB0gGGgJsZiIgY2M5MmU2YTRmNGMwZTcyZTI2MTIyOGJlNjc1MDAwY2M;
+ uid_tt=e890963c895ad76636236d4ee7bd8012;
+ uid_tt_ss=e890963c895ad76636236d4ee7bd8012;
+ sid_tt=c39dac16eb6c7b7e864503b9cc06bfa6;
+ sessionid=c39dac16eb6c7b7e864503b9cc06bfa6;
+ sessionid_ss=c39dac16eb6c7b7e864503b9cc06bfa6; is_staff_user=false;
+ _bd_ticket_crypt_doamin=2;
+ _bd_ticket_crypt_cookie=d94b00dc5003896c6a41e34592d484b8;
+ __security_server_data_status=1; store-region=cn-zj; store-region-src=uid;
+ SelfTabRedDotControl=%5B%5D;
+ FOLLOW_NUMBER_YELLOW_POINT_INFO=%22MS4wLjABAAAAuFw1NBpBldrgd6kUkSzXm882qpOX-nkmG2jMSHiXoxk%2F1728748800000%2F0%2F1728717264795%2F0%22;
+ sid_guard=c39dac16eb6c7b7e864503b9cc06bfa6%7C1728717275%7C5184000%7CWed%2C+11-Dec-2024+07%3A14%3A35+GMT;
+ sid_ucp_v1=1.0.0-KGFmNmNkNWVjZGEzM2JjM2ZkYjNhYmVjMDE5OTllZmFkNjI5NjFhY2IKGgi50eCEpM0CENvDqLgGGO8xIAw4AkDxB0gEGgJsZiIgYzM5ZGFjMTZlYjZjN2I3ZTg2NDUwM2I5Y2MwNmJmYTY;
+ ssid_ucp_v1=1.0.0-KGFmNmNkNWVjZGEzM2JjM2ZkYjNhYmVjMDE5OTllZmFkNjI5NjFhY2IKGgi50eCEpM0CENvDqLgGGO8xIAw4AkDxB0gEGgJsZiIgYzM5ZGFjMTZlYjZjN2I3ZTg2NDUwM2I5Y2MwNmJmYTY;
+ publish_badge_show_info=%220%2C0%2C0%2C1728717274522%22;
+ download_guide=%222%2F20241012%2F0%22; pwa2=%220%7C0%7C2%7C0%22;
+ __ac_nonce=0671204d000cf7a511d5;
+ __ac_signature=_02B4Z6wo00f01yb3HygAAIDDpuujdXSjLbcm1xuAAK664i8ozjg4YMd4AG2mOFHsO0Fd1E73.5lD6UR9uQBCgVA979LZPMOF2vQIAb-o024iWhuUuhVSQtIV4tDeNPYFOuzu5B6QgDXDwB-e37;
+ douyin.com; device_web_cpu_core=12; device_web_memory_size=8;
+ architecture=amd64; csrf_session_id=2264bbdaa769999e3eecc34c080de9b2;
+ strategyABtestKey=%221729234131.288%22;
+ volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Atrue%2C%22volume%22%3A0.5%7D;
+ biz_trace_id=0e5f258d; xg_device_score=7.802204888412783;
+ WallpaperGuide=%7B%22showTime%22%3A1729234135617%2C%22closeTime%22%3A0%2C%22showCount%22%3A2%2C%22cursor1%22%3A16%2C%22cursor2%22%3A4%7D;
+ odin_tt=dbdf6a7f9f8c2fb70be9c86c7caca90a829c468db4ef92e609be2988c736b84cc19ce0736278c3f7153f2fd21c9927d3;
+ passport_fe_beating_status=false;
+ stream_player_status_params=%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A1%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A0%7D%22;
+ IsDouyinActive=true; home_can_add_dy_2_desktop=%220%22; dy_swidth=1920;
+ dy_sheight=1080;
+ stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1920%2C%5C%22screen_height%5C%22%3A1080%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A12%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A100%7D%22;
+ bd_ticket_guard_client_data=eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCTjFqYW5GbHBBUXBIeDhoTGtBYmgzQVBNdmhvWXllazI1OTY5WEVmc2xiYnIvcmdTeGQ2bHRlUUsyL25mWFVQWHRzUExhRG8rNjlQUkRMOGNIT21Xdnc9IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoyfQ%3D%3D
+douyinCompression: true
+douyinComments: true
+xiaohongshuCookie: xsecappid=xhs-pc-web;acw_tc=350c17ac654c7a6669103ccf2dd453f9b24be9618e26768e1dc000632195acb0;websectiga=3633fe24d49c7dd0eb923edc8205740f10fdb18b25d424d2a2322c6196d2a4ad;webBuild=4.39.0;sec_poison_id=5a4ce41c-3934-4231-813e-89b9bcca9775;web_session=040069b66645392a9a51e64e27354bb4c13a46;gid=yjJjdKjJ0KvYyjJjdKjJ8lx0jKfxSK2349CY9IKfWAudux28iJ69Eu888y4yJ2Y8yJW4W2fd;a1=1929e692096dhc65i4tx8d7qzezf2mtwyothzhan650000141258;abRequestId=4592d5bf-bf0a-557f-837a-a4236e412134;unread={%22ub%22:%2266f6862e000000001a022a34%22%2C%22ue%22:%226705181f000000001a022078%22%2C%22uc%22:26};webId=c29b9c5db1577e152daaba1e9076a79b
+queueConcurrency: 1
+videoDownloadConcurrency: 12
+lagrangeForwardWebSocket: ws://127.0.0.1:9091/
+autoclearTrashtime: 0 0 8 * * ?
+aiBaseURL: http://localhost:8000
+aiApiKey: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyLWNlbnRlciIsImV4cCI6MTczNzQ0MDkyMiwiaWF0IjoxNzI5NjY0OTIyLCJqdGkiOiJjc2M5ZjZnamRvN2tndWN2cTZwMCIsInR5cCI6InJlZnJlc2giLCJhcHBfaWQiOiJraW1pIiwic3ViIjoiY3Mydjdrb25zbW1zdmRpYzc5M2ciLCJzcGFjZV9pZCI6ImNzMnY3a29uc21tc3ZkaWM3OTFnIiwiYWJzdHJhY3RfdXNlcl9pZCI6ImNzMnY3a29uc21tc3ZkaWM3OTEwIn0.tmu2lOu-4xQeI-8RhkF-SrObWjPLJ5mZAKahvlUnEzy3LL0dPZ_Ruwv5xpHCMIN-k0GnncXotZC5kIuNhEnyIg
+aiModel: moonshot-v1-8k
diff --git a/config/version.yaml b/config/version.yaml
index fa6b6f0..ee77fe8 100644
--- a/config/version.yaml
+++ b/config/version.yaml
@@ -1,13 +1,9 @@
-- {
- version: 1.9.2,
+- version: 1.9.2
data:
- [
- 新增RBS查看哔哩哔哩状态功能,
- 新增自建ncm功能,
- 新增直播切片功能,
- 支持锅巴插件,方便查看和修改配置,
- 输入#R帮助获取插件帮助,
- 输入#R更新更新插件,
- 输入#R版本获取插件版本,
- ],
-}
+ - 新增RBS查看哔哩哔哩状态功能
+ - 新增自建ncm功能
+ - 新增直播切片功能
+ - 支持锅巴插件,方便查看和修改配置
+ - 输入#R帮助获取插件帮助
+ - 输入#R更新更新插件
+ - 输入#R版本获取插件版本
diff --git a/constants/constant.js b/constants/constant.js
index 911768f..7e732e9 100644
--- a/constants/constant.js
+++ b/constants/constant.js
@@ -80,6 +80,13 @@ export const REDIS_YUNZAI_ISOVERSEA = "Yz:rconsole:tools:oversea";
*/
export const REDIS_YUNZAI_LAGRANGE = "Yz:rconsole:tools:lagrange";
+/**
+ * 缓存音乐搜索列表
+ * @type {string}
+ */
+export const REDIS_YUNZAI_SONGINFO = "Yz:rconsole:tools:songinfo";
+
+
/**
* 某些功能的解析白名单
* @type {string}
diff --git a/model/pick-song.js b/model/pick-song.js
new file mode 100644
index 0000000..af5be42
--- /dev/null
+++ b/model/pick-song.js
@@ -0,0 +1,17 @@
+import Base from './base.js'
+
+export default class PickSongList extends Base {
+ constructor (e) {
+ super(e)
+ this.model = 'pick-song'
+ }
+
+ /** 生成版本信息图片 */
+ async getData (songData) {
+ return {
+ ...this.screenData,
+ saveId: 'pick-song',
+ songData: songData,
+ }
+ }
+}
diff --git a/resources/font/江城月湖体 400W.ttf b/resources/font/江城月湖体 400W.ttf
new file mode 100644
index 0000000..d4f8237
Binary files /dev/null and b/resources/font/江城月湖体 400W.ttf differ
diff --git a/resources/html/pick-song/pick-song.css b/resources/html/pick-song/pick-song.css
new file mode 100644
index 0000000..9631a1b
--- /dev/null
+++ b/resources/html/pick-song/pick-song.css
@@ -0,0 +1,106 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;700&display=swap');
+
+@font-face {
+ font-family: 'number';
+ src: url("../../font/江城月湖体\ 400W.ttf");
+}
+
+body,
+html {
+ margin: 0;
+ padding: 0;
+ font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
+}
+
+.songList {
+ min-height: 50vh;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ background: #121212ef;
+ position: relative;
+ padding: 0px 40px 20px 40px;
+ box-sizing: border-box;
+}
+
+.songListNav {
+ box-sizing: border-box;
+ width: 100%;
+ height: 100px;
+ margin-top: 30px;
+ display: flex;
+ justify-content: space-between;
+ position: relative;
+ z-index: 2;
+}
+
+.navText {
+ font-size: 30px;
+ color: #fff;
+ margin-left: 20px;
+ width: 85%;
+}
+
+.songName{
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.singerText{
+ font-size: 25px;
+ color: #aaa;
+ margin-top: 5px;
+}
+
+
+.navInfo {
+ display: flex;
+ width: 80%;
+}
+
+.navDuration {
+ color: #aaa;
+ width: 40px;
+ font-size: 25px;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.navInfo img {
+ width: 90px;
+ height: 90px;
+ border-radius: 8px;
+}
+
+.bgicon {
+ position: absolute;
+ top: calc(50% - 100px);
+ left: calc(50% - 85px);
+ width: 200px;
+ height: 200px;
+ z-index: 1;
+}
+
+.bgicon img {
+ width: 100%;
+ height: 100%;
+ opacity: 0.4
+}
+
+.number {
+ width: 40px;
+ height: 100%;
+ display: flex;
+ flex-shrink: 0;
+ justify-content: center;
+ align-items: center;
+ font-size: 40px;
+ color: #fff;
+ margin-right: 25px;
+ margin-left: -20px;
+ font-family: 'number'
+}
\ No newline at end of file
diff --git a/resources/html/pick-song/pick-song.html b/resources/html/pick-song/pick-song.html
new file mode 100644
index 0000000..2108a98
--- /dev/null
+++ b/resources/html/pick-song/pick-song.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+ 搜索歌单
+
+
+
+
+
+ {{each songData info key}}
+
+
+
{{ key+1 }}
+

+
+
{{ info.songName }}
+
{{ info.singerName }}
+
+
+
{{ info.duration }}
+
+ {{ /each }}
+
+

+
+
+
+
+
\ No newline at end of file
diff --git a/resources/img/icon/neteaseRank.png b/resources/img/icon/neteaseRank.png
new file mode 100644
index 0000000..b1bf308
Binary files /dev/null and b/resources/img/icon/neteaseRank.png differ
diff --git a/utils/other.js b/utils/other.js
new file mode 100644
index 0000000..576b4d1
--- /dev/null
+++ b/utils/other.js
@@ -0,0 +1,11 @@
+export function formatTime(timestamp) {
+ const totalSeconds = Math.floor(timestamp / 1000); // 转换为秒
+ const minutes = Math.floor(totalSeconds / 60); // 分钟
+ const seconds = totalSeconds % 60; // 秒钟
+
+ // 补零格式化
+ const formattedMinutes = String(minutes).padStart(2, '0');
+ const formattedSeconds = String(seconds).padStart(2, '0');
+
+ return `${formattedMinutes}:${formattedSeconds}`;
+}
\ No newline at end of file