feat:新增点歌功能

This commit is contained in:
NikoYoke 2024-11-01 16:40:07 +08:00
parent 58ceb8f5dd
commit 9ae21c9bf3
14 changed files with 912 additions and 80 deletions

137
apps/check-car.js Normal file
View File

@ -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('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="utf-8" ?>')
.replace(/\n/g, '')
.replace(/<title color="#777777" size="26">(.+?)<\/title>/g, '___')
.replace(/___+/, `<title color="#777777" size="26">${dec}</title>`)
}
}
return forwardMsg
}
}

72
apps/deep-faker2.js Normal file
View File

@ -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
}
}

177
apps/kimi.js Normal file
View File

@ -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 = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kimi Chat Interface</title>
<style>
body {
background-color: #1a1a1a;
color: #ffffff;
margin: 0;
padding: 20px;
line-height: 1.6;
}
.chat-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.logo {
text-align: center;
margin-bottom: 20px;
}
.logo img {
max-width: 200px;
height: auto;
}
.message {
margin-bottom: 20px;
display: flex;
align-items: flex-start;
}
.avatar {
width: 36px;
height: 36px;
border-radius: 50%;
margin-right: 12px;
}
.message-content {
background-color: #2a2a2a;
border-radius: 18px;
padding: 12px 12px;
max-width: 70%;
font-size: 14px;
}
.user-message {
justify-content: flex-end;
}
.user-message .message-content {
background-color: #0066cc;
margin-right: 12px;
}
.ai-message .message-content {
background-color: #2a2a2a;
}
.user-message .avatar {
order: 1;
margin-right: 0;
margin-left: 12px;
}
pre {
background-color: #1e1e1e;
border-radius: 8px;
padding: 12px;
overflow-x: auto;
}
code {
font-family: 'Courier New', Courier, monospace;
font-size: 13px;
}
</style>
</head>
<body>
<div class="chat-container">
<div class="logo">
<img src="https://gitee.com/kyrzy0416/rconsole-plugin-complementary-set/raw/master/kimi/logo.png" alt="KIMI Logo">
</div>
<div class="message user-message">
<div class="message-content">
<p>${ query }</p>
</div>
<img src="http://q1.qlogo.cn/g?b=qq&nk=${ e.user_id }&s=100" alt="User Avatar" class="avatar">
</div>
<div class="message ai-message">
<img src="https://gitee.com/kyrzy0416/rconsole-plugin-complementary-set/raw/master/kimi/kimi.png" alt="AI Avatar" class="avatar">
<div class="message-content">
<div id="ai-content">${ marked.parse(aiContent) }</div>
</div>
</div>
</div>
</body>
</html>`;
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;
}
}

238
apps/songRequest.js Normal file
View File

@ -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<void>}
*/
async uploadGroupFile(e, path) {
// 判断是否是ICQQ
if (e.bot?.sendUni) {
await e.group.fs.upload(path);
} else {
await e.group.sendFile(path);
}
}
}

View File

@ -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插件"
desc: 进行更新R插件

View File

@ -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为原画1080720480自定义画面高度默认为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 keykimi接口申请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

View File

@ -1,13 +1,9 @@
- {
version: 1.9.2,
- version: 1.9.2
data:
[
新增<span class="cmd">RBS查看哔哩哔哩状态</span>功能,
新增<span class="cmd">自建ncm</span>功能,
新增<span class="cmd">直播切片</span>功能,
支持<span class="cmd">锅巴</span>插件,方便查看和修改配置,
输入<span class="cmd">#R帮助</span>获取插件帮助,
输入<span class="cmd">#R更新</span>更新插件,
输入<span class="cmd">#R版本</span>获取插件版本,
],
}
- 新增<span class="cmd">RBS查看哔哩哔哩状态</span>功能
- 新增<span class="cmd">自建ncm</span>功能
- 新增<span class="cmd">直播切片</span>功能
- 支持<span class="cmd">锅巴</span>插件,方便查看和修改配置
- 输入<span class="cmd">#R帮助</span>获取插件帮助
- 输入<span class="cmd">#R更新</span>更新插件
- 输入<span class="cmd">#R版本</span>获取插件版本

View File

@ -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}

17
model/pick-song.js Normal file
View File

@ -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,
}
}
}

Binary file not shown.

View File

@ -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'
}

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>搜索歌单</title>
<style>
@import url('{{pluResPath}}html/pick-song/pick-song.css');
</style>
</head>
<body>
<div class="songList">
{{each songData info key}}
<div class="songListNav">
<div class="navInfo">
<div class="number">{{ key+1 }}</div>
<img src="{{ info.cover }}" alt="">
<div class="navText">
<div class="songName">{{ info.songName }}</div>
<div class="singerText">{{ info.singerName }}</div>
</div>
</div>
<div class="navDuration">{{ info.duration }}</div>
</div>
{{ /each }}
<div class="bgicon">
<img src="{{pluResPath}}img/icon/neteaseRank.png" alt="">
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

11
utils/other.js Normal file
View File

@ -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}`;
}