This commit is contained in:
N1KO 2024-12-16 15:02:11 +08:00
parent b6f3ff6dce
commit b5bd70e0df
5 changed files with 144 additions and 64 deletions

View File

@ -0,0 +1,16 @@
package top.baogutang.music.constants;
import java.util.Arrays;
import java.util.List;
/**
*
* @description:
*
* @author: N1KO
* @date: 2024/12/16 : 14:11
*/
public class BusinessKey {
public static final List<Long> ADMIN_ID_LIST = Arrays.asList(1L);
}

View File

@ -26,7 +26,7 @@ public class MusicDownloadController {
@Resource @Resource
private IMusicService musicService; private IMusicService musicService;
@GetMapping @PostMapping
@Vip @Vip
public Results<String> download(@RequestBody MusicDownloadReq req) { public Results<String> download(@RequestBody MusicDownloadReq req) {
String downloadUrl = musicService.getMusicService(req.getChannel()).downloads(req.getIdList(), UserThreadLocal.get()); String downloadUrl = musicService.getMusicService(req.getChannel()).downloads(req.getIdList(), UserThreadLocal.get());

View File

@ -31,6 +31,8 @@ import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import static top.baogutang.music.constants.BusinessKey.ADMIN_ID_LIST;
/** /**
* *
* @description: * @description:
@ -116,36 +118,54 @@ public abstract class AbstractMusicService<Q extends AbstractMusicReq, S extends
if (CollectionUtils.isEmpty(idList)) { if (CollectionUtils.isEmpty(idList)) {
throw new BusinessException("请选择下载内容"); throw new BusinessException("请选择下载内容");
} }
if (idList.size() > 100) { if (!ADMIN_ID_LIST.contains(userId) && idList.size() > 100) {
throw new BusinessException("单次下载限制最多100首"); throw new BusinessException("单次下载限制最多100首");
} }
ChannelEnum channelEnum = getChannelEnum(); ChannelEnum channelEnum = getChannelEnum();
ChannelClient<Q, S> channelClient = channelClientFactory.getClient(channelEnum); ChannelClient<Q, S> channelClient = channelClientFactory.getClient(channelEnum);
String batchNo = UUID.randomUUID().toString(); String batchNo = UUID.randomUUID().toString();
idList.stream() idList.forEach(id -> {
.map(id -> MusicRecordEntity entity = channelClient.queryByPlatform(id);
CompletableFuture.runAsync(() -> { if (Objects.nonNull(entity)) {
MusicDownloadRes res = channelClient.download(id); channelClient.saveDownloadRecord(userId, batchNo, id);
if (Objects.isNull(res)) { return;
log.error(">>>>>>>>>>query detail error! channel:{},song id:{}<<<<<<<<<<", channelEnum.getDesc(), id); }
return; MusicDownloadRes res = channelClient.download(id);
} if (Objects.isNull(res)) {
if (StringUtils.isNotBlank(res.getArtistName())) { log.error(">>>>>>>>>>query detail error! channel:{},song id:{}<<<<<<<<<<", channelEnum.getDesc(), id);
String[] split = res.getArtistName().split("/"); return;
String artistName = String.join(",", split); }
res.setArtistName(artistName); if (StringUtils.isNotBlank(res.getArtistName())) {
} String[] split = res.getArtistName().split("/");
channelClient.saveMusic(res); String artistName = String.join(",", split);
channelClient.saveDownloadRecord(userId, batchNo, id); res.setArtistName(artistName);
try { }
channelClient.processFile(res); channelClient.saveMusic(res);
log.info(">>>>>>>>>>download file:{} success<<<<<<<<<<", res.getName()); channelClient.saveDownloadRecord(userId, batchNo, id);
} catch (IOException e) { try {
log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e); channelClient.processFile(res);
throw new BusinessException("下载异常"); log.info(">>>>>>>>>>download file:{} success<<<<<<<<<<", res.getName());
} } catch (IOException e) {
})) log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e);
.forEach(CompletableFuture::join); throw new BusinessException("下载异常");
}
// CompletableFuture.runAsync(() -> {
// if (StringUtils.isNotBlank(res.getArtistName())) {
// String[] split = res.getArtistName().split("/");
// String artistName = String.join(",", split);
// res.setArtistName(artistName);
// }
// channelClient.saveMusic(res);
// channelClient.saveDownloadRecord(userId, batchNo, id);
// try {
// channelClient.processFile(res);
// log.info(">>>>>>>>>>download file:{} success<<<<<<<<<<", res.getName());
// } catch (IOException e) {
// log.error(">>>>>>>>>>download error:{}<<<<<<<<<<", e.getMessage(), e);
// throw new BusinessException("下载异常");
// }
// }, commonExecutor);
});
return batchNo; return batchNo;
} }

View File

@ -49,15 +49,15 @@ baogutang:
album-base-url: http://117.72.78.133:5173/album?id=%d album-base-url: http://117.72.78.133:5173/album?id=%d
artist-base-url: http://117.72.78.133:5173/artists?id=%d artist-base-url: http://117.72.78.133:5173/artists?id=%d
download-base-url: https://api.sooooooooooooooooootheby.top/Netease_url/Song_V1?level=jymaster&type=json&ids=%d download-base-url: https://api.sooooooooooooooooootheby.top/Netease_url/Song_V1?level=jymaster&type=json&ids=%d
# download-path: /downloads/music download-path: /downloads/music
download-path: /Users/nikooh/Desktop/downloads/music # download-path: /Users/nikooh/Desktop/downloads/music
qq-music: qq-music:
query-base-url: http://117.72.78.133:5175/search?key=%s&pageNo=%d&pageSize=%d&t=%d query-base-url: http://117.72.78.133:5175/search?key=%s&pageNo=%d&pageSize=%d&t=%d
playlist-base-url: http://117.72.78.133:5175/songlist?id=%s playlist-base-url: http://117.72.78.133:5175/songlist?id=%s
album-base-url: http://117.72.78.133:5175/album/songs?albummid=%s album-base-url: http://117.72.78.133:5175/album/songs?albummid=%s
download-base-url: http://117.72.78.133:5176/song?url=https://y.qq.com/n/ryqq/songDetail/%s download-base-url: http://117.72.78.133:5176/song?url=https://y.qq.com/n/ryqq/songDetail/%s
# download-path: /downloads/music download-path: /downloads/music
download-path: /Users/nikooh/Desktop/downloads/music # download-path: /Users/nikooh/Desktop/downloads/music

View File

@ -902,50 +902,94 @@
} }
function downloadSelected() { function downloadSelected() {
if (selectedSongs.length === 0) return; if (selectedSongs.length === 0) {
const channel = selectedPlatformCode; alert("请选择至少一首歌曲!");
return;
}
const channel = selectedPlatformCode; // 渠道编号
const progressContainer = document.getElementById('progress-container'); const progressContainer = document.getElementById('progress-container');
const progressBar = document.getElementById('progress-bar'); const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text'); const progressText = document.getElementById('progress-text');
// 初始化进度条
progressContainer.style.display = 'block'; progressContainer.style.display = 'block';
progressBar.value = 0; progressBar.value = 0;
progressText.textContent = '0%'; progressText.textContent = '0%';
let completedCount = 0; const fetchBatchAndDownloadFile = async () => {
const total = selectedSongs.length; try {
// 1. 调用第一个接口,获取 batchNo
const promises = selectedSongs.map(id => { const batchRequestBody = {
const url = `/api/v1/music/download?channel=${channel}&id=${id}`; channel: channel,
return fetch(url, { idList: selectedSongs, // 假设selectedSongs是歌曲ID列表
credentials: 'include' // 确保请求携带cookie };
}) const batchResponse = await fetch('/api/v1/music/download', {
.then(res => res.json()) method: 'POST',
.then(data => { headers: {
if (data.code === 200) { 'Content-Type': 'application/json',
// 下载成功,可以处理成功逻辑 },
} else if (data.code === -200) { body: JSON.stringify(batchRequestBody),
showMessage(data.msg); credentials: 'include',
}
completedCount++;
const percent = Math.floor((completedCount / total) * 100);
progressBar.value = percent;
progressText.textContent = percent + '%';
})
.catch(err => {
console.error(`下载ID:${id}时出错`, err);
completedCount++;
const percent = Math.floor((completedCount / total) * 100);
progressBar.value = percent;
progressText.textContent = percent + '%';
}); });
}); // const idListParam = selectedSongs.join(','); // 拼接ID集合
// const batchUrl = `/api/v1/music/download?channel=${channel}&idList=${encodeURIComponent(idListParam)}`;
//
// const batchResponse = await fetch(batchUrl, {
// method: 'GET',
// credentials: 'include',
// });
Promise.all(promises).then(() => { const batchData = await batchResponse.json();
progressBar.value = 100;
progressText.textContent = '100%'; if (batchData.code === 200) {
alert("下载完成!文件已存放到服务器指定目录中。"); const batchNo = batchData.data; // 成功获取 batchNo
});
// 更新进度条
progressBar.value = 50;
progressText.textContent = '50%';
// 2. 使用 batchNo 请求下载文件流
const fileUrl = `/api/v1/music/download/file?batchNo=${batchNo}&channel=${channel}`;
const fileResponse = await fetch(fileUrl, {
method: 'GET',
credentials: 'include',
});
if (fileResponse.ok) {
// 处理文件流并触发下载
const blob = await fileResponse.blob();
const objectUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = objectUrl;
a.download = 'music_files.zip'; // 下载文件名
document.body.appendChild(a);
a.click();
// 清理资源
window.URL.revokeObjectURL(objectUrl);
a.remove();
alert('文件下载成功!');
} else {
alert('文件下载失败,请稍后重试!');
}
} else {
alert(`批次号获取失败: ${batchData.msg}`);
}
} catch (error) {
console.error("下载过程中发生错误:", error);
alert("请求失败,请检查网络连接!");
} finally {
// 更新进度条为 100%
progressBar.value = 100;
progressText.textContent = '100%';
// alert("下载完成!");
}
};
// 调用主函数
fetchBatchAndDownloadFile();
} }
// 显示用户名 // 显示用户名