page
This commit is contained in:
parent
914313944b
commit
814b4aff36
@ -267,13 +267,21 @@ public class QQMusicClient implements ChannelClient<MusicSearchReq, MusicSearchR
|
||||
|
||||
@Override
|
||||
public MusicDownloadRes download(String id) {
|
||||
String downloadUrl = String.format(qqMusicProperties.getDownloadBaseUrl(), id);
|
||||
String downloadUrl = String.format(qqMusicProperties.getDownloadBaseUrl1(), id);
|
||||
QQMusicDownloadRes qqMusicDownloadRes = OkHttpUtil.get(downloadUrl, null, null, new TypeReference<>() {
|
||||
});
|
||||
if (Objects.isNull(qqMusicDownloadRes) || Objects.isNull(qqMusicDownloadRes.getMusicUrlInfo())) {
|
||||
return null;
|
||||
downloadUrl = String.format(qqMusicProperties.getDownloadBaseUrl2(), id);
|
||||
qqMusicDownloadRes = OkHttpUtil.get(downloadUrl, null, null, new TypeReference<>() {
|
||||
});
|
||||
if (Objects.isNull(qqMusicDownloadRes) || Objects.isNull(qqMusicDownloadRes.getMusicUrlInfo())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return download(qqMusicDownloadRes);
|
||||
}
|
||||
|
||||
private MusicDownloadRes download(QQMusicDownloadRes qqMusicDownloadRes) {
|
||||
MusicDownloadRes musicDownloadRes = new MusicDownloadRes();
|
||||
musicDownloadRes.setAlbumName(qqMusicDownloadRes.getSong().getAlbum());
|
||||
musicDownloadRes.setArtistName(qqMusicDownloadRes.getSong().getSinger());
|
||||
|
||||
@ -22,7 +22,9 @@ public class QQMusicProperties {
|
||||
|
||||
private String albumBaseUrl;
|
||||
|
||||
private String downloadBaseUrl;
|
||||
private String downloadBaseUrl1;
|
||||
|
||||
private String downloadBaseUrl2;
|
||||
|
||||
private String downloadPath;
|
||||
|
||||
|
||||
@ -55,7 +55,8 @@ baogutang:
|
||||
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
|
||||
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-url1: http://117.72.78.133:5176/song?url=https://y.qq.com/n/ryqq/songDetail/%s
|
||||
download-base-url2: http://117.72.78.133:5176/song?url=https://u.y.qq.com/n/ryqq/songDetail/%s
|
||||
download-path: /downloads/music
|
||||
# download-path: /Users/nikooh/Desktop/downloads/music
|
||||
|
||||
|
||||
@ -241,8 +241,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 其他样式保持不变 */
|
||||
|
||||
.album-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -337,7 +335,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 歌单列表样式 */
|
||||
.playlist-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -435,13 +432,14 @@
|
||||
|
||||
<button class="search-btn" onclick="startSearch()">搜索</button>
|
||||
|
||||
<div class="search-result" id="result"></div>
|
||||
<div class="loading" id="loading" style="display: none;">加载中...</div>
|
||||
|
||||
<div class="progress-container" id="progress-container">
|
||||
<p>下载进度:<span id="progress-text">0%</span></p>
|
||||
<progress id="progress-bar" value="0" max="100"></progress>
|
||||
<!-- 将下载进度条移动到结果列表上方 -->
|
||||
<div class="search-result" id="result">
|
||||
<div class="progress-container" id="progress-container">
|
||||
<p>下载进度:<span id="progress-text">0%</span></p>
|
||||
<progress id="progress-bar" value="0" max="100"></progress>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loading" id="loading" style="display: none;">加载中...</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@ -470,7 +468,6 @@
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
displayUsername();
|
||||
|
||||
// 点击用户名时,切换下拉菜单的显示状态
|
||||
const userInfoDiv = document.getElementById('user-info');
|
||||
const dropdownMenu = document.getElementById('dropdown-menu');
|
||||
userInfoDiv.addEventListener('click', function (event) {
|
||||
@ -478,7 +475,6 @@
|
||||
dropdownMenu.classList.toggle('visible');
|
||||
});
|
||||
|
||||
// 点击页面其他部分时,隐藏下拉菜单
|
||||
document.addEventListener('click', function () {
|
||||
dropdownMenu.classList.remove('visible');
|
||||
});
|
||||
@ -486,7 +482,7 @@
|
||||
|
||||
function fetchPlatforms() {
|
||||
fetch('/api/v1/music/common?type=channel', {
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@ -522,7 +518,7 @@
|
||||
|
||||
function fetchSearchTypes() {
|
||||
fetch('/api/v1/music/common?type=searchType', {
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@ -569,11 +565,17 @@
|
||||
updateDownloadButton();
|
||||
|
||||
const resultDiv = document.getElementById('result');
|
||||
resultDiv.innerHTML = '';
|
||||
document.getElementById('progress-container').style.display = 'none';
|
||||
resultDiv.innerHTML = `
|
||||
<div class="progress-container" id="progress-container" style="display:none;">
|
||||
<p>下载进度:<span id="progress-text">0%</span></p>
|
||||
<progress id="progress-bar" value="0" max="100"></progress>
|
||||
</div>
|
||||
`; // 重置时也恢复进度条位置
|
||||
document.getElementById('progress-bar').value = 0;
|
||||
document.getElementById('progress-text').textContent = '0%';
|
||||
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
|
||||
fetchSearchData();
|
||||
}
|
||||
|
||||
@ -583,7 +585,7 @@
|
||||
|
||||
const keywords = document.getElementById('keywords').value.trim();
|
||||
fetch(`/api/v1/music/search?channel=${selectedPlatformCode}&keywords=${encodeURIComponent(keywords)}&type=${selectedSearchTypeCode}&offset=${offset}&limit=${limit}`, {
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@ -679,10 +681,21 @@
|
||||
|
||||
function displayAlbums(result, resultDiv) {
|
||||
const albums = result.albums || [];
|
||||
resultDiv.innerHTML = '';
|
||||
const albumList = document.createElement('div');
|
||||
albumList.className = 'album-list';
|
||||
resultDiv.appendChild(albumList);
|
||||
hasMore = result.hasMore || false;
|
||||
|
||||
let albumList = resultDiv.querySelector('.album-list');
|
||||
if (offset === 0) {
|
||||
// 保留progress-container,不清空整个result,而是清空其内部列表
|
||||
albumList = document.createElement('div');
|
||||
albumList.className = 'album-list';
|
||||
resultDiv.appendChild(albumList);
|
||||
} else {
|
||||
if (!albumList) {
|
||||
albumList = document.createElement('div');
|
||||
albumList.className = 'album-list';
|
||||
resultDiv.appendChild(albumList);
|
||||
}
|
||||
}
|
||||
|
||||
albums.forEach(album => {
|
||||
const albumItem = document.createElement('div');
|
||||
@ -706,14 +719,28 @@
|
||||
|
||||
albumList.appendChild(albumItem);
|
||||
});
|
||||
|
||||
if (hasMore) {
|
||||
offset += limit;
|
||||
}
|
||||
}
|
||||
|
||||
function displayArtists(result, resultDiv) {
|
||||
const artists = result.artists || [];
|
||||
resultDiv.innerHTML = '';
|
||||
const artistList = document.createElement('div');
|
||||
artistList.className = 'artist-list';
|
||||
resultDiv.appendChild(artistList);
|
||||
hasMore = result.hasMore || false;
|
||||
|
||||
let artistList = resultDiv.querySelector('.artist-list');
|
||||
if (offset === 0) {
|
||||
artistList = document.createElement('div');
|
||||
artistList.className = 'artist-list';
|
||||
resultDiv.appendChild(artistList);
|
||||
} else {
|
||||
if (!artistList) {
|
||||
artistList = document.createElement('div');
|
||||
artistList.className = 'artist-list';
|
||||
resultDiv.appendChild(artistList);
|
||||
}
|
||||
}
|
||||
|
||||
artists.forEach(artist => {
|
||||
const artistItem = document.createElement('div');
|
||||
@ -730,22 +757,29 @@
|
||||
|
||||
artistList.appendChild(artistItem);
|
||||
});
|
||||
|
||||
if (hasMore) {
|
||||
offset += limit;
|
||||
}
|
||||
}
|
||||
|
||||
function displayPlaylists(result, resultDiv) {
|
||||
const playlists = result.playlists || [];
|
||||
hasMore = result.hasMore || false;
|
||||
|
||||
let playlistList = resultDiv.querySelector('.playlist-list');
|
||||
if (offset === 0) {
|
||||
// 第一次加载清空
|
||||
resultDiv.innerHTML = '';
|
||||
const playlistList = document.createElement('div');
|
||||
playlistList = document.createElement('div');
|
||||
playlistList.className = 'playlist-list';
|
||||
resultDiv.appendChild(playlistList);
|
||||
} else {
|
||||
if (!playlistList) {
|
||||
playlistList = document.createElement('div');
|
||||
playlistList.className = 'playlist-list';
|
||||
resultDiv.appendChild(playlistList);
|
||||
}
|
||||
}
|
||||
|
||||
const playlistList = resultDiv.querySelector('.playlist-list');
|
||||
|
||||
playlists.forEach(pl => {
|
||||
const playlistItem = document.createElement('div');
|
||||
playlistItem.className = 'playlist-item';
|
||||
@ -768,14 +802,20 @@
|
||||
|
||||
function fetchAlbumSongs(albumId) {
|
||||
fetch(`/api/v1/music/search/album?channel=${selectedPlatformCode}&id=${albumId}`, {
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.code === 200) {
|
||||
const songsData = data.data?.songs || [];
|
||||
const resultDiv = document.getElementById('result');
|
||||
resultDiv.innerHTML = '';
|
||||
// 清空除progress外的内容
|
||||
resultDiv.innerHTML = `
|
||||
<div class="progress-container" id="progress-container" style="display:none;">
|
||||
<p>下载进度:<span id="progress-text">0%</span></p>
|
||||
<progress id="progress-bar" value="0" max="100"></progress>
|
||||
</div>
|
||||
`;
|
||||
allSongs = [];
|
||||
selectedSongs = [];
|
||||
const result = {
|
||||
@ -794,14 +834,19 @@
|
||||
|
||||
function fetchArtistSongs(artistId) {
|
||||
fetch(`/api/v1/music/search/artist?channel=${selectedPlatformCode}&id=${artistId}`, {
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.code === 200) {
|
||||
const hotSongs = data.data?.hotSongs || [];
|
||||
const resultDiv = document.getElementById('result');
|
||||
resultDiv.innerHTML = '';
|
||||
resultDiv.innerHTML = `
|
||||
<div class="progress-container" id="progress-container" style="display:none;">
|
||||
<p>下载进度:<span id="progress-text">0%</span></p>
|
||||
<progress id="progress-bar" value="0" max="100"></progress>
|
||||
</div>
|
||||
`;
|
||||
allSongs = [];
|
||||
selectedSongs = [];
|
||||
const result = {
|
||||
@ -819,16 +864,20 @@
|
||||
}
|
||||
|
||||
function fetchPlaylistSongs(playlistId) {
|
||||
// 获取歌单歌曲数据,返回 data.songs
|
||||
fetch(`/api/v1/music/search/playlist?channel=${selectedPlatformCode}&id=${playlistId}`, {
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.code === 200) {
|
||||
const songsData = data.data?.songs || [];
|
||||
const resultDiv = document.getElementById('result');
|
||||
resultDiv.innerHTML = '';
|
||||
resultDiv.innerHTML = `
|
||||
<div class="progress-container" id="progress-container" style="display:none;">
|
||||
<p>下载进度:<span id="progress-text">0%</span></p>
|
||||
<progress id="progress-bar" value="0" max="100"></progress>
|
||||
</div>
|
||||
`;
|
||||
allSongs = [];
|
||||
selectedSongs = [];
|
||||
const result = {
|
||||
@ -850,13 +899,8 @@
|
||||
const windowHeight = window.innerHeight;
|
||||
const bodyHeight = document.body.scrollHeight;
|
||||
|
||||
// 当搜索类型是单曲(1)或者歌单(1000)且有更多数据时,下拉加载更多
|
||||
// 这里假设歌单也可以分页获取更多数据,在返回的result.hasMore中判断
|
||||
// 若需要对不同类型单独判断分页逻辑,可根据实际需求调整
|
||||
if (scrollTop + windowHeight >= bodyHeight - 100 && hasMore && !loading) {
|
||||
if (selectedSearchTypeCode == "1" || selectedSearchTypeCode == "1000") {
|
||||
fetchSearchData();
|
||||
}
|
||||
fetchSearchData();
|
||||
}
|
||||
}
|
||||
|
||||
@ -907,22 +951,20 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = selectedPlatformCode; // 渠道编号
|
||||
const channel = selectedPlatformCode;
|
||||
const progressContainer = document.getElementById('progress-container');
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const progressText = document.getElementById('progress-text');
|
||||
|
||||
// 初始化进度条
|
||||
progressContainer.style.display = 'block';
|
||||
progressBar.value = 0;
|
||||
progressText.textContent = '0%';
|
||||
|
||||
const fetchBatchAndDownloadFile = async () => {
|
||||
try {
|
||||
// 1. 调用第一个接口,获取 batchNo
|
||||
const batchRequestBody = {
|
||||
channel: channel,
|
||||
idList: selectedSongs, // 假设selectedSongs是歌曲ID列表
|
||||
idList: selectedSongs
|
||||
};
|
||||
const batchResponse = await fetch('/api/v1/music/download', {
|
||||
method: 'POST',
|
||||
@ -932,24 +974,15 @@
|
||||
body: JSON.stringify(batchRequestBody),
|
||||
credentials: 'include',
|
||||
});
|
||||
// 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',
|
||||
// });
|
||||
|
||||
const batchData = await batchResponse.json();
|
||||
|
||||
if (batchData.code === 200) {
|
||||
const batchNo = batchData.data; // 成功获取 batchNo
|
||||
const batchNo = batchData.data;
|
||||
|
||||
// 更新进度条
|
||||
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',
|
||||
@ -957,16 +990,14 @@
|
||||
});
|
||||
|
||||
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'; // 下载文件名
|
||||
a.download = 'music_files.zip';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
// 清理资源
|
||||
window.URL.revokeObjectURL(objectUrl);
|
||||
a.remove();
|
||||
|
||||
@ -981,18 +1012,14 @@
|
||||
console.error("下载过程中发生错误:", error);
|
||||
alert("请求失败,请检查网络连接!");
|
||||
} finally {
|
||||
// 更新进度条为 100%
|
||||
progressBar.value = 100;
|
||||
progressText.textContent = '100%';
|
||||
// alert("下载完成!");
|
||||
}
|
||||
};
|
||||
|
||||
// 调用主函数
|
||||
fetchBatchAndDownloadFile();
|
||||
}
|
||||
|
||||
// 显示用户名
|
||||
function displayUsername() {
|
||||
const username = getCookie('username');
|
||||
const userInfoDiv = document.getElementById('user-info');
|
||||
@ -1003,45 +1030,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 获取Cookie的值
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift());
|
||||
}
|
||||
|
||||
// 设置Cookie的值(可选)
|
||||
function setCookie(name, value, days) {
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
let expires = "expires=" + d.toUTCString();
|
||||
document.cookie = name + "=" + encodeURIComponent(value) + "; " + expires + "; path=/";
|
||||
}
|
||||
|
||||
// 显示消息并处理重定向
|
||||
function showMessage(msg) {
|
||||
alert(msg);
|
||||
setTimeout(() => {
|
||||
window.location.href = '/login.html'; // 确保登录页面的路径正确
|
||||
window.location.href = '/login.html';
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 退出登录函数
|
||||
function logout() {
|
||||
fetch('/api/v1/user/logout', { // 假设后端的退出登录接口是 /api/v1/user/logout
|
||||
fetch('/api/v1/user/logout', {
|
||||
method: 'POST',
|
||||
credentials: 'include' // 确保请求携带cookie
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 200) {
|
||||
// 清除可访问的cookie,如username
|
||||
deleteCookie('username');
|
||||
// 由于token是HttpOnly,无法通过JavaScript清除,后端已通过响应头清除
|
||||
// 跳转回登录页面
|
||||
window.location.href = '/login.html';
|
||||
} else {
|
||||
// 显示错误信息
|
||||
showMessage(data.msg || '退出登录失败,请稍后重试');
|
||||
}
|
||||
})
|
||||
@ -1051,12 +1063,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 删除Cookie的函数
|
||||
function deleteCookie(name) {
|
||||
document.cookie = name + '=; Max-Age=0; path=/';
|
||||
}
|
||||
|
||||
// 辅助函数:转义HTML,以防止XSS攻击
|
||||
function escapeHTML(str) {
|
||||
if (!str) return '';
|
||||
return str.replace(/[&<>"'`=\/]/g, function (s) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user