/*!
 * @name 星海音乐源
 * @description 主API：GDAPI | 备用API：聚合接口 | ChKSz API网易云高音质
 * @version v2.3.1
 * @author 万去了了
 * @homepage https://zrcdy.dpdns.org/
 * @lastUpdate 2025-06-01
 *
 * @version v2.3.1：更新接口，新增网易云高音质
 */

// ============================ 核心配置 ============================

const UPDATE_CONFIG = {
    versionApiUrl: 'https://zrcdy.dpdns.org/lx/version.php',  
    latestScriptUrl: 'https://zrcdy.dpdns.org/lx/vers.php',
    currentVersion: 'v2.3.1' 
};

// 动态稳定源接口
const STABLE_SOURCES_API_URL = 'https://zrcdy.dpdns.org/lx/stable_sources.php';

// 主API - GD Studio
const MAIN_API_BASE = 'https://music-api.gdstudio.xyz/api.php?use_xbridge3=true&loader_name=forest&need_sec_link=1&sec_link_scene=im&theme=light';

// 备用API - 聚合接口
const BACKUP_API_BASE = 'https://zrcdy.dpdns.org/lx/api/api.php';

// 网易云VIP高音质API
const NETEASE_VIP_API = 'https://api.chksz.top/api/163_music';

// ============================ 全局状态 ============================

let musicSourceEnabled = true;
let serverCheckCompleted = false;
let backupApiAvailable = false;       // 将由 version.php 的 gd_api_available 决定
let stableSourcesList = null;
let mainApiSourceMap = {};
let availablePlatforms = [];

const ALL_PLATFORMS = ['wy', 'tx', 'kw', 'kg', 'mg'];

const MUSIC_QUALITY_FULL = {
    wy: ['128k', '192k', '320k', 'flac', 'flac24bit', 'hires', 'jyeffect', 'sky', 'jymaster'],
    tx: ['128k', '192k', '320k', 'flac', 'flac24bit'],
    kw: ['128k', '192k', '320k', 'flac', 'flac24bit'],
    kg: ['128k', '192k', '320k', 'flac', 'flac24bit'],
    mg: ['128k', '192k', '320k', 'flac', 'flac24bit']
};

const PLATFORM_NAME_MAP = {
    wy: '网易云音乐',
    tx: 'QQ音乐',
    kw: '酷我音乐',
    kg: '酷狗音乐',
    mg: '咪咕音乐'
};

const BACKUP_SOURCE_MAP = {
    kg: 'kg',
    tx: 'qq',
    mg: 'migu'
};

const NETEASE_VIP_LEVEL_MAP = {
    'hires': 'hires',
    'jyeffect': 'jyeffect',
    'sky': 'sky',
    'jymaster': 'jymaster'
};

const NETEASE_VIP_QUALITY_SET = new Set(['hires', 'jyeffect', 'sky', 'jymaster']);

const { EVENT_NAMES, request, on, send } = globalThis.lx;

// ============================ 工具函数 ============================

function log(...args) {
    console.log('[星海]', ...args);
}

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function logSimple(action, source, musicInfo, status, extra = '') {
    const songName = musicInfo.name || '未知歌曲';
    log(`[${action}] 平台:${source} | 歌曲:${songName} | 状态:${status}${extra ? ' | ' + extra : ''}`);
}

function buildQueryString(params) {
    const parts = [];
    for (const key in params) {
        if (params.hasOwnProperty(key)) {
            const value = params[key];
            if (value !== undefined && value !== null && value !== '') {
                parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
            }
        }
    }
    return parts.join('&');
}

function mapQuality(targetQuality, availableQualities) {
    const priorityMap = {
        '臻品母带': 'jymaster',
        '臻品音质2.0': 'sky',
        '臻品音质AI': 'jyeffect',
        '臻品音质': 'jyeffect',
        'Hires 无损24-Bit': 'hires',
        'Hi-Res': 'hires',
        'FLAC': 'flac',
        '320k': '320k',
        '192k': '192k',
        '128k': '128k'
    };
    if (availableQualities.includes(targetQuality)) return targetQuality;
    const mapped = priorityMap[targetQuality];
    if (mapped && availableQualities.includes(mapped)) return mapped;
    const order = ['jymaster', 'sky', 'jyeffect', 'hires', 'flac24bit', 'flac', '320k', '192k', '128k'];
    for (const q of order) if (availableQualities.includes(q)) return q;
    return availableQualities[0] || '128k';
}

const httpFetch = (url, options = { method: 'GET' }) => {
    return new Promise((resolve, reject) => {
        const cancelRequest = request(url, options, (err, resp) => {
            if (err) return reject(new Error(`网络请求异常：${err.message}`));
            let body = resp.body;
            if (typeof body === 'string') {
                const trimmed = body.trim();
                if (trimmed.startsWith('{') || trimmed.startsWith('[') || trimmed.startsWith('"')) {
                    try { body = JSON.parse(trimmed); } catch (e) {}
                }
            }
            resolve({ body, statusCode: resp.statusCode, headers: resp.headers || {} });
        });
    });
};

const compareVersions = (remoteVer, currentVer) => {
    const parse = (v) => {
        const cleaned = v.replace(/^v/, '');
        return cleaned.split('.').map(part => {
            const num = parseInt(part, 10);
            return isNaN(num) ? part : num;
        });
    };
    const r = parse(remoteVer);
    const c = parse(currentVer);
    const maxLen = Math.max(r.length, c.length);
    for (let i = 0; i < maxLen; i++) {
        const rv = r[i] !== undefined ? r[i] : (typeof c[i] === 'number' ? 0 : '');
        const cv = c[i] !== undefined ? c[i] : (typeof r[i] === 'number' ? 0 : '');
        if (typeof rv === 'number' && typeof cv === 'number') {
            if (rv > cv) return true;
            if (rv < cv) return false;
        } else if (typeof rv === 'string' && typeof cv === 'string') {
            if (rv > cv) return true;
            if (rv < cv) return false;
        } else {
            if (typeof rv === 'number' && typeof cv === 'string') return true;
            if (typeof rv === 'string' && typeof cv === 'number') return false;
        }
    }
    return false;
};

function trimSpacesOnly(rawName) {
    if (!rawName) return '';
    return rawName.replace(/\s+/g, ' ').trim();
}

function removeBracketsContent(rawName) {
    if (!rawName) return '';
    let cleaned = rawName.replace(/[（(][^）)]*[）)]/g, '');
    cleaned = cleaned.replace(/\s+/g, ' ').trim();
    return cleaned;
}

function removeSpecialChars(rawName) {
    if (!rawName) return '';
    let cleaned = removeBracketsContent(rawName);
    cleaned = cleaned.replace(/[^\u4e00-\u9fa5\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af\u1100-\u11ff\u3130-\u318fa-zA-Z0-9\s]/g, '');
    cleaned = cleaned.replace(/\s+/g, ' ').trim();
    return cleaned;
}

function cleanStrict(rawName) {
    if (!rawName) return '';
    let cleaned = removeSpecialChars(rawName);
    cleaned = cleaned.replace(/\s+/g, '');
    return cleaned.trim();
}

// ============================ 动态稳定源获取 ============================

const fetchStableSources = async () => {
    log('正在获取服务器稳定源列表...');
    try {
        const resp = await httpFetch(STABLE_SOURCES_API_URL, {
            method: 'GET', timeout: 5000,
            headers: { 'User-Agent': 'LX-Music-Mobile/星海音乐源' }
        });
        if (resp.statusCode !== 200) throw new Error(`HTTP ${resp.statusCode}`);
        let data = resp.body;
        if (typeof data === 'string') {
            try { data = JSON.parse(data); } catch (e) { throw new Error('JSON解析失败'); }
        }
        if (!Array.isArray(data) || data.length === 0) throw new Error('返回数据非数组或为空');
        stableSourcesList = data;
        log('✅ 获取稳定源成功:', stableSourcesList);
    } catch (err) {
        log('❌ 获取稳定源失败，使用默认值 [netease, kuwo]:', err.message);
        stableSourcesList = ['netease', 'kuwo'];
    }
};

const buildPlatformsFromStableSources = () => {
    const sourceToCode = {
        netease: 'wy', tencent: 'tx', kuwo: 'kw', kugou: 'kg', migu: 'mg'
    };
    mainApiSourceMap = {};
    stableSourcesList.forEach(src => {
        const code = sourceToCode[src];
        if (code) mainApiSourceMap[code] = src;
    });
    availablePlatforms = [...ALL_PLATFORMS];
    log('主API支持映射:', mainApiSourceMap);
    log('最终可用平台:', availablePlatforms);
};

// ============================ 服务器状态检查（改用 version.php） ============================

const fetchServerStatus = async () => {
    log('正在通过 version.php 检查服务器状态...');
    for (let attempt = 0; attempt <= 2; attempt++) {
        if (attempt > 0) await delay(1000);
        try {
            const resp = await httpFetch(UPDATE_CONFIG.versionApiUrl, {
                method: 'GET', timeout: 5000,
                headers: { 'User-Agent': 'LX-Music-Mobile/星海音乐源' }
            });
            if (resp.statusCode !== 200) throw new Error(`HTTP ${resp.statusCode}`);
            const data = typeof resp.body === 'object' ? resp.body : JSON.parse(resp.body);
            if (!data || typeof data !== 'object') throw new Error('无效数据格式');
            
            const gdAvailable = data.gd_api_available !== undefined ? data.gd_api_available : true;
            backupApiAvailable = gdAvailable;
            log(`GD API 可用状态: ${gdAvailable ? '可用' : '不可用'}，备用API ${gdAvailable ? '已启用' : '已禁用'}`);
            
            return {
                enabled: true,
                message: gdAvailable ? '服务正常' : 'GD API 不可用，部分功能受限',
                error: null,
                remoteVersion: data.version || null,
                remoteChangelog: data.changelog || ''
            };
        } catch (err) {
            log(`状态检查失败(第${attempt + 1}次):`, err.message);
            if (attempt === 2) {
                log('状态检查多次失败，使用本地模式');
                backupApiAvailable = false;
                return { enabled: true, message: `服务器连接失败，使用本地模式: ${err.message}`, error: err.message, remoteVersion: null, remoteChangelog: '' };
            }
        }
    }
    backupApiAvailable = false;
    return { enabled: true, message: '未知错误，使用本地模式', error: '未知错误', remoteVersion: null, remoteChangelog: '' };
};

// ============================ 搜索功能 ============================

async function handleSearch(source, info) {
    if (!backupApiAvailable) {
        throw new Error('搜索功能暂不可用（服务器连接异常）');
    }
    if (!['kg', 'tx', 'mg'].includes(source)) {
        throw new Error(`平台 ${source} 暂不支持搜索`);
    }
    const backupSource = BACKUP_SOURCE_MAP[source];
    const keyword = info.key || info.keyword || '';
    if (!keyword) throw new Error('请输入搜索关键词');
    const limit = info.limit || 20;
    const params = { source: backupSource, msg: keyword, n: '0', g: String(limit) };
    if (backupSource === 'migu') {
        params.num = String(limit);
        delete params.g;
    }
    const url = `${BACKUP_API_BASE}?${buildQueryString(params)}`;
    log(`搜索请求: ${url}`);
    const resp = await httpFetch(url);
    if (resp.statusCode !== 200) throw new Error(`搜索接口 HTTP ${resp.statusCode}`);
    const data = resp.body;
    if (data.code !== 200) throw new Error(data.msg || '搜索失败');
    const songs = data.data?.songs || [];
    const list = songs.map((item, index) => {
        const songId = item.hash || item.mid || item.id || String(index);
        const name = item.title || item.name || '未知歌曲';
        const singer = item.singer || item.author || '未知歌手';
        const album = item.album || item.albumname || '';
        const img = item.cover || item.picture || '';
        const interval = item.duration ? Math.floor(parseInt(item.duration) * 1000) : null;
        return { singer, name, album, source, songmid: songId, interval, img, lrc: null, hash: songId, albumId: item.albumid || '', lyricUrl: null };
    });
    return { list, total: data.data?.total || list.length, limit, page: info.page || 1, source };
}

// ============================ 音频地址解析 ============================

const getMusicUrlFromMainAPI = async (source, songId, apiQuality) => {
    const apiSource = mainApiSourceMap[source];
    if (!apiSource) throw new Error('主API不支持此平台');
    const url = `${MAIN_API_BASE}&types=url&source=${apiSource}&id=${songId}&br=${apiQuality}`;
    const resp = await httpFetch(url, {
        method: 'GET',
        headers: { 'User-Agent': 'LX-Music-Mobile', 'Accept': 'application/json' }
    });
    const data = typeof resp.body === 'object' ? resp.body : JSON.parse(resp.body);
    if (!data.url) throw new Error('主API未返回音频地址');
    return data.url;
};

const getMusicUrlFromNeteaseVIP = async (songId, quality) => {
    const level = NETEASE_VIP_LEVEL_MAP[quality] || 'jymaster';
    const url = `${NETEASE_VIP_API}?id=${songId}&level=${level}`;
    log(`网易云VIP API请求: ${url}`);
    const resp = await httpFetch(url, {
        method: 'GET',
        headers: { 'User-Agent': 'LX-Music-Mobile', 'Accept': 'application/json' }
    });
    if (resp.statusCode !== 200) throw new Error(`网易云VIP API HTTP ${resp.statusCode}`);
    const data = typeof resp.body === 'object' ? resp.body : JSON.parse(resp.body);
    if (data.code !== 200 || !data.data?.url) {
        throw new Error(data.msg || '网易云VIP接口未返回音频地址');
    }
    log(`网易云VIP API返回: br=${data.data.br}, level=${data.data.level}, 歌曲:${data.data.name}`);
    return data.data.url;
};

function stringMatchScore(str1, str2) {
    if (!str1 || !str2) return 0;
    const s1 = str1.toLowerCase().replace(/\s+/g, ' ').trim();
    const s2 = str2.toLowerCase().replace(/\s+/g, ' ').trim();
    if (s1 === s2) return 1.0;
    if (s1.includes(s2) || s2.includes(s1)) return 0.9;
    const maxLen = Math.max(s1.length, s2.length);
    let matches = 0;
    for (let i = 0; i < Math.min(s1.length, s2.length); i++) {
        if (s1[i] === s2[i]) matches++;
    }
    return matches / maxLen;
}

function findBestMatchSong(originalName, originalSinger, songs) {
    if (!songs || songs.length === 0) return null;
    let bestIndex = 1;
    let bestScore = -1;
    songs.forEach((song, idx) => {
        const songName = song.title || song.name || '';
        const songSinger = song.singer || song.author || '';
        const nameScore = stringMatchScore(originalName, songName);
        const singerScore = stringMatchScore(originalSinger, songSinger);
        const totalScore = nameScore * 0.6 + singerScore * 0.4;
        if (totalScore > bestScore) {
            bestScore = totalScore;
            bestIndex = idx + 1;
        }
    });
    return bestScore >= 0.3 ? bestIndex : null;
}

const getMusicUrlFromBackup = async (source, musicInfo, quality) => {
    if (!backupApiAvailable) {
        throw new Error('备用接口暂不可用（服务器连接异常）');
    }
    const backupSource = BACKUP_SOURCE_MAP[source];
    if (!backupSource) throw new Error('备用接口不支持此平台');
    const songName = musicInfo.name || '';
    const songSinger = musicInfo.singer || '';
    if (!songName) throw new Error('歌曲信息缺失，无法使用备用接口');
    
    const keywords = [];
    const kw1 = trimSpacesOnly(songName);
    const kw2 = removeBracketsContent(songName);
    const kw3 = removeSpecialChars(songName);
    const kw4 = cleanStrict(songName);
    if (kw1 && !keywords.includes(kw1)) keywords.push(kw1);
    if (kw2 && !keywords.includes(kw2)) keywords.push(kw2);
    if (kw3 && !keywords.includes(kw3)) keywords.push(kw3);
    if (kw4 && !keywords.includes(kw4)) keywords.push(kw4);
    if (!keywords.includes(songName)) keywords.push(songName);
    
    let searchData = null;
    let usedKeyword = '';
    for (const kw of keywords) {
        const searchParams = { source: backupSource, msg: kw, n: '0', g: '10' };
        if (backupSource === 'migu') {
            searchParams.num = '10';
            delete searchParams.g;
        }
        const searchUrl = `${BACKUP_API_BASE}?${buildQueryString(searchParams)}`;
        log(`备用API搜索 (关键词: "${kw}"): ${searchUrl}`);
        try {
            const searchResp = await httpFetch(searchUrl);
            if (searchResp.statusCode !== 200) {
                log(`关键词 "${kw}" HTTP ${searchResp.statusCode}，尝试下一个`);
                continue;
            }
            const data = searchResp.body;
            if (data.code !== 200) {
                log(`关键词 "${kw}" 业务code ${data.code} (${data.msg || ''})，尝试下一个`);
                continue;
            }
            const songs = data.data?.songs || [];
            if (songs.length > 0) {
                searchData = data;
                usedKeyword = kw;
                break;
            } else {
                log(`关键词 "${kw}" 返回0条结果，尝试下一个`);
            }
        } catch (e) {
            log(`关键词 "${kw}" 搜索异常:`, e.message);
        }
    }
    if (!searchData) {
        throw new Error('所有关键词均未搜索到歌曲（可能接口异常或歌曲不存在）');
    }
    
    const songs = searchData.data?.songs || [];
    log(`使用关键词 "${usedKeyword}" 搜索到 ${songs.length} 条结果`);
    const bestN = findBestMatchSong(songName, songSinger, songs);
    if (bestN === null) throw new Error('未找到匹配的歌曲');
    log(`备用API匹配结果: n=${bestN}, 歌曲: ${songs[bestN-1]?.title || songs[bestN-1]?.name}`);
    
    const detailParams = { source: backupSource, msg: usedKeyword, n: String(bestN) };
    if (backupSource === 'kg') {
        const qMap = { '128k': '128', '192k': '192', '320k': '320', 'flac': 'flac', 'flac24bit': 'flac' };
        detailParams.quality = qMap[quality] || '320';
    } else if (backupSource === 'qq') {
        detailParams.size = 'hq';
    }
    const detailUrl = `${BACKUP_API_BASE}?${buildQueryString(detailParams)}`;
    log(`备用API详情请求: ${detailUrl}`);
    const detailResp = await httpFetch(detailUrl);
    if (detailResp.statusCode !== 200) throw new Error(`详情接口 HTTP ${detailResp.statusCode}`);
    const detailData = detailResp.body;
    if (detailData.code !== 200) throw new Error(detailData.msg || '获取详情失败');
    
    const data = detailData.data;
    let musicUrl = '';
    if (backupSource === 'kg') {
        musicUrl = data?.play_url || data?.music_url || data?.url || data?.musicurl;
    } else if (backupSource === 'qq') {
        musicUrl = data?.musicurl || data?.music_url?.url || data?.url || data?.play_url;
    } else if (backupSource === 'migu') {
        musicUrl = data?.music_url || data?.url || data?.play_url;
    }
    if (!musicUrl) throw new Error('备用API返回数据中未找到音频地址');
    return musicUrl;
};

const handleGetMusicUrl = async (source, musicInfo, quality) => {
    if (!musicSourceEnabled) throw new Error('服务暂时不可用');
    if (!serverCheckCompleted) throw new Error('服务初始化中，请稍后');
    
    const songId = musicInfo.hash ?? musicInfo.songmid ?? musicInfo.id;
    if (!songId) throw new Error('歌曲信息不完整');
    
    logSimple('解析音频地址', source, musicInfo, '开始');
    
    const avail = MUSIC_QUALITY_FULL[source] || ['128k', '192k', '320k', 'flac'];
    let actual = mapQuality(quality, avail);
    if (actual !== quality) log(`音质自动映射: ${quality} -> ${actual}`);
    
    let finalUrl = null;
    let lastErr = null;
    
    // ========== 网易云VIP高音质：走专属API（hires/jyeffect/sky/jymaster）==========
    if (source === 'wy' && NETEASE_VIP_QUALITY_SET.has(actual)) {
        try {
            finalUrl = await getMusicUrlFromNeteaseVIP(songId, actual);
            logSimple('解析音频地址', source, musicInfo, '成功(网易云VIP API)');
            return finalUrl;
        } catch (err) {
            lastErr = err;
            logSimple('解析音频地址', source, musicInfo, '网易云VIP API失败，回退到GDAPI', err.message);
            actual = 'flac24bit';
        }
    }
    
    // ========== 主API (GDAPI) - 前5档音质保持不变 ==========
    if (mainApiSourceMap[source]) {
        try {
            const brMap = { '128k': '128', '192k': '192', '320k': '320', 'flac': '740', 'flac24bit': '999' };
            const apiBr = brMap[actual] || '320';
            finalUrl = await getMusicUrlFromMainAPI(source, songId, apiBr);
            logSimple('解析音频地址', source, musicInfo, '成功(GDAPI)');
        } catch (err) {
            lastErr = err;
            logSimple('解析音频地址', source, musicInfo, 'GDAPI失败，尝试备用API', err.message);
        }
    } else {
        log(`主API不支持平台 ${source}，直接使用备用API`);
    }
    
    // ========== 备用API ==========
    if (!finalUrl && backupApiAvailable && BACKUP_SOURCE_MAP[source]) {
        try {
            finalUrl = await getMusicUrlFromBackup(source, musicInfo, actual);
            logSimple('解析音频地址', source, musicInfo, '成功(备用API)');
        } catch (err) {
            lastErr = err;
            logSimple('解析音频地址', source, musicInfo, '备用API失败', err.message);
        }
    }
    
    if (!finalUrl) {
        const msg = `无法获取音频地址：${lastErr ? lastErr.message : '未知错误'}`;
        logSimple('解析音频地址', source, musicInfo, '完全失败', msg);
        throw new Error(msg);
    }
    
    return finalUrl;
};

// ============================ 构建音乐源对象 ============================

const buildMusicSources = (platforms) => {
    const sources = {};
    platforms.forEach(code => {
        sources[code] = {
            name: PLATFORM_NAME_MAP[code] || code,
            type: 'music',
            actions: ['musicUrl'],
            qualitys: MUSIC_QUALITY_FULL[code]
        };
    });
    return sources;
};

// ============================ 事件监听 ============================

on(EVENT_NAMES.request, ({ action, source, info }) => {
    if (action === 'musicUrl') {
        if (!info?.musicInfo || !info.type) return Promise.reject(new Error('请求参数不完整'));
        return handleGetMusicUrl(source, info.musicInfo, info.type);
    } else if (action === 'search') {
        if (!info) return Promise.reject(new Error('搜索参数缺失'));
        return handleSearch(source, info);
    } else {
        return Promise.reject(new Error('不支持的操作类型'));
    }
});

// ============================ 初始化 ============================

(async () => {
    log('========================================');
    log('星海音乐源 v2.3.1 初始化（新版合并接口）');
    log('========================================');
    try {
        const server = await fetchServerStatus();   // 改用 version.php 检查状态
        musicSourceEnabled = server.enabled;
        backupApiAvailable = server.enabled;        // 服务器能连通则启用备用
        
        if (!musicSourceEnabled) {
            log('⚠️ 服务器状态异常，服务受限:', server.message);
        } else {
            log('✅ 服务器状态正常，搜索和备用播放已启用');
        }
        
        await fetchStableSources();
        buildPlatformsFromStableSources();
        serverCheckCompleted = true;
        const sources = buildMusicSources(availablePlatforms);
        send(EVENT_NAMES.inited, { status: true, openDevTools: false, sources, initStatus: 'ready' });
        log('✅ 初始化完成，全部平台:', availablePlatforms.join(', '));
        
        // 延迟检查更新（仍是原来的 version.php，但现在它会返回版本）
        setTimeout(() => checkAutoUpdate(), 3000);
    } catch (err) {
        log('❌ 初始化异常，进入降级模式:', err.message);
        stableSourcesList = ['netease', 'kuwo'];
        buildPlatformsFromStableSources();
        musicSourceEnabled = true;
        backupApiAvailable = false;
        serverCheckCompleted = true;
        const sources = buildMusicSources(availablePlatforms);
        send(EVENT_NAMES.inited, { status: true, openDevTools: false, sources, initStatus: 'degraded' });
        log('降级模式完成，全部平台仍显示，但仅主API支持的可用');
        setTimeout(() => checkAutoUpdate(), 3000);
    }
})();

async function checkAutoUpdate() {
    if (!musicSourceEnabled) return;
    try {
        const resp = await httpFetch(UPDATE_CONFIG.versionApiUrl, {
            timeout: 10000,
            headers: { 'Content-Type': 'application/json', 'User-Agent': 'LX-Music-Mobile' }
        });
        if (resp.statusCode !== 200) return;
        let data = resp.body;
        if (typeof data === 'string') {
            try { data = JSON.parse(data.trim().replace(/^\uFEFF/, '')); } catch (e) { return; }
        }
        if (!data || typeof data !== 'object') return;
        
    
       const remoteVer = data.version || null;
        if (!remoteVer) return;
        
        const needUpdate = data.need_update !== undefined ? data.need_update : compareVersions(remoteVer, UPDATE_CONFIG.currentVersion);
        const changelog = data.changelog || '暂无更新日志';
        
        if (needUpdate) {
            log('发现新版本:', remoteVer, '当前版本:', UPDATE_CONFIG.currentVersion);
            const updateUrl = data.update_url || UPDATE_CONFIG.latestScriptUrl;
            const msg = `【星海音乐源更新通知】\n当前版本：${UPDATE_CONFIG.currentVersion}\n最新版本：${remoteVer}\n\n更新内容：\n${changelog}`;
            send(EVENT_NAMES.updateAlert, { log: msg, updateUrl, confirmText: '立即更新', cancelText: '暂不更新' });
        }
    } catch (err) {
        log('更新检查失败:', err.message);
    }
}