diff --git a/xiaomusic/static/iwebplayer/iwebplayer.html b/xiaomusic/static/iwebplayer/iwebplayer.html
index 212c7db..adc51c1 100644
--- a/xiaomusic/static/iwebplayer/iwebplayer.html
+++ b/xiaomusic/static/iwebplayer/iwebplayer.html
@@ -238,31 +238,7 @@
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6), 0 4px 12px rgba(0, 0, 0, 0.3);
}
}
- .inline-save-btn {
- background: rgba(236, 72, 153, 0.1);
- color: var(--primary);
- border: none;
- border-radius: 8px;
- flex-shrink: 0;
- width: 30px;
- height: 30px;
- display: none;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- transition: background 0.2s, transform 0.1s, opacity 0.2s;
- }
- @media (prefers-color-scheme: dark) {
- .inline-save-btn { background: rgba(236, 72, 153, 0.15); }
- }
- .inline-save-btn:active {
- opacity: 0.8;
- transform: scale(0.95);
- }
- .inline-save-btn.show {
- display: flex;
- animation: fadeIn 0.2s;
- }
+
.playlist-container-search { flex: 0 0 auto !important; max-width: 160px; }
.search-inline-wrap {
@@ -1075,8 +1051,7 @@
.text-mf { color: var(--primary) !important; }
.text-lx { color: #10b981 !important; }
- .bg-mf { background: rgba(236, 72, 153, 0.1) !important; color: var(--primary) !important; }
- .bg-lx { background: rgba(16, 185, 129, 0.1) !important; color: #10b981 !important; }
+
li.select-option[data-value="LXServer"].active { color: #10b981 !important; }
.lx-opts .select-option.active { color: #10b981 !important; background: var(--bg-color) !important; }
@keyframes spin-hourglass { 100% { transform: rotate(180deg); } }
@@ -1483,6 +1458,12 @@
#voice-pane #radio-lx:checked::after { background-color: #10b981; }
#voice-pane .radio-item:has(#radio-lx:checked) .radio-label { color: #10b981; }
.radio-item:has(input[name="voice-strategy"]:checked) .radio-label { color: var(--primary); font-weight: bold; }
+
+ .select-option.disabled {
+ color: var(--text-sub);
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
@@ -1509,7 +1490,7 @@
项目主页 / 更新地址:
https://github.com/birdstudy-nj/iWebPlayer
@@ -1890,7 +1908,7 @@
@@ -2136,8 +2154,9 @@
/* ==========================================
* 1. 核心配置与全局状态
* ========================================== */
- const APP_VERSION = 'v1.7.5';
+ const APP_VERSION = 'v1.7.6';
const APP_LOGO = document.getElementById('app-logo')?.content || '';
+ const PREDEFINED_PLAYLISTS = ['在线资源', '本地搜索', '所有电台', '所有歌曲', '最近新增', '收藏', '下载', 'cache_songs'];
const LX_PLATFORMS_MAP = { 'tx': 'QQ', 'wy': '网易云', 'kg': '酷狗', 'kw': '酷我', 'mg': '咪咕' };
const LX_BACKEND_NAMES = { 'tx': '小秋音乐', 'wy': '小芸音乐', 'kg': '小枸音乐', 'kw': '小蜗音乐', 'mg': '小蜜音乐' };
const STANDARD_LX_KEYS = Object.keys(LX_PLATFORMS_MAP);
@@ -2303,8 +2322,6 @@
const searchClear = document.getElementById('search-clear');
const mfSearchInput = document.getElementById('mf-search-input');
const mfSearchClear = document.getElementById('mf-search-clear');
- const searchSaveBtn = document.getElementById('search-save');
- const mfSearchSaveBtn = document.getElementById('mf-search-save');
document.getElementById('setting-version-label').textContent = APP_VERSION;
document.getElementById('about-version-label').textContent = APP_VERSION;
@@ -2357,6 +2374,12 @@
else if (name === '本地搜索') { icon = SVG_ICONS.search; displayName = '曲库搜索'; }
else if (name === '下载') icon = SVG_ICONS.download;
else if (name === '最近新增') { icon = SVG_ICONS.recent; displayName = '本地新增'; }
+
+ else if (name === 'cache_songs') {
+ icon = `
`;
+ displayName = '缓存歌曲';
+ }
+
else if (
name === '_online_iwebplayer_search' ||
name === '_online_play' ||
@@ -2642,44 +2665,50 @@
const mfSearchWrap = document.getElementById('mf-search-wrap');
const mfPluginRow = document.getElementById('mf-plugin-row');
const plContainer = document.getElementById('playlist-container');
-
- if (playlistName !== '本地搜索' && searchSaveBtn) {
- searchSaveBtn.classList.remove('show');
- }
+ const gm1Container = document.getElementById('global-menu-1-container');
if (playlistName === '本地搜索') {
if (searchWrap) searchWrap.classList.add('show');
if (mfSearchWrap) mfSearchWrap.classList.remove('show');
if (mfPluginRow) mfPluginRow.classList.remove('show');
if (plContainer) plContainer.classList.add('playlist-container-search');
+ if (gm1Container) gm1Container.style.display = 'flex';
const savedSearch = localStorage.getItem('local_search_keyword') || '';
if (searchInput) searchInput.value = savedSearch;
if (savedSearch && searchClear) searchClear.classList.add('show');
} else if (playlistName === '在线资源') {
-
if (searchWrap) searchWrap.classList.remove('show');
if (mfPluginRow) mfPluginRow.classList.add('show');
if (plContainer) plContainer.classList.add('playlist-container-search');
-
if (mfSearchWrap) mfSearchWrap.classList.add('show');
+ if (gm1Container) gm1Container.style.display = 'none';
const mfPluginContainer = document.getElementById('mf-plugin-container');
if (mfPluginContainer) {
mfPluginContainer.style.opacity = '1';
mfPluginContainer.style.pointerEvents = 'auto';
}
-
const currentEngineStr = document.getElementById('engine-val')?.dataset.value || 'MusicFree';
- if (typeof window.applyEngineUIAndState === 'function') {
- window.applyEngineUIAndState(currentEngineStr);
- }
+ if (typeof window.applyEngineUIAndState === 'function') window.applyEngineUIAndState(currentEngineStr);
} else {
if (searchWrap) searchWrap.classList.remove('show');
if (mfSearchWrap) mfSearchWrap.classList.remove('show');
if (mfPluginRow) mfPluginRow.classList.remove('show');
if (plContainer) plContainer.classList.remove('playlist-container-search');
+ if (gm1Container) gm1Container.style.display = 'flex';
+ }
+
+ // 控制语音搜索歌单、歌曲、歌手的“刷新”按钮显示状态
+ const refreshWrap = document.getElementById('voice-playlist-refresh-wrap');
+ const isVoicePlaylist = (
+ playlistName === '_online_iwebplayer_search' ||
+ playlistName === '_online_play' ||
+ (playlistName.startsWith('_online_') && !playlistName.startsWith('_online_iwp_') && !playlistName.startsWith('_online_lx_') && !playlistName.startsWith('_online_mf_') && playlistName !== '_online_webPush')
+ );
+ if (refreshWrap) {
+ refreshWrap.style.display = isVoicePlaylist ? 'flex' : 'none';
}
}
@@ -3656,12 +3685,13 @@
});
const allCleanKeys = Array.from(uniqueBaseNames);
- const predefinedOrder = ['在线资源', '本地搜索', '所有电台', '所有歌曲', '最近新增', '收藏', '下载'];
+ const predefinedOrder = PREDEFINED_PLAYLISTS;
const customKeys = [];
allCleanKeys.forEach(k => {
if (predefinedOrder.includes(k)) return; // 排除系统默认歌单
- if (k === '_online_iwebplayer_search' || k === '_online_play' || k.startsWith('🎵') || (window.customPlaylistNames && window.customPlaylistNames.includes(k))) {
+ if (k.startsWith('_online_')) return;
+ if (k.startsWith('🎵') || (window.customPlaylistNames && window.customPlaylistNames.includes(k))) {
customKeys.push(k);
}
});
@@ -3806,13 +3836,7 @@
renderPlaylist();
- if (currentPlaylist === '本地搜索' || currentPlaylist === '在线资源') {
- if (currentPlaylist === '本地搜索') {
- if (searchSaveBtn) searchSaveBtn.classList.toggle('show', songList.length > 0);
- } else if (currentPlaylist === '在线资源') {
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.toggle('show', songList.length > 0);
- }
- } else {
+ if (currentPlaylist !== '本地搜索' && currentPlaylist !== '在线资源') {
if (isOnlineObj) {
try {
const settingRes = await fetch(API.setting);
@@ -4119,7 +4143,6 @@
if (voiceOnlineSearchToggle) {
voiceOnlineSearchToggle.addEventListener('change', async (e) => {
const newState = e.target.checked;
- // 🌟 实时联动按钮状态
updateVoiceSaveBtnState();
showToast(`⏳ 正在${newState ? '注入' : '移除'}全网搜索指令...`);
@@ -4571,7 +4594,6 @@
const searchOpt = document.querySelector('#playlist-opts .select-option[data-key="本地搜索"]');
if (searchOpt) searchOpt.innerHTML = text;
}
- if (searchSaveBtn) searchSaveBtn.classList.toggle('show', (!keyword ? false : (allPlaylists['本地搜索']||[]).length > 0));
}
function initDeviceDropdown(devicesMap) {
@@ -4720,11 +4742,10 @@
li.innerHTML = formatPlaylistText(key, window.getMergedSongList(key).length);
- // 🌟 修改点:将点击回调改为 async 异步函数
li.addEventListener('click', async (e) => {
e.stopPropagation();
- // --- 🚀 新增:特殊歌单实时同步逻辑 ---
+ // 特殊歌单实时同步逻辑 ---
const isVoicePlaylist = (
key === '_online_iwebplayer_search' ||
key === '_online_play' ||
@@ -4777,8 +4798,8 @@
}
};
- const predefinedOrder = ['在线资源', '本地搜索', '所有电台', '所有歌曲', '最近新增', '收藏', '下载'];
- const hiddenPlaylists = ['全部', '_local_iwebplayer_search', '_online_webPush'];
+ const predefinedOrder = PREDEFINED_PLAYLISTS;
+ const hiddenPlaylists = ['全部', '_local_iwebplayer_search', '_online_webPush', 'cache_songs'];
if (window.getMergedSongList('其他').length === 0) hiddenPlaylists.push('其他');
if (window.getMergedSongList('下载').length === 0) hiddenPlaylists.push('下载');
@@ -4839,6 +4860,14 @@
localFolderKeys.forEach(key => createOpt(key));
}
+ if (allCleanKeys.includes('cache_songs')) {
+ if (playlistOpts.lastElementChild) playlistOpts.lastElementChild.style.borderBottom = 'none';
+ const sep = document.createElement('li');
+ sep.style.cssText = 'height: 1px; background: var(--border); margin: 6px 16px; cursor: default; box-sizing: content-box;';
+ playlistOpts.appendChild(sep);
+ createOpt('cache_songs');
+ }
+
if (defaultKey) {
currentPlaylist = defaultKey;
playlistVal.innerHTML = formatPlaylistText(defaultKey, window.getMergedSongList(defaultKey).length);
@@ -5202,8 +5231,6 @@
if (document.visibilityState === 'visible') {
scrollToCurrentSong();
- // 🌟 核心修复:监听从后台切回前台的瞬间
- // 如果是在本机模式,且有选中的歌曲,且发现 src 被后台清空了,立刻重新静默拉取!
if (currentDid === "" && currentIndex !== -1) {
const isSrcEmpty = !audioEl.src || audioEl.src === window.location.href || audioEl.src.includes('blob:');
if (audioEl.paused && isSrcEmpty) {
@@ -5221,6 +5248,11 @@
const mfPluginContainer = document.getElementById('mf-plugin-container');
const mfPluginVal = document.getElementById('mf-plugin-val');
+ const gm1Btn = document.getElementById('global-menu-1-btn');
+ const gm1Opts = document.getElementById('global-menu-1-opts');
+ const gm2Btn = document.getElementById('global-menu-2-btn');
+ const gm2Opts = document.getElementById('global-menu-2-opts');
+
const closeAllDropdownsExcept = (exceptId) => {
if (exceptId !== 'device-opts') deviceOpts.classList.remove('show');
if (exceptId !== 'playlist-opts') playlistOpts.classList.remove('show');
@@ -5228,10 +5260,42 @@
if (exceptId !== 'mf-plugin-opts' && mfOpts) mfOpts.classList.remove('show');
if (exceptId !== 'engine-opts' && engineOpts) engineOpts.classList.remove('show');
+ if (exceptId !== 'global-menu-1-opts' && gm1Opts) gm1Opts.classList.remove('show');
+ if (exceptId !== 'global-menu-2-opts' && gm2Opts) gm2Opts.classList.remove('show');
+
const historyList = document.getElementById('mf-search-history-list');
if (historyList) historyList.classList.remove('show');
};
+ const checkGridMode = () => document.getElementById('playlist-grid')?.style.display !== 'none';
+
+ if (gm1Btn) {
+ gm1Btn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ closeAllDropdownsExcept('global-menu-1-opts');
+
+ // 动态给菜单 1 的“创建/加入”变灰
+ document.querySelectorAll('#global-menu-1-opts .global-add-btn').forEach(btn => {
+ checkGridMode() ? btn.classList.add('disabled') : btn.classList.remove('disabled');
+ });
+
+ gm1Opts.classList.toggle('show');
+ });
+ }
+ if (gm2Btn) {
+ gm2Btn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ closeAllDropdownsExcept('global-menu-2-opts');
+
+ // 动态给菜单 2 的“创建/加入”变灰
+ document.querySelectorAll('#global-menu-2-opts .global-add-btn').forEach(btn => {
+ checkGridMode() ? btn.classList.add('disabled') : btn.classList.remove('disabled');
+ });
+
+ gm2Opts.classList.toggle('show');
+ });
+ }
+
deviceVal.addEventListener('click', (e) => {
e.stopPropagation();
closeAllDropdownsExcept('device-opts');
@@ -5293,6 +5357,9 @@
if (mfOpts && !e.target.closest('#mf-plugin-container')) mfOpts.classList.remove('show');
if (engineOpts && !e.target.closest('#engine-container')) engineOpts.classList.remove('show');
+ if (gm1Opts && !e.target.closest('#global-menu-1-container')) gm1Opts.classList.remove('show');
+ if (gm2Opts && !e.target.closest('#global-menu-2-container')) gm2Opts.classList.remove('show');
+
const historyList = document.getElementById('mf-search-history-list');
if (historyList && !e.target.closest('#mf-search-input-wrap')) historyList.classList.remove('show');
@@ -5330,6 +5397,50 @@
});
}
+ // 语音歌单快捷“刷新”数据交互核心
+ const voiceRefreshBtn = document.getElementById('voice-playlist-refresh-btn');
+ if (voiceRefreshBtn) {
+ voiceRefreshBtn.addEventListener('click', async (e) => {
+ e.stopPropagation();
+ if (!currentPlaylist) return;
+
+ // 变成加载状态,防止用户鬼畜连击
+ const originalHtml = voiceRefreshBtn.innerHTML;
+ voiceRefreshBtn.innerHTML = "同步中...";
+ voiceRefreshBtn.disabled = true;
+ voiceRefreshBtn.style.opacity = "0.6";
+
+ try {
+ // 1. 重新调用核心函数:从后台获取最新的全量曲库与状态
+ await reloadGlobalData();
+
+ // 2. 刷新当前选中语音列表的数据池
+ songList = window.getMergedSongList(currentPlaylist);
+
+ // 3. 重新渲染屏幕列表
+ renderPlaylist();
+
+ // 4. 同步修正顶部选择框的数值和文案
+ const newText = formatPlaylistText(currentPlaylist, songList.length);
+ if (playlistVal) playlistVal.innerHTML = newText;
+
+ // 5. 更新下拉抽屉里对应选项的缓存文案
+ const opt = document.querySelector(`#playlist-opts .select-option[data-key="${currentPlaylist}"]`);
+ if (opt) opt.innerHTML = newText;
+
+ showToast("✅ 语音交互结果已同步更新");
+ } catch (err) {
+ console.error("语音歌单异步刷新失败:", err);
+ showToast("❌ 同步失败,请稍后重试");
+ } finally {
+ // 还原按钮
+ voiceRefreshBtn.innerHTML = originalHtml;
+ voiceRefreshBtn.disabled = false;
+ voiceRefreshBtn.style.opacity = "1";
+ }
+ });
+ }
+
if (settingRefreshBtn) {
settingRefreshBtn.addEventListener('click', (e) => {
e.stopPropagation();
@@ -5477,7 +5588,7 @@
if (audioEl.paused) {
audioEl.play();
} else {
- // 🌟 给系统发通行证:证明这个暂停是 btn-play 触发的
+ // 给系统发通行证:证明这个暂停是 btn-play 触发的
window.isPageBtnPause = true;
audioEl.pause();
// 0.2秒后立刻销毁通行证,防止影响后续真实的锁屏暂停
@@ -6020,7 +6131,7 @@
const autoAddToggle = document.getElementById('voice-auto-add-toggle');
if (autoAddToggle) autoAddToggle.checked = !!data.data.auto_add_song;
- // 🌟 核心修改:从下拉框赋值改为勾选对应的单选按钮
+ // 从下拉框赋值改为勾选对应的单选按钮
const strategyVal = data.data.voice_playlist_strategy || 'default';
const strategyRadio = document.querySelector(`input[name="voice-strategy"][value="${strategyVal}"]`);
if (strategyRadio) strategyRadio.checked = true;
@@ -6364,7 +6475,7 @@
window.addOnlineSearchHistory = function(itemObj) {
let history = JSON.parse(localStorage.getItem('online_search_history_list') || '[]');
- // 🌟 核心优化:只有具体的歌单(detail)和分类标签(tag)才绑定平台身份!打字搜歌/搜单不绑定
+ // 只有具体的歌单(detail)和分类标签(tag)才绑定平台身份!打字搜歌/搜单不绑定
if (itemObj.type === 'detail' || itemObj.type === 'tag') {
itemObj.engine = document.getElementById('engine-val')?.dataset.value || 'MusicFree';
}
@@ -6399,7 +6510,7 @@
historyHtml = history.slice(0, 10).map((item, idx) => {
if (item.type === 'detail' || item.type === 'tag') {
const sourceName = LX_PLATFORMS_MAP[item.source] || item.source;
- // 🌟 渲染:根据 engine 属性给历史胶囊上色
+ // 根据 engine 属性给历史胶囊上色
const themeClass = item.engine === 'LXServer' ? 'lx-theme' : 'mf-theme';
return `
@@ -6470,7 +6581,7 @@
e.stopPropagation();
const item = history[li.dataset.index];
- // 🌟 核心优化:只有胶囊(具体歌单或标签)才强制切回它所属的引擎。关键词直接用当前引擎!
+ // 只有胶囊(具体歌单或标签)才强制切回它所属的引擎。关键词直接用当前引擎!
if ((item.type === 'detail' || item.type === 'tag') && item.engine) {
window.applyEngineUIAndState(item.engine);
}
@@ -6615,11 +6726,10 @@
document.getElementById('mf-search-input-wrap').insertBefore(capsule, document.getElementById('mf-search-input'));
}
- // 🌟 根据 apiType 切换胶囊颜色类名
+ // 根据 apiType 切换胶囊颜色类名
const currentEngine = apiType === 1 ? 'MusicFree' : 'LXServer';
capsule.className = `search-tag-capsule ${apiType === 1 ? 'mf-theme' : 'lx-theme'}`;
- // 🌟 核心修复:把你之前不小心弄丢的这行代码补回来!把点进去的具体歌单存入历史记录
window.addOnlineSearchHistory({ type: 'detail', id: id, name: name, source: source });
// 控制提示词和清空搜歌文字
@@ -6655,7 +6765,7 @@
if (resJson.success && resJson.data && resJson.data.length > 0) {
songList = resJson.data;
- // 🌟 核心修复:在详情缓存里记录 engine
+ // 在详情缓存里记录 engine
localStorage.setItem('lx_detail_cache', JSON.stringify({
engine: currentEngine, // 存入身份
type: 'detail',
@@ -6666,12 +6776,7 @@
}));
if (typeof window.toggleSearchBackBtn === 'function') window.toggleSearchBackBtn(true);
-
renderPlaylist();
-
- const mfSearchSaveBtn = document.getElementById('mf-search-save');
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.add('show');
-
const playlistVal = document.getElementById('playlist-val');
const text = formatPlaylistText('在线资源', songList.length);
if (playlistVal) playlistVal.innerHTML = text;
@@ -6708,7 +6813,7 @@
const currentEngine = document.getElementById('engine-val')?.dataset.value || 'MusicFree';
const apiType = currentEngine === 'LXServer' ? 2 : 1;
- // 🌟 加载 SVG 的动态颜色
+ // 加载 SVG 的动态颜色
const themeColor = currentEngine === 'LXServer' ? '#10b981' : 'var(--primary)';
// 核心判断:如果是打字搜歌单,处理历史记录和UI
@@ -6727,7 +6832,6 @@
}
} else if (type === 'tag' && !isLoadMore) {
localStorage.removeItem('lx_detail_cache');
- // 🌟 响应你的需求:仅仅清除旧的详情缓存,不再把标签当做历史记录存入
}
// 胶囊(tag)直接走LX源地址,文字搜歌单(keyword)走XiaoMusic后端桥接!
@@ -6745,7 +6849,7 @@
window.hasMoreLxPlaylists = true;
list.style.display = 'none';
grid.style.display = 'grid';
- // 🌟 修复转圈动画颜色
+
grid.innerHTML = ``;
} else {
window.currentLxPlaylistPage++;
@@ -6787,7 +6891,7 @@
if (targetList.length < targetLimit) window.hasMoreLxPlaylists = false;
- // 🌟 核心:存入专属的海报墙抽屉时带上引擎身份
+ // 存入专属的海报墙抽屉时带上引擎身份
localStorage.setItem('lx_grid_cache', JSON.stringify({
engine: currentEngine, // 存入引擎身份
type: type === 'keyword' ? 'playlist' : 'tag',
@@ -6979,7 +7083,6 @@
renderPlaylist();
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.add('show');
const text = formatPlaylistText('在线资源', songList.length);
playlistVal.innerHTML = text;
const mfOpt = document.querySelector('#playlist-opts .select-option[data-key="在线资源"]');
@@ -7086,7 +7189,7 @@
}
if (typeof window.toggleSearchBackBtn === 'function') window.toggleSearchBackBtn(false);
- // 🌟 修复返回错乱:读取网格缓存的真实引擎身份,没记录就用当前引擎
+ // 读取网格缓存的真实引擎身份,没记录就用当前引擎
const targetEngine = gridCache.engine || document.getElementById('engine-val')?.dataset.value || 'MusicFree';
window.applyEngineUIAndState(targetEngine);
} else {
@@ -7162,6 +7265,20 @@
const handleBulkAddClick = (e) => {
e.stopPropagation();
+
+ // 触发点击时,顺手把菜单收起来
+ const gm1Opts = document.getElementById('global-menu-1-opts');
+ const gm2Opts = document.getElementById('global-menu-2-opts');
+ if (gm1Opts) gm1Opts.classList.remove('show');
+ if (gm2Opts) gm2Opts.classList.remove('show');
+
+ // 拦截“歌单海报墙(Grid)”模式的点击,弹出专属提示
+ const isGridMode = document.getElementById('playlist-grid')?.style.display !== 'none';
+ if (isGridMode) {
+ showToast("⚠️ 需要进入歌曲列表模式");
+ return;
+ }
+
if (!songList || songList.length === 0) { showToast("当前列表为空,无法加入"); return; }
if (window.skipAddConfirm && window.lastAddedPlaylist) {
@@ -7169,12 +7286,43 @@
return;
}
- window.pendingBulkAdd = true;
+ window.pendingBulkAdd = true;window.pendingBulkAdd = true;
window.pendingAddIndex = -1;
const nameSpan = document.getElementById('add-song-name');
if (nameSpan) nameSpan.textContent = `当前列表 (共 ${songList.length} 首)`;
+ // 智能抓取当前上下文的名称,并预填到输入框中
+ const newPlaylistInput = document.getElementById('add-new-playlist-input');
+ if (newPlaylistInput) {
+ let defaultName = currentPlaylist;
+
+ if (currentPlaylist === '在线资源') {
+ // 如果是在线资源,优先抓取搜索胶囊里的完整名称(title存了未截断的全名)
+ const capsule = document.getElementById('search-tag-capsule');
+ if (capsule && capsule.title) {
+ defaultName = capsule.title;
+ } else if (capsule && capsule.innerText) {
+ defaultName = capsule.innerText.trim();
+ } else {
+ const mfInput = document.getElementById('mf-search-input');
+ if (mfInput && mfInput.value) defaultName = mfInput.value.trim();
+ }
+ } else if (currentPlaylist === '本地搜索') {
+ // 如果是本地搜索,抓取搜索框里的关键词
+ const localInput = document.getElementById('search-input');
+ if (localInput && localInput.value) defaultName = localInput.value.trim();
+ } else {
+ // 如果是普通歌单,使用系统自带的解析函数去掉“🎵”等前缀
+ if (typeof window.getDisplayPlaylistName === 'function') {
+ defaultName = window.getDisplayPlaylistName(currentPlaylist);
+ }
+ }
+
+ // 将抓取到的名字填入输入框
+ newPlaylistInput.value = defaultName;
+ }
+
const listEl = document.getElementById('add-song-playlist-list');
if (listEl) window.renderPlaylistRadioList(listEl);
if (addSongModal) {
@@ -7184,8 +7332,20 @@
}
};
- if (searchSaveBtn) searchSaveBtn.addEventListener('click', handleBulkAddClick);
- if (mfSearchSaveBtn) mfSearchSaveBtn.addEventListener('click', handleBulkAddClick);
+ document.querySelectorAll('.global-add-btn').forEach(btn => {
+ btn.addEventListener('click', handleBulkAddClick);
+ });
+
+ document.querySelectorAll('.global-dev-btn').forEach(btn => {
+ btn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ const gm1Opts = document.getElementById('global-menu-1-opts');
+ const gm2Opts = document.getElementById('global-menu-2-opts');
+ if (gm1Opts) gm1Opts.classList.remove('show');
+ if (gm2Opts) gm2Opts.classList.remove('show');
+ showToast("努力开发中 🚀");
+ });
+ });
}
@@ -7309,7 +7469,6 @@
const mfPluginVal = document.getElementById('mf-plugin-val');
const mfPluginOpts = document.getElementById('mf-plugin-opts');
const mfSearchBtn = document.getElementById('mf-search-btn');
- const mfSearchSaveBtn = document.getElementById('mf-search-save');
if (!engineVal || !engineOpts) return;
engineVal.dataset.value = targetVal;
@@ -7323,7 +7482,6 @@
if (mfPluginVal) mfPluginVal.classList.remove('text-mf', 'text-lx');
if (mfPluginOpts) mfPluginOpts.classList.remove('lx-opts');
if (mfSearchBtn) mfSearchBtn.classList.remove('bg-mf', 'bg-lx');
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.remove('bg-mf', 'bg-lx');
const mfSearchInput = document.getElementById('mf-search-input');
const mfSearchClear = document.getElementById('mf-search-clear');
@@ -7337,13 +7495,11 @@
engineVal.classList.add('text-lx');
if (mfPluginVal) mfPluginVal.classList.add('text-lx');
if (mfPluginOpts) mfPluginOpts.classList.add('lx-opts');
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.add('bg-lx');
const currentSource = document.getElementById('mf-plugin-val')?.dataset.value || 'tx';
if (typeof window.fetchLxTags === 'function') window.fetchLxTags(currentSource);
} else {
engineVal.classList.add('text-mf');
if (mfPluginVal) mfPluginVal.classList.add('text-mf');
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.add('bg-mf');
}
if (typeof renderSearchPluginDropdown === 'function') renderSearchPluginDropdown(targetVal);
@@ -7360,7 +7516,7 @@
if (playlistBtn) playlistBtn.style.display = 'block';
if (searchDivider) searchDivider.style.display = 'block';
- // 🌟 统一缓存恢复核心逻辑:双方都认同引擎身份牌
+ // 统一缓存恢复核心逻辑:双方都认同引擎身份牌
try {
const detailCache = JSON.parse(localStorage.getItem('lx_detail_cache'));
const gridCache = JSON.parse(localStorage.getItem('lx_grid_cache'));
@@ -7490,8 +7646,6 @@
const text = formatPlaylistText('在线资源', (window.lxPlaylistItems || []).length);
if (playlistVal) playlistVal.innerHTML = text;
}
-
- if (mfSearchSaveBtn) mfSearchSaveBtn.classList.toggle('show', songList.length > 0 && mode !== 'playlist' && mode !== 'tag');
}
};
@@ -7658,9 +7812,106 @@
window.migrateOldPlaylists(false);
});
+ // GitHub 远端版本自动探针检测与云控配置
+ function checkRemoteVersion() {
+ // 拼接时间戳 t=... 强行打破 GitHub 静态文件的 CDN 缓存,确保获取最新数据
+ const versionUrl = "https://raw.githubusercontent.com/birdstudy-nj/iWebPlayer/main/version.json?t=" + new Date().getTime();
+
+ fetch(versionUrl)
+ .then(res => res.json())
+ .then(data => {
+ if (!data) return;
+
+ // 1. 新版本红点菜单检测逻辑
+ if (data.latest_version && data.latest_version !== APP_VERSION) {
+ const optsUl = document.getElementById('settings-opts');
+ if (optsUl) {
+ const li = document.createElement('li');
+ li.className = 'select-option';
+ li.id = 'setting-remote-update';
+ const rocketSvg = ``;
+ li.innerHTML = `${rocketSvg} 发现${data.latest_version}`;
+ li.style.color = 'var(--primary)';
+ li.addEventListener('click', (e) => {
+ e.stopPropagation();
+ if (data.download_url) window.open(data.download_url, '_blank');
+ optsUl.classList.remove('show');
+ });
+ optsUl.appendChild(li);
+ }
+ }
+
+ // 2. 云控公告与二维码动态注入逻辑
+ if (data.dynamic_notice && data.dynamic_notice.enable) {
+ const noticeWrapper = document.getElementById('remote-notice-wrapper');
+ if (noticeWrapper) {
+ let htmlStr = '';
+
+ // 渲染标题
+ if (data.dynamic_notice.title) {
+ htmlStr += `${data.dynamic_notice.title}
`;
+ }
+ // 渲染富文本内容
+ if (data.dynamic_notice.html_content) {
+ htmlStr += `${data.dynamic_notice.html_content}
`;
+ }
+ // 渲染精致的二维码微卡片
+ if (data.dynamic_notice.qr_code_url) {
+ htmlStr += `
+
+
+

+
+
`;
+ }
+
+ noticeWrapper.innerHTML = htmlStr;
+ noticeWrapper.style.display = 'block'; // 彻底激活并显示
+ }
+ }
+ })
+ .catch(err => console.log("远端检测或配置拉取失败:", err));
+ }
+
+ // 本地后端 HTML 版本静默探测与自动热更
+ function checkLocalVersionUpdate() {
+ // 发送一个带时间戳的请求,绕过 iOS 缓存,直接偷看后端服务器上真实的 HTML 源码
+ fetch(window.location.pathname + '?t=' + Date.now(), { cache: 'no-store' })
+ .then(res => res.text())
+ .then(html => {
+ // 用正则精准提取服务器上那份 HTML 里的 APP_VERSION
+ const match = html.match(/const APP_VERSION = ['"](.*?)['"]/);
+ if (match && match[1] && match[1] !== APP_VERSION) {
+ const newVersion = match[1];
+ const lastAttempt = localStorage.getItem('iwp_update_attempt');
+
+ if (lastAttempt !== newVersion) {
+ // 第一次发现新版:记录并尝试强制刷新破除缓存
+ localStorage.setItem('iwp_update_attempt', newVersion);
+ showToast(`🚀 发现后端已更新至 ${newVersion},正在自动为您刷新...`, true);
+
+ setTimeout(() => {
+ // 强制重载,尝试打破 iOS WebClip 的缓存层
+ window.location.reload(true);
+ }, 2000);
+ } else {
+ // 已经尝试过刷新,但页面依然是旧版,说明 iOS 发生了“底层缓存死锁”
+ // 此时绝不能再刷新(防死循环),只弹窗提醒用户手动重装
+ showToast(`⚠️ 后端已是 ${newVersion},但 iOS 缓存固化。请重新生成桌面配置!`, true);
+ }
+ } else if (match && match[1] === APP_VERSION) {
+ // 如果版本一致,说明当前就是最新版,或者刚刚的热更成功了,清除防死循环标记
+ localStorage.removeItem('iwp_update_attempt');
+ }
+ })
+ .catch(err => console.log("本地更新探针检测失败:", err));
+ }
+
async function init() {
renderLogos();
bindAllEvents();
+ checkRemoteVersion();
+ checkLocalVersionUpdate();
window.currentEngineType = 1; // 默认 1=MF, 2=LX