Skip to content

Commit 856b78e

Browse files
committed
Merge branch 'main' of https://github.com/NB-Group/NB_Music
2 parents 6f7e892 + 39b7a0d commit 856b78e

File tree

11 files changed

+368
-47
lines changed

11 files changed

+368
-47
lines changed

src/javascript/EffectManager.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ class EffectManager {
4848
effectdialog.addEventListener("mousedown", () => {
4949
effectdialog.classList.add("hide");
5050
});
51+
// 添加重置按钮事件监听
52+
effectdialogcontent.querySelector('.reset-btn').addEventListener('click', () => {
53+
this.frequencies.forEach(freq => {
54+
this.adjustFrequency(freq, 0);
55+
const slider = effectdialogcontent.querySelector(`.equalizer-item>.slider[data-adjust="${freq}"]`);
56+
if (slider) {
57+
slider.value = 0;
58+
}
59+
});
60+
});
61+
5162
if (this.settingManager.getSetting("echo") == "true") {
5263
effectdialogcontent.querySelector('a.echo[data-value="true"]').classList.add("active");
5364
} else {

src/javascript/FavoriteManager.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ class FavoriteManager {
5959
const removeIndex = this.lovelist.findIndex((item) => item.title === song.title);
6060
if (removeIndex !== -1) {
6161
this.lovelist.splice(removeIndex, 1);
62+
63+
// 修改后的清空检测逻辑
64+
if (this.lovelist.length === 0) {
65+
const listElement = document.querySelector("#lovelist");
66+
listElement.innerHTML = '<div class="empty-state fadein">' +
67+
'<i class="bi bi-music-note-beamed"></i>' +
68+
'<p>还没有收藏的音乐哦</p>' +
69+
'<span class="tip">小贴士:在播放界面点击❤️图标即可收藏歌曲</span>' +
70+
'</div>';
71+
}
6272
}
6373

6474
// 更新UI

src/javascript/LoginManager.js

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -514,29 +514,27 @@ class LoginManager {
514514
const loginMode = this.getCookie("nbmusic_loginmode");
515515

516516
if (loginMode === "qrcode") {
517-
this.getCookie("bili_jct").then((biliJct) => {
518-
axios
519-
.post("https://passport.bilibili.com/login/exit/v2", "biliCSRF=" + biliJct, { headers: { "Content-Type": "application/x-www-form-urlencoded" } })
520-
.then((response) => {
521-
if (response.data.code !== 0) {
522-
console.error("退出登录失败:", response.data.message);
523-
this.uiManager.showNotification("退出登录失败", "error");
524-
return;
525-
}
526-
527-
ipcRenderer.send("logout");
528-
})
529-
.catch((error) => {
530-
if (error.response) {
531-
console.error("退出登录失败:", error.response.data.message);
532-
} else if (error.request) {
533-
console.error("退出登录失败:服务器没有响应");
534-
} else {
535-
console.error("退出登录失败:", error.message);
536-
}
517+
axios
518+
.post("https://passport.bilibili.com/login/exit/v2", "biliCSRF=" + this.getCookie("bili_jct"), { headers: { "Content-Type": "application/x-www-form-urlencoded" } })
519+
.then((response) => {
520+
if (response.data.code !== 0) {
521+
console.error("退出登录失败:", response.data.message);
537522
this.uiManager.showNotification("退出登录失败", "error");
538-
});
539-
});
523+
return;
524+
}
525+
526+
ipcRenderer.send("logout");
527+
})
528+
.catch((error) => {
529+
if (error.response) {
530+
console.error("退出登录失败:", error.response.data.message);
531+
} else if (error.request) {
532+
console.error("退出登录失败:服务器没有响应");
533+
} else {
534+
console.error("退出登录失败:", error.message);
535+
}
536+
this.uiManager.showNotification("退出登录失败", "error");
537+
});
540538
} else {
541539
ipcRenderer.send("logout");
542540
}

src/javascript/MusiclistManager.js

Lines changed: 242 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class MusiclistManager {
1111
* @param {import("./LoginManager.js")} loginManager
1212
*/
1313
constructor(playlistManager, musicSearcher, cacheManager, loginManager) {
14+
this.isUpdating = false;
1415
this.playlistManager = playlistManager;
1516
this.musicSearcher = musicSearcher;
1617
this.cacheManager = cacheManager;
@@ -203,6 +204,9 @@ class MusiclistManager {
203204
lyricSearchTypeSelect.addEventListener("change", (e) => {
204205
this.lyricSearchType = e.target.value;
205206
});
207+
document.getElementById('autoUpdateBtn').addEventListener('click', () => {
208+
this.updateBiliFav(this.activePlaylistIndex);
209+
});
206210
// 点击新建歌单按钮事件
207211
this.newPlaylistBtn.addEventListener("click", () => {
208212
const input = document.createElement("input");
@@ -830,7 +834,12 @@ class MusiclistManager {
830834
this.playlists.push({
831835
id: this.generateUUID(),
832836
name: playlistTitle,
833-
songs: []
837+
songs: [],
838+
meta: {
839+
mediaId: favId,
840+
type: 'bilibili',
841+
total: favInfo.media_count
842+
}
834843
});
835844

836845
// 2. 收集所有要添加的歌曲信息
@@ -910,6 +919,231 @@ class MusiclistManager {
910919
};
911920
}
912921
}
922+
async updateBiliFav(playlistIndex) {
923+
const playlist = this.playlists[playlistIndex];
924+
let updateNotification = null;
925+
926+
// 新增状态检查防止重复点击
927+
if (this.isUpdating) {
928+
this.uiManager.showNotification('更新正在进行中,请稍后再试', 'warning');
929+
return;
930+
}
931+
932+
try {
933+
this.isUpdating = true; // 设置更新状态
934+
// 增强类型验证逻辑
935+
const { mediaId, seasonId, type } = playlist.meta || {};
936+
937+
// 根据不同类型选择更新方式
938+
if (type === 'bilibili-season' && seasonId) {
939+
return await this.updateBiliSeason(playlistIndex);
940+
}
941+
942+
// 原有收藏夹更新逻辑
943+
if (!mediaId) {
944+
throw new Error('此歌单未关联B站收藏夹,请重新添加收藏夹');
945+
}
946+
947+
// 修改API请求使用v3接口
948+
const favResponse = await axios.get(
949+
`https://api.bilibili.com/x/v3/fav/folder/info?media_id=${mediaId}`
950+
);
951+
952+
const favInfo = favResponse.data.data;
953+
const totalCount = favInfo.media_count;
954+
const existingBVids = new Set(playlist.songs.map(song => song.bvid));
955+
956+
// 设置进度通知
957+
updateNotification = this.uiManager.showNotification(
958+
`正在检查更新 (0/${totalCount})`,
959+
'info',
960+
{ showProgress: true, progress: 0 }
961+
);
962+
963+
let newSongs = [];
964+
const pageSize = 20;
965+
const totalPages = Math.ceil(totalCount / pageSize);
966+
967+
// 遍历所有页面
968+
for (let page = 1; page <= totalPages; page++) {
969+
const res = await axios.get(
970+
`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${mediaId}&pn=${page}&ps=${pageSize}`
971+
);
972+
973+
if (res.data.code === 0) {
974+
const medias = res.data.data.medias || [];
975+
976+
// 过滤已存在的视频
977+
const filtered = medias.filter(media =>
978+
!existingBVids.has(media.bvid) && media.attr !== 1
979+
);
980+
981+
// 转换格式并添加到新歌曲列表
982+
newSongs.push(...await Promise.all(filtered.map(async media => ({
983+
title: media.title,
984+
artist: media.upper.name,
985+
bvid: media.bvid,
986+
duration: media.duration,
987+
poster: media.cover,
988+
meta: { mediaId } // 保存收藏夹ID用于后续更新
989+
}))));
990+
991+
// 更新进度
992+
const processed = page * pageSize;
993+
const progress = Math.min(processed / totalCount * 100, 100);
994+
const progressBar = updateNotification.querySelector('.notification-progress-inner'); // 修正选择器
995+
const progressText = updateNotification.querySelector('.notification-message');
996+
997+
if (progressText && progressBar) { // 添加空值检查
998+
progressText.textContent =
999+
`正在检查更新 (${Math.min(processed, totalCount)}/${totalCount})`;
1000+
progressBar.style.width = `${progress}%`;
1001+
}
1002+
}
1003+
}
1004+
1005+
// 应用更新
1006+
if (newSongs.length > 0) {
1007+
// 处理新增歌曲的歌词
1008+
const newSongsWithLyrics = await this.processSongsLyrics(newSongs); // 新增歌词处理
1009+
1010+
playlist.songs = [...newSongsWithLyrics, ...playlist.songs]; // 使用带歌词的新数据
1011+
this.savePlaylists();
1012+
this.uiManager.showNotification(`发现${newSongs.length}首新歌曲`, 'success');
1013+
1014+
// 强制刷新歌单列表并保持激活状态
1015+
this.renderPlaylistList();
1016+
this.renderSongList();
1017+
1018+
// 高亮更新后的歌单条目
1019+
const updatedElement = document.querySelector(`li[data-id="${playlist.id}"]`);
1020+
if (updatedElement) {
1021+
updatedElement.classList.add('active');
1022+
updatedElement.click();
1023+
}
1024+
} else {
1025+
this.uiManager.showNotification('当前歌单已是最新', 'info');
1026+
}
1027+
} catch (error) {
1028+
this.uiManager.showNotification(`更新失败: ${error.message}`, 'error');
1029+
} finally {
1030+
this.isUpdating = false; // 重置更新状态
1031+
if (updateNotification) { // 添加安全判断
1032+
updateNotification.remove();
1033+
}
1034+
}
1035+
}
1036+
1037+
async updateBiliSeason(playlistIndex) {
1038+
const playlist = this.playlists[playlistIndex];
1039+
let updateNotification = null;
1040+
try {
1041+
const { seasonId, mid } = playlist.meta || {};
1042+
if (!seasonId || !mid) {
1043+
throw new Error('此歌单未关联B站合集或信息不完整');
1044+
}
1045+
1046+
// 获取合集信息
1047+
const seasonResponse = await axios.get(
1048+
`https://api.bilibili.com/x/polymer/web-space/seasons_archives_list?mid=${mid}&season_id=${seasonId}&page_num=1&page_size=100`
1049+
);
1050+
1051+
if (seasonResponse.data.code !== 0) {
1052+
throw new Error('获取合集信息失败: ' + seasonResponse.data.message);
1053+
}
1054+
1055+
const videos = seasonResponse.data.data.archives;
1056+
const totalCount = videos.length;
1057+
const existingBVids = new Set(playlist.songs.map(song => song.bvid));
1058+
1059+
// 获取合集名称
1060+
const seasonName = playlist.name.replace(/\([^)]*\)$/, '').trim();
1061+
1062+
// 设置进度通知
1063+
updateNotification = this.uiManager.showNotification(
1064+
`正在检查更新 (0/${totalCount})`,
1065+
'info',
1066+
{ showProgress: true, progress: 0 }
1067+
);
1068+
1069+
let newSongs = [];
1070+
let processedCount = 0;
1071+
1072+
// 处理每个视频
1073+
for (const video of videos) {
1074+
try {
1075+
// 跳过已存在的视频
1076+
if (existingBVids.has(video.bvid)) {
1077+
processedCount++;
1078+
continue;
1079+
}
1080+
1081+
// 获取视频详情以获取CID
1082+
let cid = video.cid;
1083+
if (!cid) {
1084+
const videoDetailResponse = await axios.get(
1085+
`https://api.bilibili.com/x/web-interface/view?bvid=${video.bvid}`
1086+
);
1087+
if (videoDetailResponse.data.code === 0) {
1088+
cid = videoDetailResponse.data.data.cid;
1089+
}
1090+
}
1091+
1092+
newSongs.push({
1093+
title: video.title,
1094+
artist: seasonName,
1095+
bvid: video.bvid,
1096+
cid: cid,
1097+
duration: video.duration,
1098+
poster: video.pic,
1099+
meta: { seasonId, mid }
1100+
});
1101+
1102+
// 更新进度
1103+
processedCount++;
1104+
const progress = (processedCount / totalCount) * 100;
1105+
updateNotification.querySelector(".notification-message").textContent =
1106+
`正在检查更新 (${processedCount}/${totalCount})`;
1107+
updateNotification.querySelector(".notification-progress-inner").style.width =
1108+
`${progress}%`;
1109+
1110+
} catch (error) {
1111+
console.warn(`处理视频 ${video.bvid} 失败:`, error);
1112+
continue;
1113+
}
1114+
}
1115+
1116+
// 应用更新
1117+
if (newSongs.length > 0) {
1118+
// 处理新增歌曲的歌词
1119+
const newSongsWithLyrics = await this.processSongsLyrics(newSongs);
1120+
1121+
playlist.songs = [...newSongsWithLyrics, ...playlist.songs];
1122+
this.savePlaylists();
1123+
this.uiManager.showNotification(`发现${newSongs.length}首新歌曲`, 'success');
1124+
1125+
// 强制刷新歌单列表并保持激活状态
1126+
this.renderPlaylistList();
1127+
this.renderSongList();
1128+
1129+
// 高亮更新后的歌单条目
1130+
const updatedElement = document.querySelector(`li[data-id="${playlist.id}"]`);
1131+
if (updatedElement) {
1132+
updatedElement.classList.add('active');
1133+
updatedElement.click();
1134+
}
1135+
} else {
1136+
this.uiManager.showNotification('当前歌单已是最新', 'info');
1137+
}
1138+
} catch (error) {
1139+
this.uiManager.showNotification(`更新失败: ${error.message}`, 'error');
1140+
} finally {
1141+
if (updateNotification) {
1142+
updateNotification.remove();
1143+
}
1144+
}
1145+
}
1146+
9131147
async showLyricSearchDialog(song) {
9141148
return new Promise((resolve) => {
9151149
const dialog = document.getElementById("lyricSearchDialog");
@@ -1032,7 +1266,13 @@ class MusiclistManager {
10321266
this.playlists.push({
10331267
id: this.generateUUID(),
10341268
name: playlistTitle,
1035-
songs: []
1269+
songs: [],
1270+
meta: {
1271+
seasonId: seasonId,
1272+
mid: mid,
1273+
type: 'bilibili-season',
1274+
total: totalCount
1275+
}
10361276
});
10371277

10381278
// 收集所有要添加的歌曲信息

src/javascript/SettingManager.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class SettingManager {
247247

248248
this.sliderSetting(
249249
"lyricLineFontSize",
250-
"24px",
250+
"24",
251251
"歌词字体大小已重置",
252252
(value) => `${value}px`,
253253
() => this.applyFontSize()

src/login.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
min-height: 100vh;
3939
display: flex;
4040
overflow-x: hidden;
41+
/* 禁用复制 */
42+
user-select: none;
43+
-moz-user-select: none;
44+
-webkit-user-select: none;
45+
-ms-user-select: none;
4146
}
4247

4348
.login-container {
@@ -467,6 +472,12 @@ <h2 class="card-title">Bilibili 账号登录</h2>
467472
const userInfo = document.getElementById('userInfo');
468473
const loginButton = document.getElementById('loginButton');
469474

475+
// 禁用右键菜单
476+
document.oncontextmenu = (event) => {
477+
event.preventDefault();
478+
};
479+
480+
// 获取用户信息
470481
fetch('/getUserInfo').then(res => res.json()).then(data => {
471482
if (data.data.isLogin) {
472483
avatar.src = data.data.avatar;

0 commit comments

Comments
 (0)