喜马拉雅解析vip音频链接方法(javascript版本)

喜马拉雅有声书下载后拷贝到车机上无法播放?网页上无法下载?看这里

油猴脚本链接

喜马拉雅音频地址提取工具

核心代码直接拿走

// @require             https://cdn.jsdelivr.net/npm/blueimp-md5@2.19.0/js/md5.min.js
// @require             https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.min.js

'use strict';

/*************** 基础 *******************/
const SECRET_KEY = 'himalaya-'; // 证书生成秘钥

/**
 * 获取接口签名,header 中的 xm-sign
 * @returns
 */
function getSign() {
  var secretKey = SECRET_KEY;
  var serverTime = window.XM_SERVER_CLOCK || 0; //看 getServerTime 方法了解详情
  var clientTime = Date.now();
  var random = (t) => ~~(Math.random() * t);
  return `${md5(`${secretKey}${serverTime}`)}(${random(100)})${serverTime}(${random(100)})${clientTime}`;
}

/**
 * 获取服务器时间(无需xm-sign)
 * 备用方法,如果获取不到 window.XM_SERVER_CLOCK, serverTime = await getServerTime()
 * @returns 一个时间字符串
 */
async function getServerTime() {
  return await fetch("https://www.ximalaya.com/revision/time")
    .then(res => res.text());
}

/**
 * 获取专辑播放列表
 * 注意:请在专辑界面调用
 * @param {*} albumId 专辑id
 * @param {*} pageNum 分页
 * @returns
 */
async function getAlbumTrackList(albumId, pageNum) {
  const response = await fetch(`https://www.ximalaya.com/revision/album/v1/getTracksList?albumId=${albumId}&pageNum=${pageNum}&pageSize=100&sort=0`, {
    "credentials": "include",
    "headers": {
      "xm-sign": getSign(),
    },
    "method": "GET",
    "mode": "cors"
  });
  return response.json();
}

/**
 * 获取播放url列表(需要cookie,无需xm-sign)
 * 在任何界面均可调用
 * https://www.ximalaya.com/sound/${trackId}
 * @param {*} trackId 音轨id
 * @returns
 */
async function getTrackList(trackId) {
  const response = await fetch(`https://mobile.ximalaya.com/mobile-playpage/track/v3/baseInfo/${Date.now()}?device=web&trackId=${trackId}&trackQualityLevel=1`, {
    "credentials": "include",
    "method": "GET",
    "mode": "cors"
  });
  return response.json();
}

/**
 * 获取播放url列表中的第一个直链
 * @param {*} playList
 * @returns
 */
function getDownloadURL(playUrlList) {
  if (playUrlList && playUrlList.length) {
    const url = playUrlList[0].url;
    return decrypt(url);
  }
  return false;

  function decrypt(t) {
    return CryptoJS.AES.decrypt({
      ciphertext: CryptoJS.enc.Base64url.parse(t)
    }, CryptoJS.enc.Hex.parse('aaad3e4fd540b0f79dca95606e72bf93'), {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7
    })
      .toString(CryptoJS.enc.Utf8);
  }
}