首页  编辑  

无限制洛雪高清音源

Tags: /计算机文档/软件应用技巧/   Date Created:
洛雪高清,无限制,免费,免注册音源,基于 无损音乐下载 开发。点击下载 %E6%97%A0%E6%8D%9F%E9%9F%B3%E6%BA%902.js
/*!
 * @name 高品质无损音乐音源
 * @description 基于flac.music.hi.cn API的音源服务
 * @version 1.0
 * @author Kingron
 * @homepage https://flac.music.hi.cn/
*/

const API_BASE_URL = "https://flac.music.hi.cn"
const { EVENT_NAMES, request, on, send } = globalThis.lx

// 全局cookie存储
let globalCookie = 'sl-session=cfvqX25YrmjOIuvFqDrbpQ==; sl-challenge-server=cloud; sl_jwt_session=cpF4eqtnrWghBeqsta5jqA==; sl_jwt_sign='
let cookieUpdateTimer = null

// 提取的f函数
function calculateArray(input) {
  let t = 1;
  const sum = input.reduce((acc, val) => acc + val, 0);
  let cycles = (6 + input.length + sum) % 6 + 6;
  
  while (cycles--) t *= 6;
  
  if (t < 6666) t *= input.length;
  if (t > 0x3f940aa) t = Math.floor(t / input.length);
  
  for (let i = 0; i < input.length; i++) {
    t += Math.pow(input[i], 3);
    t ^= i;
    t ^= input[i] + i;
  }
  
  const result = [];
  while (t > 0) {
    result.unshift(t & 63);
    t >>= 6;
  }
  
  return result;
}

// 自定义request函数,允许468状态码
function customRequest(url, options) {
  return new Promise((resolve, reject) => {
    request(url, options, (err, resp) => {
      if (err) return reject(err);
      // 允许200-299和468状态码
      if ((resp.statusCode >= 200 && resp.statusCode < 300) || resp.statusCode === 468) {
        resolve(resp);
      } else {
        reject(new Error(`请求失败,状态码: ${resp.statusCode}`));
      }
    });
  });
}

// 生成cookie的函数
async function generateCookie() {
  try {
    console.log('开始生成cookie...');
    
    // 第一步:获取初始页面并提取sl-session和key
    console.log('第一步:获取初始页面...');
    const response1 = await customRequest('https://flac.music.hi.cn/', {
      method: 'GET',
      headers: {
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'accept-language': 'zh-CN,zh;q=0.9',
        'priority': 'u=0, i',
        'sec-ch-ua': '"Chromium";v="131", "Not_A Brand";v="24"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        'sec-fetch-dest': 'document',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-site': 'none',
        'sec-fetch-user': '?1',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
      }
    });
    console.log('第一步响应状态码:', response1.statusCode);
    
    // 提取sl-session
    const setCookieHeader = response1.headers['set-cookie'];
    let slSession = '';
    if (setCookieHeader) {
      for (const cookie of setCookieHeader) {
        if (cookie.includes('sl-session=')) {
          const match = cookie.match(/sl-session=([^;]+)/);
          if (match) {
            slSession = match[1];
            break;
          }
        }
      }
    }

    // 提取key
    let key = '';
    if (response1.body) {
      const keyMatch = response1.body.match(/SafeLineChallenge\("([^"]+)"/);
      if (keyMatch) {
        key = keyMatch[1];
      }
    }

    console.log('提取到的sl-session:', slSession);
    console.log('提取到的key:', key);

    if (!slSession || !key) {
      throw new Error('无法提取sl-session或key');
    }

    // 第二步:请求issue
    console.log('第二步:请求issue...');
    const response2 = await customRequest('https://challenge.rivers.chaitin.cn/challenge/v2/api/issue', {
      method: 'POST',
      headers: {
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Content-Type': 'application/json',
        'Origin': 'https://flac.music.hi.cn',
        'Referer': 'https://flac.music.hi.cn/',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'cross-site',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
        'sec-ch-ua': '"Chromium";v="131", "Not_A Brand";v="24"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"'
      },
      body: JSON.stringify({
        client_id: key,
        level: 1
      })
    });
    console.log('第二步响应状态码:', response2.statusCode);
    
    let issueData = response2.body.data;
    console.log('获取到的issue数据:', issueData);

    // 第三步:计算result
    console.log('第三步:计算result...');
    const result = calculateArray(issueData.data);
    console.log('计算结果:', result);

    // 第四步:验证result
    console.log('第四步:验证result...');
    const response3 = await customRequest('https://challenge.rivers.chaitin.cn/challenge/v2/api/verify', {
      method: 'POST',
      headers: {
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Content-Type': 'application/json',
        'Origin': 'https://flac.music.hi.cn',
        'Referer': 'https://flac.music.hi.cn/',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'cross-site',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
        'sec-ch-ua': '"Chromium";v="131", "Not_A Brand";v="24"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"'
      },
      body: JSON.stringify({
        issue_id: issueData.issue_id,
        result: result,
        serials: [],
        client: {
          userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
          platform: 'Win32',
          language: 'zh-CN',
          vendor: 'Google Inc.',
          screen: [1920, 1080],
          visitorId: '37e2d1aea4b49c1604dfb58aa19c260b',
          score: 0,
          target: []
        }
      })
    });
    console.log('第四步响应状态码:', response3.statusCode);
    
    let jwt = response3.body.data.jwt;
    console.log('获取到的JWT:', jwt);

    // 第五步:最终请求获取cookie
    console.log('第五步:获取最终cookie...');
    const response4 = await customRequest('https://flac.music.hi.cn/', {
      method: 'GET',
      headers: {
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'accept-language': 'zh-CN,zh;q=0.9',
        'cache-control': 'max-age=0',
        'cookie': `sl-session=${slSession}; sl-challenge-server=cloud; sl-challenge-jwt=${jwt}`,
        'priority': 'u=0, i',
        'referer': 'https://flac.music.hi.cn/',
        'sec-ch-ua': '"Chromium";v="131", "Not_A Brand";v="24"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        'sec-fetch-dest': 'document',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-site': 'same-origin',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
      }
    });

    console.log('第五步响应状态码:', response4.statusCode);

    // 提取最终的cookie
    const finalCookies = response4.headers['set-cookie'];
    let slJwtSession = '';
    let slJwtSign = '';
    let slChallengeJwt = '';

    if (finalCookies) {
      for (const cookie of finalCookies) {
        if (cookie.includes('sl_jwt_session=')) {
          const match = cookie.match(/sl_jwt_session=([^;]+)/);
          if (match) slJwtSession = match[1];
        } else if (cookie.includes('sl_jwt_sign=')) {
          const match = cookie.match(/sl_jwt_sign=([^;]+)/);
          if (match) slJwtSign = match[1];
        } else if (cookie.includes('sl-challenge-jwt=')) {
          const match = cookie.match(/sl-challenge-jwt=([^;]+)/);
          if (match) slChallengeJwt = match[1];
        }
      }
    }

    console.log('提取的sl_jwt_session:', slJwtSession);
    console.log('提取的sl_jwt_sign:', slJwtSign);
    console.log('提取的sl-challenge-jwt:', slChallengeJwt);

    // 生成最终cookie
    const finalCookie = `sl-session=${slSession};sl-challenge-server=cloud;sl_jwt_session=${slJwtSession};sl_jwt_sign=${slJwtSign};sl-challenge-jwt=${slChallengeJwt}`;
    
    console.log('生成的新cookie:', finalCookie);
    return finalCookie;
  } catch (error) {
    console.error('生成cookie过程中出错:', error.message);
    throw error;
  }
}

// 初始化cookie并设置定时更新
async function initCookie() {
  try {
    globalCookie = await generateCookie();
    console.log('Cookie初始化成功');
    
    // 设置每小时更新一次cookie
    if (cookieUpdateTimer) {
      clearInterval(cookieUpdateTimer);
    }
    cookieUpdateTimer = setInterval(async () => {
      try {
        globalCookie = await generateCookie();
        console.log('Cookie定时更新成功');
      } catch (error) {
        console.error('Cookie定时更新失败:', error.message);
      }
    }, 60 * 60 * 1000); // 1小时
    
  } catch (error) {
    console.error('Cookie初始化失败,使用默认cookie:', error.message);
  }
}

// 初始化cookie
initCookie();

const httpFetch = (url, body) => new Promise((resolve, reject) => {
  console.log("发送请求 " + url + ", 参数: " + body);
  request(
    url, 
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Origin': API_BASE_URL,
        'X-Requested-With': 'XMLHttpRequest',
        'Cookie': globalCookie, // 使用动态生成的cookie
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
      },
      body: body,
    },
    (err, resp) => {
      if (err) {
        console.log("请求错误: ", err);
        return reject(err)
      }
      console.log("服务器返回: ", resp);
	  if (resp.statusCode === 468) {
		initCookie();
		reject("Session过期, 重新获取");
	  }
      resolve(resp.body)
    }
  )
})

function getLink(list, info) {
  let filter = list.filter(item => item.id === info.musicInfo.songmid);
  if (filter.length > 0) return filter[0].link;

  filter = list.filter(item => 
    item.artist.toLowerCase() === info.musicInfo.singer.toLowerCase()
    && item.name.toLowerCase() === info.musicInfo.name.toLowerCase()
  );
  if (filter.length > 0) return filter[0].link;
    
  filter = list.filter(item => item.artist.toLowerCase() === info.musicInfo.singer.toLowerCase());
  if (filter.length > 0) return filter[0].link;

  filter = list.filter(item => item.name.toLowerCase() === info.musicInfo.name.toLowerCase());
  if (filter.length > 0) return filter[0].link;

  return list[0].link;
}

// 获取音乐URL
const musicUrl = async(source, info) => {
  console.log("运行 musicUrl: ", info);
  const key = encodeURIComponent(info.musicInfo.name + info.musicInfo.singer)
  const qual = info.type.replace("k", "");
  const url = `${API_BASE_URL}/ajax.php?act=search`
  const response = await httpFetch(url, `keyword=${key}&page=1&size=30`);
  if (response.code === 0) {
    const link = getLink(response.data.list, info);
    console.log("获取链接: " + link);
    const url = `${API_BASE_URL}/ajax.php?act=getUrl`
    const resp = await httpFetch(url, `songid=${response.data.list[0].id}&format=mp3&bitrate=${qual}`);
    if (resp.code === 0) {
      return Promise.resolve(resp.data.url);
    } else {
      return Promise.reject("获取歌曲地址失败");
    }
  } else {
    return Promise.reject("搜索失败");
  }
}

// 获取歌词
const lyricUrl = async(source, info) => {
  console.log("运行 lyricUrl", info);
  return Promise.resolve('')
}

// 获取专辑信息
const picUrl = async(source, info) => {
  console.log("运行 picUrl", info);  
  return Promise.resolve("")
}

on(EVENT_NAMES.request, ({ source, action, info }) => {
  switch (action) {
    case 'musicUrl':
      return musicUrl(source, info)
        .then(data => Promise.resolve(data))
        .catch(err => Promise.reject(err))
    case 'lyric':
      return lyricUrl(source, info)
        .then(data => Promise.resolve(data))
        .catch(err => Promise.reject(err))
    case 'pic':
      return picUrl(source, info)
        .then(data => Promise.resolve(data))
        .catch(err => Promise.reject(err))
    default:
      console.error(`action(${action}) not support`)
      return Promise.reject('action not support')
  }
})

send(EVENT_NAMES.inited, { 
  status: true, 
  openDevTools: true, 
  sources: {
    kw: {
      name: '酷我音乐',
      type: 'music',
      actions: ['musicUrl'],
      qualitys: ['128k', '320k', 'flac', 'flac24bit'],
    },
    kg: {
      name: '酷狗音乐',
      type: 'music',
      actions: ['musicUrl'],
      qualitys: ['128k', '320k', 'flac', 'flac24bit'],
    },
    tx: {
      name: 'QQ音乐',
      type: 'music',
      actions: ['musicUrl'],
      qualitys: ['128k', '320k', 'flac', 'flac24bit'],
    },
    wy: {
      name: '网易云音乐',
      type: 'music',
      actions: ['musicUrl'],
      qualitys: ['128k', '320k', 'flac', 'flac24bit'],
    },
    mg: {
      name: '咪咕音乐',
      type: 'music',
      actions: ['musicUrl'],
      qualitys: ['128k', '320k', 'flac', 'flac24bit'],
    },
    local: {
      name: '本地音乐',
      type: 'music',
      actions: ['musicUrl', 'lyric', 'pic'],
      qualitys: [],
    }
  }
})
无损音源2.js (11.8KB)