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(/___+/, `<title color="#777777" size="26">${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 + + + +
+ +
+
+

${ query }

+
+ User Avatar +
+
+ AI Avatar +
+
${ 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}} +
+ + +
+ {{ /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