/*!
 * @name 全豆要[聚合音源]
 * @description 迭代4.0版本，聚合 星海/Huibq/聆川/溯音/念心/长青/歌一刀专属汽水音乐，多链路自动回退
 * @version v4.0
 * @author 全豆要 and Gemini优化 Toskysun去混淆
 */

// --- 常量定义 ---
const CACHE_TTL_MS = 21600000;
const CACHE_MAX_SIZE = 500;
const HTTP_URL_REGEX = /^https?:\/\//i;

// API 端点
const XINGHAI_MAIN_API = "https://music-api.gdstudio.xyz/api.php?use_xbridge3=true&loader_name=forest&need_sec_link=1&sec_link_scene=im&theme=light";
const XINGHAI_BACKUP_API = "https://music-dl.sayqz.com/api/";
const HUIBQ_API = "https://lxmusicapi.onrender.com";
const HUIBQ_REQUEST_KEY = "share-v3";
const LINGCHUAN_API = "https://lc.guoyue2010.top/api/music";
const SUYIN_QQ_API = "https://oiapi.net/api/QQ_Music";
const SUYIN_QQ_KEY = "oiapi-ef6133b7-ac2f-dc7d-878c-d3e207a82575";
const SUYIN_163_API = "https://oiapi.net/api/Music_163";
const SUYIN_KUWO_API = "https://oiapi.net/api/Kuwo";
const SUYIN_MIGU_API = "https://api.xcvts.cn/api/music/migu";

// 长青SVIP URL模板
const CHANGQING_URL_TEMPLATES = {
  tx: "http://175.27.166.236/kgqq/qq.php?type=mp3&id={id}&level={level}",
  wy: "http://175.27.166.236/wy/wy.php?type=mp3&id={id}&level={level}",
  kw: "https://musicapi.haitangw.net/music/kw.php?type=mp3&id={id}&level={level}",
  kg: "https://music.haitangw.cc/kgqq/kg.php?type=mp3&id={id}&level={level}",
  mg: "https://music.haitangw.cc/musicapi/mg.php?type=mp3&id={id}&level={level}"
};

// 念心SVIP URL模板
const NIANXIN_URL_TEMPLATES = {
  tx: "https://music.nxinxz.com/kgqq/tx.php?id={id}&level={level}&type=mp3",
  wy: "http://music.nxinxz.com/wy.php?id={id}&level={level}&type=mp3",
  kw: "http://music.nxinxz.com/kw.php?id={id}&level={level}&type=mp3",
  kg: "https://music.nxinxz.com/kgqq/kg.php?id={id}&level={level}&type=mp3",
  mg: "http://music.nxinxz.com/mg.php?id={id}&level={level}&type=mp3"
};

// 汽水VIP
const QISHUI_SOURCE_ID = "qsvip";
const QISHUI_SOURCE_NAME = "汽水VIP";
const QISHUI_API_HTTPS = "https://api.vsaa.cn/api/music.qishui.vip";
const QISHUI_API_HTTP = "http://api.vsaa.cn/api/music.qishui.vip";
const QISHUI_PROXY_API = "https://proxy.qishui.vsaa.cn/qishui/proxy";

// 各平台支持的音质列表
const PLATFORM_QUALITIES = {
  wy: ["24bit", "flac", "320k", "192k", "128k"],
  tx: ["24bit", "flac", "320k", "192k", "128k"],
  kw: ["24bit", "flac", "320k", "192k", "128k"],
  kg: ["24bit", "flac", "320k", "192k", "128k"],
  mg: ["24bit", "flac", "320k", "192k", "128k"]
};

// 平台ID映射到星海主API名称
const PLATFORM_TO_XINGHAI = {
  wy: "netease",
  tx: "tencent",
  kw: "kuwo",
  kg: "kugou",
  mg: "migu"
};

// 音质到星海主API码率参数
const QUALITY_TO_BR = {
  "128k": "128",
  "192k": "192",
  "320k": "320",
  flac: "740",
  flac24bit: "999",
  "24bit": "999"
};

// 平台ID映射到星海备API名称
const PLATFORM_TO_XINGHAI_BACKUP = {
  wy: "netease",
  tx: "qq",
  kw: "kuwo"
};

// 音质到溯音QQ码率参数
const QUALITY_TO_SUYIN_QQ_BR = {
  "128k": 7,
  "320k": 5,
  flac: 4,
  hires: 3,
  atmos: 2,
  master: 1,
  "24bit": 1
};

// 音质到溯音酷我码率参数
const QUALITY_TO_KUWO_BR = {
  flac: 1,
  "320k": 5,
  "128k": 7,
  "24bit": 1
};

// 高品质音质集合
const HIRES_QUALITY_SET = new Set(["24bit", "flac", "flac24bit", "hires", "master", "atmos"]);

// URL缓存
const urlCache = new Map();

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

// 空函数（占位/日志）
function noop() {}

// 发起HTTP请求，返回 Promise<{statusCode, headers, body}>
function httpRequest(url, options = { method: "GET" }) {
  return new Promise((resolve, reject) => {
    request(url, {
      timeout: 2000,
      ...options
    }, (err, res) => {
      if (err) {
        return reject(new Error("请求错误: " + err.message));
      }
      let body = res?.body;
      if (typeof body === "string") {
        const trimmed = body.trim();
        if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.startsWith("\"")) {
          try {
            body = JSON.parse(trimmed);
          } catch (e2) {}
        }
      }
      resolve({
        statusCode: res?.statusCode ?? 0,
        headers: res?.headers || {},
        body: body
      });
    });
  });
}

// 发起GET请求，自动拼接查询参数，返回响应body
async function httpGet(url, params = {}) {
  const queryStr = Object.keys(params)
    .filter(k => params[k] !== undefined && params[k] !== null)
    .map(k => encodeURIComponent(k) + "=" + encodeURIComponent(params[k]))
    .join("&");
  const sep = url.includes("?") ? "&" : "?";
  const fullUrl = "" + url + (queryStr ? sep + queryStr : "");
  const res = await httpRequest(fullUrl, {
    method: "GET",
    timeout: 2000
  });
  if (res.statusCode >= 400) {
    throw new Error("HTTP错误: " + res.statusCode);
  }
  return res.body;
}

// 构建查询字符串（带前导 ?）
function buildQueryString(params = {}) {
  const parts = Object.keys(params)
    .filter(k => params[k] !== undefined && params[k] !== null)
    .map(k => encodeURIComponent(String(k)) + "=" + encodeURIComponent(String(params[k])));
  if (parts.length) {
    return "?" + parts.join("&");
  } else {
    return "";
  }
}

// 带fallback的GET请求（汽水VIP自动尝试https/http）
async function httpGetWithFallback(url, params = {}, timeout = 5000) {
  const urls = url === QISHUI_API_HTTPS ? [QISHUI_API_HTTPS, QISHUI_API_HTTP] : [url];
  let lastError = null;
  for (const u of urls) {
    try {
      const fullUrl = "" + u + buildQueryString(params);
      const res = await httpRequest(fullUrl, {
        method: "GET",
        timeout: timeout
      });
      if (res.statusCode >= 400) {
        throw new Error("HTTP " + res.statusCode);
      }
      return res.body;
    } catch (e3) {
      lastError = e3;
    }
  }
  throw lastError || new Error("汽水VIP请求失败");
}

// 发起POST请求，body为JSON，返回响应body
async function httpPost(url, body = {}, timeout = 5000) {
  const res = await httpRequest(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: body,
    timeout: timeout
  });
  if (res.statusCode >= 400) {
    throw new Error("HTTP错误: " + res.statusCode);
  }
  return res.body;
}

// 从歌曲信息对象中提取歌曲ID字符串
function getSongId(songInfo) {
  return (songInfo?.id || songInfo?.songmid || songInfo?.songId || songInfo?.hash || songInfo?.rid || songInfo?.mid || songInfo?.strMediaMid || songInfo?.mediaId || "").toString();
}

// 标准化音质字符串
function normalizeQuality(quality) {
  switch (String(quality || "").toLowerCase()) {
    case "128k":
      return "low";
    case "320k":
      return "standard";
    case "flac":
      return "lossless";
    case "flac24bit":
      return "flac24bit";
    default:
      return "128k";
  }
}

// 标准化歌曲信息为统一格式
function normalizeSongInfo(raw) {
  const id = raw?.id || raw?.vid ? String(raw.id || raw.vid) : "";
  return {
    id: id,
    songmid: id,
    hash: id,
    name: raw?.name ? String(raw.name) : "未知歌曲",
    singer: raw?.artists ? String(raw.artists) : "未知歌手",
    albumName: raw?.album ? String(raw.album) : "",
    duration: raw?.duration ? Math.floor(Number(raw.duration) / 1000) : 0,
    pic: raw?.cover || raw?.pic ? String(raw.cover || raw.pic) : "",
    _raw: raw || {}
  };
}

// 获取响应数据中的第一条记录
function getFirstData(response) {
  const data = response?.data;
  if (Array.isArray(data)) {
    return data[0] || null;
  }
  if (data && typeof data === "object" && data[0]) {
    return data[0];
  }
  return null;
}

// 汽水VIP搜索
async function qishuiSearch(keyword, page = 1, pageSize = 30) {
  if (!keyword) {
    return {
      isEnd: true,
      list: []
    };
  }
  const res = await httpGetWithFallback(QISHUI_API_HTTPS, {
    act: "search",
    keywords: keyword,
    page: page,
    pagesize: pageSize,
    type: "music"
  }, 15000);
  const list = Array.isArray(res?.data?.lists) ? res.data.lists : [];
  const total = res?.data?.total ? Number(res.data.total) : list.length;
  return {
    isEnd: list.length < pageSize,
    list: list.map(normalizeSongInfo),
    total: total
  };
}

// 汽水VIP获取播放URL
async function qishuiGetUrl(songInfo, quality) {
  const songId = getSongId(songInfo);
  if (!songId) {
    throw new Error("汽水VIP缺少歌曲ID");
  }
  const res = await httpGetWithFallback(QISHUI_API_HTTPS, {
    act: "song",
    id: songId,
    quality: normalizeQuality(quality)
  }, 20000);
  const data = getFirstData(res);
  if (!data?.url) {
    throw new Error("汽水VIP未返回可用URL");
  }
  if (data.ekey) {
    const proxyRes = await httpPost(QISHUI_PROXY_API, {
      url: data.url,
      key: data.ekey,
      filename: data.filename || "KMusic",
      ext: data.fileExtension ? String(data.fileExtension) : "aac"
    }, 60000);
    if (Number(proxyRes?.code) === 200 && proxyRes?.url) {
      return String(proxyRes.url);
    }
    throw new Error("汽水VIP代理解密失败");
  }
  return String(data.url);
}

// 汽水VIP获取歌词
async function qishuiGetLyric(songInfo) {
  const songId = getSongId(songInfo);
  if (!songId) {
    return { lyric: "" };
  }
  const res = await httpGetWithFallback(QISHUI_API_HTTPS, {
    act: "song",
    id: songId
  }, 15000);
  const data = getFirstData(res);
  return {
    lyric: data?.lyric ? String(data.lyric) : ""
  };
}

// 汽水VIP统一处理器（搜索/获取URL/获取歌词）
async function qishuiHandler(action, params = {}) {
  if (action === "musicSearch" || action === "search") {
    const keyword = params?.keyword ? String(params.keyword) : "";
    const page = params?.page ? Number(params.page) : 1;
    const pageSize = params?.pagesize ? Number(params.pagesize) : 30;
    return qishuiSearch(keyword, page, pageSize);
  }
  if (action === "musicUrl") {
    if (!params?.musicInfo) {
      throw new Error("请求参数不完整");
    }
    const url = await qishuiGetUrl(params.musicInfo, params.type);
    return validateUrl(url, "汽水VIP");
  }
  if (action === "lyric") {
    return qishuiGetLyric(params?.musicInfo || {});
  }
  throw new Error("action not support");
}

// 从支持的音质列表中选择最接近的音质
function selectQuality(requestedQuality, supportedQualities) {
  if (requestedQuality === "24bit") {
    return "24bit";
  }
  const qualityList = Array.isArray(supportedQualities) ? supportedQualities : ["128k"];
  const normalized = String(requestedQuality || "128k").toLowerCase();
  if (qualityList.includes(normalized)) {
    return normalized;
  }
  const qualityOrder = ["flac24bit", "flac", "320k", "192k", "128k"];
  let idx = qualityOrder.indexOf(normalized);
  if (idx < 0) {
    idx = qualityOrder.length - 1;
  }
  for (let i = idx; i < qualityOrder.length; i++) {
    if (qualityList.includes(qualityOrder[i])) {
      return qualityOrder[i];
    }
  }
  for (let i = qualityOrder.length - 1; i >= 0; i--) {
    if (qualityList.includes(qualityOrder[i])) {
      return qualityOrder[i];
    }
  }
  return qualityList[0] || "128k";
}

// 标准化关键词（去除括号、空格、特殊字符，转小写）
function normalizeKeyword(keyword) {
  if (!keyword) {
    return "";
  }
  return String(keyword)
    .replace(/\(\s*Live\s*\)/gi, "")
    .replace(/\([^)]*\)/g, "")
    .replace(/\s+/g, "")
    .replace(/[^\w\u4e00-\u9fa5]/g, "")
    .trim()
    .toLowerCase();
}

// 构建搜索关键词列表（标题+专辑、标题+歌手、仅标题）
function buildSearchKeywords(songInfo) {
  const keywords = [];
  const name = songInfo?.name || "";
  const album = songInfo?.albumName || songInfo?.album || "";
  const singer = songInfo?.singer || "";
  if (name && album) {
    const kw = normalizeKeyword(name + album);
    if (kw) {
      keywords.push({ keyword: kw, strict: true });
    }
  }
  if (name && singer) {
    const kw = normalizeKeyword(name + singer);
    if (kw) {
      keywords.push({ keyword: kw, strict: true });
    }
  }
  if (name) {
    const kw = normalizeKeyword(name);
    if (kw) {
      keywords.push({ keyword: kw, strict: false });
    }
  }
  return keywords;
}

// 标题模糊匹配（双向包含）
function titleMatch(a, b) {
  const na = normalizeKeyword(a);
  const nb = normalizeKeyword(b);
  if (!na || !nb) {
    return true;
  }
  return na.includes(nb) || nb.includes(na);
}

// 歌曲信息匹配（song/singer/album字段）
function songInfoMatch(responseData, songInfo) {
  const song = responseData?.song || responseData?.data?.song || "";
  const singer = responseData?.singer || responseData?.data?.singer || "";
  const album = responseData?.album || responseData?.data?.album || "";
  if (!titleMatch(song, songInfo?.name || "")) {
    return false;
  }
  if (songInfo?.singer && singer && !titleMatch(singer, songInfo.singer)) {
    return false;
  }
  if ((songInfo?.albumName || songInfo?.album) && album && !titleMatch(album, songInfo.albumName || songInfo.album)) {
    return false;
  }
  return true;
}

// 歌曲标题匹配（title/artist/album字段）
function songTitleMatch(responseData, songInfo) {
  if (!titleMatch(responseData?.title || "", songInfo?.name || "")) {
    return false;
  }
  if (songInfo?.singer && responseData?.artist && !titleMatch(responseData.artist, songInfo.singer)) {
    return false;
  }
  if ((songInfo?.albumName || songInfo?.album) && responseData?.album && !titleMatch(responseData.album, songInfo.albumName || songInfo.album)) {
    return false;
  }
  return true;
}

// 从消息文本中解析歌曲信息（歌名/歌手/专辑）
function parseMessageSongInfo(message) {
  if (!message) {
    return null;
  }
  const result = {};
  const lines = String(message).split("\n");
  for (const line of lines) {
    if (line.startsWith("歌名：")) {
      result.song = line.replace("歌名：", "").trim();
    }
    if (line.startsWith("歌手：")) {
      result.singer = line.replace("歌手：", "").trim();
    }
    if (line.startsWith("专辑：")) {
      result.album = line.replace("专辑：", "").trim();
    }
  }
  if (result.song) {
    return result;
  } else {
    return null;
  }
}

// 获取歌曲的hash或mid（优先hash）
function getHashOrMid(songInfo) {
  return songInfo?.hash ?? songInfo?.songmid ?? songInfo?.id ?? null;
}

// 获取QQ音乐歌曲ID（区分mid字符串和songid数字）
function getQQSongId(songInfo) {
  const mid = songInfo?.meta?.qq?.mid || songInfo?.meta?.mid || songInfo?.songmid ||
    (typeof songInfo?.id === "string" && !/^\d+$/.test(songInfo.id) ? songInfo.id : null);
  if (mid) {
    return { type: "mid", value: mid };
  }
  const songid = songInfo?.meta?.qq?.songid || songInfo?.meta?.songid ||
    (typeof songInfo?.id === "number" ? songInfo.id :
      (typeof songInfo?.id === "string" && /^\d+$/.test(songInfo.id) ? Number(songInfo.id) : null));
  if (songid) {
    return { type: "songid", value: songid };
  }
  return null;
}

// 将音质转换为网易云格式
function qualityToNetease(quality) {
  const q = String(quality || "128k").toLowerCase();
  if (q === "flac" || q === "flac24bit" || q === "hires" || q === "master" || q === "atmos") {
    return "lossless";
  }
  if (q === "320k" || q === "192k") {
    return "exhigh";
  }
  return "standard";
}

// 获取平台对应的歌曲ID
function getPlatformSongId(platform, songInfo) {
  if (platform === "kg") {
    return songInfo?.hash || songInfo?.songmid || songInfo?.id || songInfo?.rid || songInfo?.mid || null;
  }
  if (platform === "tx") {
    const qqId = getQQSongId(songInfo);
    if (qqId?.value) {
      return qqId.value;
    }
  }
  return songInfo?.songmid || songInfo?.id || songInfo?.songId || songInfo?.rid || songInfo?.hash || null;
}

// 构建模板URL（替换{id}和{level}占位符）
function buildTemplateUrl(platform, quality, songInfo, templates, sourceName) {
  const template = templates[platform];
  if (!template) {
    throw new Error(sourceName + "不支持该平台");
  }
  const songId = getPlatformSongId(platform, songInfo);
  if (!songId) {
    throw new Error(sourceName + "缺少songId");
  }
  const level = qualityToNetease(quality);
  return template
    .replace("{id}", encodeURIComponent(String(songId)))
    .replace("{level}", encodeURIComponent(level));
}

// 构建缓存键
function buildCacheKey(prefix, songInfo, quality = "") {
  const name = songInfo?.name || "";
  const singer = songInfo?.singer || "";
  const album = songInfo?.albumName || songInfo?.album || "";
  return prefix + "_" + name + "_" + singer + "_" + album + "_" + quality;
}

// 从缓存中获取URL（过期自动删除）
function getCachedUrl(cacheKey) {
  const entry = urlCache.get(cacheKey);
  if (!entry) {
    return null;
  }
  if (Date.now() - entry.timestamp >= CACHE_TTL_MS) {
    urlCache.delete(cacheKey);
    return null;
  }
  return entry.url;
}

// 将URL写入缓存（超出上限时淘汰最旧条目）
function setCachedUrl(cacheKey, url) {
  urlCache.set(cacheKey, {
    url: url,
    timestamp: Date.now()
  });
  if (urlCache.size > CACHE_MAX_SIZE) {
    const oldestKey = urlCache.keys().next().value;
    if (oldestKey !== undefined) {
      urlCache.delete(oldestKey);
    }
  }
}

// 验证URL合法性（必须是http/https开头的字符串）
function validateUrl(url, sourceName) {
  if (!url || typeof url !== "string") {
    throw new Error(sourceName + "返回空URL");
  }
  if (!HTTP_URL_REGEX.test(url.trim())) {
    throw new Error(sourceName + "非法URL格式");
  }
  return url;
}

// 获取移动端User-Agent
function getMobileUserAgent() {
  return "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1";
}

// 星海主API获取URL
async function xinghaiMainGetUrl(platform, songId, quality, songInfo) {
  const source = PLATFORM_TO_XINGHAI[platform];
  if (!source) {
    throw new Error("星海主API不支持该平台");
  }
  const id = songId ?? getHashOrMid(songInfo);
  if (!id) {
    throw new Error("缺少songId");
  }
  const selectedQuality = selectQuality(quality, ["128k", "192k", "320k", "flac", "flac24bit"]);
  const br = QUALITY_TO_BR[selectedQuality];
  if (!br) {
    throw new Error("星海主API音质映射失败");
  }
  const url = XINGHAI_MAIN_API + "&types=url&source=" + source + "&id=" + encodeURIComponent(id) + "&br=" + br;
  const res = await httpRequest(url, {
    method: "GET",
    headers: {
      "User-Agent": "LX-Music-Mobile",
      Accept: "application/json"
    }
  });
  const body = res.body;
  if (!body || typeof body !== "object" || !body.url) {
    throw new Error(body?.message || "星海主API未返回可用URL");
  }
  return body.url;
}

// 星海备API获取URL（返回完整请求URL字符串）
async function xinghaiBackupGetUrl(platform, songId, quality, songInfo) {
  const source = PLATFORM_TO_XINGHAI_BACKUP[platform];
  if (!source) {
    throw new Error("星海备API不支持该平台");
  }
  const id = songId ?? getHashOrMid(songInfo);
  if (!id) {
    throw new Error("缺少songId");
  }
  const selectedQuality = selectQuality(quality, ["128k", "192k", "320k", "flac", "flac24bit"]);
  return XINGHAI_BACKUP_API + "?source=" + encodeURIComponent(source) + "&id=" + encodeURIComponent(id) + "&type=url&br=" + encodeURIComponent(selectedQuality);
}

// Huibq API获取URL
async function huibqGetUrl(platform, songId, quality, songInfo) {
  const hashOrMid = songInfo?.hash ?? songInfo?.songmid;
  if (!hashOrMid) {
    throw new Error("Huibq缺少hash/songmid");
  }
  const selectedQuality = selectQuality(quality, ["320k", "128k"]);
  const url = HUIBQ_API + "/url/" + platform + "/" + encodeURIComponent(hashOrMid) + "/" + encodeURIComponent(selectedQuality);
  const res = await httpRequest(url, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      "User-Agent": getMobileUserAgent(),
      "X-Request-Key": HUIBQ_REQUEST_KEY
    }
  });
  const body = res.body;
  if (!body || typeof body !== "object" || Number.isNaN(Number(body.code))) {
    throw new Error("Huibq返回无效");
  }
  switch (Number(body.code)) {
    case 0:
      if (!body.url) {
        throw new Error("Huibq返回空URL");
      }
      return body.url;
    case 1:
      throw new Error("Huibq block ip");
    case 2:
      throw new Error("Huibq get music url failed");
    case 4:
      throw new Error("Huibq too many requests");
    case 5:
      throw new Error("Huibq param error");
    case 6:
      throw new Error("Huibq internal server error");
    default:
      throw new Error(body.message || "Huibq unknown error");
  }
}

// 聆川API获取URL
async function lingchuanGetUrl(platform, songId, quality, songInfo) {
  const hashOrMid = songInfo?.hash ?? songInfo?.songmid;
  if (!hashOrMid) {
    throw new Error("聆川缺少hash/songmid");
  }
  const selectedQuality = selectQuality(quality, ["320k", "128k"]);
  const url = LINGCHUAN_API + "/url?source=" + encodeURIComponent(platform) + "&songId=" + encodeURIComponent(hashOrMid) + "&quality=" + encodeURIComponent(selectedQuality);
  const res = await httpRequest(url, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      "User-Agent": getMobileUserAgent()
    },
    follow_max: 5
  });
  const body = res.body;
  if (!body || typeof body !== "object" || Number.isNaN(Number(body.code))) {
    throw new Error("聆川返回无效");
  }
  switch (Number(body.code)) {
    case 200:
      if (!body.url) {
        throw new Error("聆川返回空URL");
      }
      return body.url;
    case 403:
      throw new Error("聆川403 forbidden");
    case 429:
      throw new Error("聆川429 rate limit");
    case 500:
      throw new Error("聆川500 " + (body.message || "server error"));
    default:
      throw new Error(body.message || "聆川未知错误");
  }
}

// 从溯音QQ响应中提取音频URL
function extractQQUrl(responseData) {
  if (responseData?.music) {
    return responseData.music;
  }
  if (responseData?.url) {
    return responseData.url;
  }
  if (responseData?.message) {
    const match = String(responseData.message).match(/音频链接[：:](.+?)(?:\n|$)/);
    if (match && match[1]) {
      return match[1].trim();
    }
  }
  throw new Error("溯音QQ未找到音频链接");
}

// 将音质转换为溯音QQ码率参数
function qualityToSuyinQQ(quality) {
  const q = String(quality || "128k").toLowerCase();
  if (q === "flac24bit") {
    return "hires";
  }
  if (q === "192k") {
    return "320k";
  }
  if (QUALITY_TO_SUYIN_QQ_BR[q]) {
    return q;
  }
  return "128k";
}

// 溯音QQ获取URL（遍历多个码率尝试）
async function suyinQQGetUrl(songInfo, quality) {
  const qqId = getQQSongId(songInfo);
  if (!qqId) {
    throw new Error("溯音QQ缺少songmid/id");
  }
  const normalizedQuality = qualityToSuyinQQ(quality);
  const startBr = QUALITY_TO_SUYIN_QQ_BR[normalizedQuality] || QUALITY_TO_SUYIN_QQ_BR["128k"];
  const brList = [startBr, 4, 5, 7]
    .filter((val, idx, arr) => arr.indexOf(val) === idx && val >= startBr)
    .sort((a, b) => a - b);
  let lastError = null;
  for (const br of brList) {
    try {
      const reqParams = {
        key: SUYIN_QQ_KEY,
        type: "json",
        br: br,
        n: 1
      };
      if (qqId.type === "mid") {
        reqParams.mid = qqId.value;
      } else {
        reqParams.songid = qqId.value;
      }
      const res = await httpGet(SUYIN_QQ_API, reqParams);
      return extractQQUrl(res);
    } catch (e4) {
      lastError = e4;
    }
  }
  throw new Error("溯音QQ全部音质尝试失败: " + (lastError?.message || "unknown"));
}

// 溯音163获取URL
async function suyin163GetUrl(songInfo) {
  const id = songInfo?.songmid || songInfo?.id;
  if (!id) {
    throw new Error("溯音163缺少songmid/id");
  }
  const res = await httpGet(SUYIN_163_API, { id: id });
  if (res?.code === 0 && res?.data) {
    const item = Array.isArray(res.data) ? res.data[0] : res.data;
    if (item?.url) {
      return item.url;
    }
  }
  throw new Error("溯音163获取失败");
}

// 溯音酷我搜索并获取URL（通过关键词搜索）
async function suyinKuwoSearch(keyword, br, songInfo = null) {
  const res = await httpGet(SUYIN_KUWO_API, {
    msg: keyword,
    n: 1,
    br: br
  });
  if (res?.data?.url) {
    if (songInfo && !songInfoMatch(res, songInfo)) {
      throw new Error("溯音酷我歌曲信息不匹配");
    }
    return res.data.url;
  }
  if (res?.message) {
    const match = String(res.message).match(/音乐链接[：:](\S+)/);
    if (match && match[1]) {
      if (songInfo) {
        const parsed = parseMessageSongInfo(res.message);
        if (parsed && !songInfoMatch(parsed, songInfo)) {
          throw new Error("溯音酷我歌曲信息不匹配");
        }
      }
      return match[1];
    }
  }
  throw new Error("溯音酷我未找到链接");
}

// 溯音酷我获取URL（带缓存，遍历关键词）
async function suyinKuwoGetUrl(songInfo, quality) {
  if (!songInfo?.name) {
    throw new Error("溯音酷我需要歌曲名");
  }
  const cacheKey = buildCacheKey("kw", songInfo, quality);
  const cached = getCachedUrl(cacheKey);
  if (cached) {
    return cached;
  }
  const selectedQuality = selectQuality(quality, ["flac", "320k", "128k"]);
  const br = QUALITY_TO_KUWO_BR[selectedQuality] || 1;
  const keywords = buildSearchKeywords(songInfo);
  let lastError = null;
  for (const item of keywords) {
    try {
      const url = await suyinKuwoSearch(item.keyword, br, item.strict ? songInfo : null);
      if (url) {
        setCachedUrl(cacheKey, url);
        return url;
      }
    } catch (e5) {
      lastError = e5;
    }
  }
  throw new Error("溯音酷我失败: " + (lastError?.message || "unknown"));
}

// 溯音咪咕获取URL（带缓存，遍历关键词）
async function suyinMiguGetUrl(songInfo) {
  if (!songInfo?.name) {
    throw new Error("溯音咪咕需要歌曲名");
  }
  const cacheKey = buildCacheKey("mg", songInfo);
  const cached = getCachedUrl(cacheKey);
  if (cached) {
    return cached;
  }
  const keywords = buildSearchKeywords(songInfo);
  let lastError = null;
  for (const item of keywords) {
    try {
      const res = await httpGet(SUYIN_MIGU_API, {
        gm: item.keyword,
        n: 1,
        num: 1,
        type: "json"
      });
      if (res?.code === 200 && res?.musicInfo) {
        if (item.strict && !songTitleMatch(res, songInfo)) {
          throw new Error("溯音咪咕歌曲信息不匹配");
        }
        setCachedUrl(cacheKey, res.musicInfo);
        return res.musicInfo;
      }
    } catch (e6) {
      lastError = e6;
    }
  }
  throw new Error("溯音咪咕失败: " + (lastError?.message || "unknown"));
}

// 溯音统一获取URL（按平台分发）
async function suyinGetUrl(platform, songId, quality, songInfo) {
  switch (platform) {
    case "tx":
      return suyinQQGetUrl(songInfo, quality);
    case "wy":
      return suyin163GetUrl(songInfo);
    case "kw":
      return suyinKuwoGetUrl(songInfo, quality);
    case "mg":
      return suyinMiguGetUrl(songInfo);
    default:
      throw new Error("溯音不支持该平台");
  }
}

// 长青SVIP获取URL
async function changqingGetUrl(platform, songId, quality, songInfo) {
  return buildTemplateUrl(platform, quality, songInfo, CHANGQING_URL_TEMPLATES, "长青SVIP");
}

// 念心SVIP获取URL
async function nianxinGetUrl(platform, songId, quality, songInfo) {
  return buildTemplateUrl(platform, quality, songInfo, NIANXIN_URL_TEMPLATES, "念心SVIP");
}

// 音源处理器注册表
const SOURCE_HANDLERS = {
  xinghai: {
    name: "星海主",
    fn: xinghaiMainGetUrl
  },
  xinghaiBackup: {
    name: "星海备",
    fn: xinghaiBackupGetUrl
  },
  huibq: {
    name: "Huibq",
    fn: huibqGetUrl
  },
  lingchuan: {
    name: "聆川",
    fn: lingchuanGetUrl
  },
  suyinQQ: {
    name: "溯音QQ",
    fn: (platform, songId, quality, songInfo) => suyinGetUrl("tx", songId, quality, songInfo)
  },
  suyin163: {
    name: "溯音163",
    fn: (platform, songId, quality, songInfo) => suyinGetUrl("wy", songId, quality, songInfo)
  },
  suyinSearch: {
    name: "溯音搜索",
    fn: (platform, songId, quality, songInfo) => suyinGetUrl("kw", songId, quality, songInfo)
  },
  suyinMigu: {
    name: "溯音咪咕",
    fn: (platform, songId, quality, songInfo) => suyinGetUrl("mg", songId, quality, songInfo)
  },
  changqingVip: {
    name: "长青SVIP",
    fn: changqingGetUrl
  },
  nianxinVip: {
    name: "念心SVIP",
    fn: nianxinGetUrl
  }
};

// 构建音源链（按平台和是否高品质排序）
function buildSourceChain(platform, isHires, quality) {
  const chain = [];
  if (SOURCE_HANDLERS.xinghai) {
    chain.push(SOURCE_HANDLERS.xinghai);
  }
  if (SOURCE_HANDLERS.huibq) {
    chain.push(SOURCE_HANDLERS.huibq);
  }
  if (platform === "wy" && SOURCE_HANDLERS.suyin163) {
    chain.push(SOURCE_HANDLERS.suyin163);
  }
  if (platform === "tx" && SOURCE_HANDLERS.suyinQQ) {
    chain.push(SOURCE_HANDLERS.suyinQQ);
  }
  if (platform === "kw" && SOURCE_HANDLERS.suyinSearch) {
    chain.push(SOURCE_HANDLERS.suyinSearch);
  }
  if (platform === "mg" && SOURCE_HANDLERS.suyinMigu) {
    chain.push(SOURCE_HANDLERS.suyinMigu);
  }
  if (SOURCE_HANDLERS.lingchuan) {
    chain.push(SOURCE_HANDLERS.lingchuan);
  }
  if (SOURCE_HANDLERS.changqingVip) {
    chain.push(SOURCE_HANDLERS.changqingVip);
  }
  if (SOURCE_HANDLERS.nianxinVip) {
    chain.push(SOURCE_HANDLERS.nianxinVip);
  }
  return chain;
}

// 带fallback获取URL（并发尝试前3个源，失败后顺序尝试剩余源）
async function getUrlWithFallback(platform, songInfo, quality) {
  if (!platform || typeof platform !== "string" || !PLATFORM_QUALITIES[platform]) {
    throw new Error("无效的平台参数");
  }
  if (!songInfo || typeof songInfo !== "object") {
    throw new Error("无效的歌曲信息");
  }
  const resolvedQuality = quality || "128k";
  const selectedQuality = selectQuality(resolvedQuality, PLATFORM_QUALITIES[platform]);
  const songId = getHashOrMid(songInfo);
  const isHires = HIRES_QUALITY_SET.has(resolvedQuality.toLowerCase());
  const chain = buildSourceChain(platform, isHires, selectedQuality);
  if (!chain.length) {
    throw new Error("未找到可用fallback链");
  }
  const errors = [];
  try {
    const url = await Promise.any(chain.slice(0, 3).map(async handler => {
      const result = await handler.fn(platform, songId, selectedQuality, songInfo);
      return validateUrl(result, handler.name);
    }));
    if (url) {
      return url;
    }
  } catch (e7) {
    if (e7.errors) {
      e7.errors.forEach(err => errors.push(err.message));
    }
  }
  for (const handler of chain.slice(3)) {
    try {
      const result = await handler.fn(platform, songId, selectedQuality, songInfo);
      return validateUrl(result, handler.name);
    } catch (e8) {
      errors.push(handler.name + ": " + e8.message);
      continue;
    }
  }
  throw new Error("所有源均失败: " + errors.join("; "));
}

// --- 音源配置与注册 ---
const sourceConfig = {};

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

Object.keys(PLATFORM_QUALITIES).forEach(platform => {
  sourceConfig[platform] = {
    name: PLATFORM_NAMES[platform],
    type: "music",
    actions: ["musicUrl"],
    qualitys: PLATFORM_QUALITIES[platform]
  };
});

sourceConfig[QISHUI_SOURCE_ID] = {
  name: QISHUI_SOURCE_NAME,
  type: "music",
  actions: ["musicSearch", "musicUrl", "lyric"],
  qualitys: ["128k", "320k", "flac", "flac24bit"]
};

// --- 事件监听 ---
on(EVENT_NAMES.request, ({ action, source, info }) => {
  if (source === QISHUI_SOURCE_ID) {
    return qishuiHandler(action, info);
  }
  if (action !== "musicUrl") {
    return Promise.reject(new Error("action not support"));
  }
  if (!info?.musicInfo) {
    return Promise.reject(new Error("请求参数不完整"));
  }
  return getUrlWithFallback(source, info.musicInfo, info.type || "128k")
    .then(url => Promise.resolve(url))
    .catch(err => Promise.reject(err));
});

send(EVENT_NAMES.inited, {
  openDevTools: false,
  sources: sourceConfig
});

noop("初始化完成，聚合音源已就绪");
