mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 16:19:18 +00:00
✨ feat: 新增群文件上传
This commit is contained in:
parent
05931a6586
commit
1671ab4cd7
@ -6,12 +6,14 @@ import PickSongList from "../model/pick-song.js";
|
|||||||
import NeteaseMusicInfo from '../model/neteaseMusicInfo.js'
|
import NeteaseMusicInfo from '../model/neteaseMusicInfo.js'
|
||||||
import { NETEASE_API_CN, NETEASE_SONG_DOWNLOAD, NETEASE_TEMP_API } from "../constants/tools.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, REDIS_YUNZAI_CLOUDSONGLIST } from "../constants/constant.js";
|
import { COMMON_USER_AGENT, REDIS_YUNZAI_ISOVERSEA, REDIS_YUNZAI_SONGINFO, REDIS_YUNZAI_CLOUDSONGLIST } from "../constants/constant.js";
|
||||||
import { downloadAudio } from "../utils/common.js";
|
import { downloadAudio, retryAxiosReq } from "../utils/common.js";
|
||||||
import { redisExistKey, redisGetKey, redisSetKey } from "../utils/redis-util.js";
|
import { redisExistKey, redisGetKey, redisSetKey } from "../utils/redis-util.js";
|
||||||
import { checkAndRemoveFile } from "../utils/file.js";
|
import { checkAndRemoveFile } from "../utils/file.js";
|
||||||
import { sendMusicCard } from "../utils/yunzai-util.js";
|
import { sendMusicCard, getGroupFileUrl } from "../utils/yunzai-util.js";
|
||||||
import config from "../model/config.js";
|
import config from "../model/config.js";
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
|
import NodeID3 from 'node-id3';
|
||||||
|
import { isError } from "node:util";
|
||||||
|
|
||||||
let FileSuffix = 'flac'
|
let FileSuffix = 'flac'
|
||||||
|
|
||||||
@ -53,6 +55,11 @@ export class songRequest extends plugin {
|
|||||||
reg: '^#?清除云盘缓存$',
|
reg: '^#?清除云盘缓存$',
|
||||||
fnc: 'cleanCloudData',
|
fnc: 'cleanCloudData',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#?获取群文件$',
|
||||||
|
fnc: 'getLatestDocument',
|
||||||
|
permission: 'master'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -95,16 +102,16 @@ export class songRequest extends plugin {
|
|||||||
const saveId = songInfo.findIndex(item => item.group_id === e.group.group_id)
|
const saveId = songInfo.findIndex(item => item.group_id === e.group.group_id)
|
||||||
let musicDate = { 'group_id': group_id, data: [] }
|
let musicDate = { 'group_id': group_id, data: [] }
|
||||||
// 获取搜索歌曲列表信息
|
// 获取搜索歌曲列表信息
|
||||||
let detailUrl = autoSelectNeteaseApi + "/song/detail?ids={}" //歌曲详情API
|
let detailUrl = autoSelectNeteaseApi + "/song/detail?ids={}&time=" + Date.now() //歌曲详情API
|
||||||
if (e.msg.replace(/\s+/g, "").match(/点歌(.+)/)) {
|
if (e.msg.replace(/\s+/g, "").match(/点歌(.+)/)) {
|
||||||
const songKeyWord = e.msg.replace(/\s+/g, "").match(/点歌(.+)/)[1]
|
const songKeyWord = e.msg.replace(/\s+/g, "").match(/点歌(.+)/)[1].replace(/[^\w\u4e00-\u9fa5]/g, '')
|
||||||
// 获取云盘歌单列表
|
// 获取云盘歌单列表
|
||||||
const cloudSongList = await this.getCloudSong()
|
const cloudSongList = await this.getCloudSong()
|
||||||
// 搜索云盘歌单并进行搜索
|
// 搜索云盘歌单并进行搜索
|
||||||
const matchedSongs = await cloudSongList.filter(({ songName, singerName }) =>
|
const matchedSongs = await cloudSongList.filter(({ songName, singerName }) =>
|
||||||
songName.includes(songKeyWord) || singerName.includes(songKeyWord)
|
songName.includes(songKeyWord) || singerName.includes(songKeyWord) || songName == songKeyWord || singerName == songKeyWord
|
||||||
);
|
);
|
||||||
// 计算列表数 计算偏移量
|
// 计算列表数
|
||||||
let songListCount = matchedSongs.length >= this.songRequestMaxList ? this.songRequestMaxList : matchedSongs.length
|
let songListCount = matchedSongs.length >= this.songRequestMaxList ? this.songRequestMaxList : matchedSongs.length
|
||||||
let searchCount = this.songRequestMaxList - songListCount
|
let searchCount = this.songRequestMaxList - songListCount
|
||||||
for (let i = 0; i < songListCount; i++) {
|
for (let i = 0; i < songListCount; i++) {
|
||||||
@ -317,51 +324,47 @@ export class songRequest extends plugin {
|
|||||||
const title = msg.message[0].data.match(/"title":"([^"]+)"/)[1]
|
const title = msg.message[0].data.match(/"title":"([^"]+)"/)[1]
|
||||||
const desc = msg.message[0].data.match(/"desc":"([^"]+)"/)[1]
|
const desc = msg.message[0].data.match(/"desc":"([^"]+)"/)[1]
|
||||||
if (id === "") return
|
if (id === "") return
|
||||||
let path = this.getCurDownloadPath(e) + '/' + title + '-' + desc + '.' + FileSuffix
|
let path = this.getCurDownloadPath(e) + '/' + desc + '-' + title + '.' + FileSuffix
|
||||||
let tryCount = 0
|
|
||||||
const tryUpload = async () => {
|
const tryUpload = async () => {
|
||||||
let formData = new FormData()
|
let formData = new FormData();
|
||||||
await formData.append('songFile', fs.createReadStream(path))
|
formData.append('songFile', fs.createReadStream(path));
|
||||||
const headers = {
|
const headers = {
|
||||||
...formData.getHeaders(),
|
...formData.getHeaders(),
|
||||||
'Cookie': this.neteaseCookie,
|
'Cookie': this.neteaseCookie,
|
||||||
};
|
};
|
||||||
const updateUrl = autoSelectNeteaseApi + `/cloud?time=${Date.now()}`
|
const updateUrl = `${autoSelectNeteaseApi}/cloud?time=${Date.now()}`;
|
||||||
axios({
|
try {
|
||||||
method: 'post',
|
const res = await axios({
|
||||||
url: updateUrl,
|
method: 'post',
|
||||||
headers: headers,
|
url: updateUrl,
|
||||||
data: formData,
|
headers: headers,
|
||||||
})
|
data: formData,
|
||||||
.then(async res => {
|
});
|
||||||
if (res.data.code == 200) {
|
if (res.data.code == 200) {
|
||||||
let matchUrl = autoSelectNeteaseApi + '/cloud/match?uid=' + this.uid + "&sid=" + res.data.privateCloud.songId + '&asid=' + id
|
let matchUrl = `${autoSelectNeteaseApi}/cloud/match?uid=${this.uid}&sid=${res.data.privateCloud.songId}&asid=${id}`;
|
||||||
await axios.get(matchUrl, {
|
try {
|
||||||
|
const matchRes = await axios.get(matchUrl, {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": COMMON_USER_AGENT,
|
"User-Agent": COMMON_USER_AGENT,
|
||||||
"Cookie": this.neteaseCookie
|
"Cookie": this.neteaseCookie
|
||||||
},
|
},
|
||||||
}).then(res => {
|
});
|
||||||
logger.info('歌曲信息匹配成功')
|
logger.info('歌曲信息匹配成功');
|
||||||
})
|
} catch (error) {
|
||||||
.catch(error => {
|
logger.error('歌曲信息匹配错误', error);
|
||||||
logger.error('歌曲信息匹配错误', error)
|
|
||||||
})
|
|
||||||
this.songCloudUpdate(e)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
tryCount += 1;
|
|
||||||
logger.info('失败喽~再试一次')
|
|
||||||
if (tryCount < 3) {
|
|
||||||
tryUpload(); // 直接调用
|
|
||||||
} else {
|
|
||||||
logger.error('怎么想都传不上去吧', error)
|
|
||||||
}
|
}
|
||||||
|
this.songCloudUpdate(e);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error('上传失败,响应不正确');
|
||||||
}
|
}
|
||||||
)
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
tryUpload();
|
await retryAxiosReq(() => tryUpload())
|
||||||
|
await checkAndRemoveFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取云盘歌单
|
// 获取云盘歌单
|
||||||
@ -380,10 +383,10 @@ export class songRequest extends plugin {
|
|||||||
"Cookie": this.neteaseCookie
|
"Cookie": this.neteaseCookie
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const songs = res.data.data.map(({ simpleSong }) => ({
|
const songs = res.data.data.map(({ songId, songName, artist }) => ({
|
||||||
'songName': simpleSong.name,
|
'songName': songName,
|
||||||
'id': simpleSong.id,
|
'id': songId,
|
||||||
'singerName': simpleSong.ar[0].name || '喵喵~',
|
'singerName': artist || '喵喵~',
|
||||||
'duration': '云盘'
|
'duration': '云盘'
|
||||||
}));
|
}));
|
||||||
songList.push(...songs);
|
songList.push(...songs);
|
||||||
@ -404,6 +407,70 @@ export class songRequest extends plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 群文件上传云盘
|
||||||
|
async getLatestDocument(e) {
|
||||||
|
const autoSelectNeteaseApi = await this.pickApi()
|
||||||
|
const cleanPath = await getGroupFileUrl(e)
|
||||||
|
logger.info(cleanPath)
|
||||||
|
// 拓展名
|
||||||
|
const extension = cleanPath.match(/\.\w+$/);
|
||||||
|
// 获取文件路径
|
||||||
|
const dirPath = cleanPath.substring(0, cleanPath.lastIndexOf('/'));
|
||||||
|
// 获取文件名
|
||||||
|
const fileName = cleanPath.split('/').pop().replace(/\.\w+$/, '');
|
||||||
|
logger.info(fileName)
|
||||||
|
const parts = fileName.match(/([\u4e00-\u9fa5a-zA-Z0-9]+)\s*-\s*([\u4e00-\u9fa5a-zA-Z0-9]+)/);
|
||||||
|
logger.info(parts)
|
||||||
|
logger.info(parts[1].trim())
|
||||||
|
const newFileName = dirPath + '/' + parts[2].trim() + extension
|
||||||
|
// 进行元数据编辑
|
||||||
|
if (parts) {
|
||||||
|
const tags = {
|
||||||
|
title: parts[2].trim(),
|
||||||
|
artist: parts[1].trim()
|
||||||
|
};
|
||||||
|
// 写入元数据
|
||||||
|
let success = NodeID3.write(tags, cleanPath)
|
||||||
|
if (fs.existsSync(newFileName)) {
|
||||||
|
logger.info(`音频已存在`);
|
||||||
|
fs.unlinkSync(newFileName);
|
||||||
|
}
|
||||||
|
// 文件重命名
|
||||||
|
fs.renameSync(cleanPath, newFileName)
|
||||||
|
if (success) logger.info('写入元数据成功')
|
||||||
|
} else {
|
||||||
|
logger.info('未按照标准命名')
|
||||||
|
}
|
||||||
|
// 上传请求
|
||||||
|
const tryUpload = async () => {
|
||||||
|
let formData = new FormData()
|
||||||
|
await formData.append('songFile', fs.createReadStream(newFileName))
|
||||||
|
const headers = {
|
||||||
|
...formData.getHeaders(),
|
||||||
|
'Cookie': this.neteaseCookie,
|
||||||
|
};
|
||||||
|
const updateUrl = autoSelectNeteaseApi + `/cloud?time=${Date.now()}`
|
||||||
|
try {
|
||||||
|
const res = await axios({
|
||||||
|
method: 'post',
|
||||||
|
url: updateUrl,
|
||||||
|
headers: headers,
|
||||||
|
data: formData,
|
||||||
|
});
|
||||||
|
this.songCloudUpdate(e);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 重试
|
||||||
|
await retryAxiosReq(() => tryUpload())
|
||||||
|
checkAndRemoveFile(newFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 清除缓存
|
||||||
async cleanCloudData(e) {
|
async cleanCloudData(e) {
|
||||||
await redisSetKey(REDIS_YUNZAI_CLOUDSONGLIST, [])
|
await redisSetKey(REDIS_YUNZAI_CLOUDSONGLIST, [])
|
||||||
}
|
}
|
||||||
@ -494,7 +561,7 @@ export class songRequest extends plugin {
|
|||||||
const AudioSize = bytesToMB(resp.data.data?.[0]?.size)
|
const AudioSize = bytesToMB(resp.data.data?.[0]?.size)
|
||||||
|
|
||||||
// 获取歌曲标题
|
// 获取歌曲标题
|
||||||
let title = songInfo[pickNumber].songName + '-' + songInfo[pickNumber].singerName
|
let title = songInfo[pickNumber].singerName + '-' + songInfo[pickNumber].songName
|
||||||
let typelist = []
|
let typelist = []
|
||||||
// 歌曲百科API
|
// 歌曲百科API
|
||||||
await axios.get(songWikiUrl, {
|
await axios.get(songWikiUrl, {
|
||||||
@ -503,24 +570,25 @@ export class songRequest extends plugin {
|
|||||||
// "Cookie": this.neteaseCookie
|
// "Cookie": this.neteaseCookie
|
||||||
},
|
},
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
const wikiData = res.data.data.blocks[1].creatives
|
const wikiData = res.data.data.blocks[1]?.creatives || []
|
||||||
|
if (wikiData[0]) {
|
||||||
typelist.push(wikiData[0].resources[0].uiElement.mainTitle.title)
|
typelist.push(wikiData[0].resources[0].uiElement.mainTitle.title)
|
||||||
// 防止数据过深出错
|
// 防止数据过深出错
|
||||||
const recTags = wikiData[1]
|
const recTags = wikiData[1]
|
||||||
if (recTags.resources[0]) {
|
if (recTags.resources[0]) {
|
||||||
for (let i = 0; i < Math.min(3, recTags.resources.length); i++) {
|
for (let i = 0; i < Math.min(3, recTags.resources.length); i++) {
|
||||||
if (recTags.resources[i] && recTags.resources[i].uiElement && recTags.resources[i].uiElement.mainTitle.title) {
|
if (recTags.resources[i] && recTags.resources[i].uiElement && recTags.resources[i].uiElement.mainTitle.title) {
|
||||||
typelist.push(recTags.resources[i].uiElement.mainTitle.title)
|
typelist.push(recTags.resources[i].uiElement.mainTitle.title)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (recTags.uiElement.textLinks[0].text) typelist.push(recTags.uiElement.textLinks[0].text)
|
||||||
|
}
|
||||||
|
if (wikiData[2].uiElement.mainTitle.title == 'BPM') {
|
||||||
|
typelist.push('BPM ' + wikiData[2].uiElement.textLinks[0].text)
|
||||||
|
} else {
|
||||||
|
typelist.push(wikiData[2].uiElement.textLinks[0].text)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (recTags.uiElement.textLinks[0].text) typelist.push(recTags.uiElement.textLinks[0].text)
|
|
||||||
}
|
|
||||||
if (wikiData[2].uiElement.mainTitle.title == 'BPM') {
|
|
||||||
typelist.push('BPM ' + wikiData[2].uiElement.textLinks[0].text)
|
|
||||||
} else {
|
|
||||||
typelist.push(wikiData[2].uiElement.textLinks[0].text)
|
|
||||||
}
|
}
|
||||||
typelist.push(AudioLevel)
|
typelist.push(AudioLevel)
|
||||||
})
|
})
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
"form-data": "^4.0.1",
|
"form-data": "^4.0.1",
|
||||||
|
"node-id3": "^0.2.6",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"p-queue": "^8.0.1"
|
"p-queue": "^8.0.1"
|
||||||
}
|
}
|
||||||
|
@ -34,3 +34,38 @@ export async function sendMusicCard(e, platformType, musicId) {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群文件Url地址
|
||||||
|
* @param e
|
||||||
|
* @param count 获取群聊条数
|
||||||
|
*/
|
||||||
|
|
||||||
|
export async function getGroupFileUrl(e, count = 10) {
|
||||||
|
const latestChat = await e.bot.sendApi("get_group_msg_history", {
|
||||||
|
"group_id": e.group_id,
|
||||||
|
"count": count
|
||||||
|
});
|
||||||
|
const messages = latestChat.data.messages;
|
||||||
|
let file_id = "";
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
const message = messages?.[i]?.message;
|
||||||
|
if (message?.[0]?.type === "file") {
|
||||||
|
file_id = message?.[0].data?.file_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file_id === "") {
|
||||||
|
logger.info('未找到群文件')
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// 获取文件信息
|
||||||
|
let latestFileUrl = await e.bot.sendApi("get_group_file_url", {
|
||||||
|
"group_id": e.group_id,
|
||||||
|
"file_id": file_id
|
||||||
|
});
|
||||||
|
let path = decodeURIComponent(latestFileUrl.data.url)
|
||||||
|
const cleanPath = path.startsWith('file:///') ? path.replace('file:///', '') : path;
|
||||||
|
return cleanPath
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user