QQMusicApi icon indicating copy to clipboard operation
QQMusicApi copied to clipboard

搜索接口失效问题解决方案

Open onceisy opened this issue 2 years ago • 17 comments

onceisy avatar Nov 04 '22 10:11 onceisy

搜索接口失效问题解决方案

搜索类型:默认为 0 // 0:单曲,1:歌手,2:专辑,3:歌单,7:歌词
代码:直接将以下代码覆盖原来的search.js即可,兼容以前的数据。

module.exports = {
  '/': async ({req, res, request, globalCookie, cache}) => {
    const obj = {...req.query, ...req.body};
    let { uin, qqmusic_key } = globalCookie.userCookie();
    if (Number(obj.ownCookie)) {
      uin = req.cookies.uin || uin;
    }

    const {
      pageNo = 1,
      pageSize = 20,
      key,
      t = 0, // 0:单曲,2:歌单,7:歌词,8:专辑,9:歌手,12:mv
      raw
    } = req.query;
    let total = 0;

    if (!key) {
      return res.send({
        result: 500,
        errMsg: '关键词不能为空',
      });
    }

    // 缓存
    const cacheKey = `search_${key}_${pageNo}_${pageSize}_${t}`;
    const cacheData = cache.get(cacheKey);
    if (cacheData) {
      res && res.send(cacheData);
      return cacheData;
    }

    const url = 'https://u.y.qq.com/cgi-bin/musicu.fcg'

    const typeMap = {
      0: 'song',
      2: 'album',
      1: 'singer',
      3: 'songlist',
      7: 'lyric',
      12: 'mv',
    };
    if (!typeMap[t]) {
      return res.send({
        result: 500,
        errMsg: '搜索类型错误,检查一下参数 t',
      });
    }

    const params = {
      req_1: {
        method: "DoSearchForQQMusicDesktop",
        module: "music.search.SearchCgiService",
        param: {
          num_per_page: Number(pageSize),
          page_num: Number(pageNo),
          query: key,
          search_type: Number(t)
        }
      }
    }
    let result = {}

    try {     
      result = await request({
        url,
        method: 'POST',
        data: params,
        headers: {
          Referer: 'https://y.qq.com'
        },
      });
    } catch (error) {
      return res.send({
        result: 400,
        error
      })
    }

    // 直接返回原生数据
    if (Number(raw)) {
      return res.send(result);
    }
    const response = {
      result: 100,
      data: {
        list: Number(t) === 0 ? formatSongList(result.req_1.data.body[typeMap[t]].list) : result.req_1.data.body[typeMap[t]].list,
        pageNo,
        pageSize,
        total: result.req_1.data.meta.sum,
        key: result.req_1.data.meta.query || key,
        t,
        type: typeMap[t],
      },
    }
    res.send(response);
  },

  // 热搜词
  '/hot': async ({req, res, request}) => {
    const {raw} = req.query;
    const result = await request({
      url: 'https://c.y.qq.com/splcloud/fcgi-bin/gethotkey.fcg',
    });
    if (Number(raw)) {
      return res.send(result);
    }
    res.send({
      result: 100,
      data: result.data.hotkey,
    });
  },

  // 快速搜索
  '/quick': async ({req, res, request}) => {
    const {raw, key} = req.query;
    if (!key) {
      return res.send({
        result: 500,
        errMsg: 'key ?',
      });
    }
    const result = await request(
      `https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?key=${key}&g_tk=5381`,
    );
    if (Number(raw)) {
      return res.send(result);
    }
    return res.send({
      result: 100,
      data: result.data,
    });
  },
}

function formatSongList(list) {
  if (!Array.isArray(list)) {
    return []
  }
  return list.map((item) => {
    // 美化歌曲数据
    return {
      singer: item.singer, // 、
      name: item.title,
      songid: item.id,
      songmid: item.mid,
      songname: item.title,

      albumid: item.album.id,
      albummid: item.album.mid,
      albumname: item.album.name,
      interval: item.interval,

      strMediaMid: item.file.media_mid,
      size128: item.file.size_128mp3,
      size320: item.file.size_320mp3,
      sizeape: item.file.size_ape,
      sizeflac: item.file.size_flac,
      pay: item.pay || {}
    }
  })
}

onceisy avatar Nov 04 '22 10:11 onceisy

报404阿

643063150 avatar Mar 09 '23 03:03 643063150

报404阿

onceisy avatar Mar 09 '23 08:03 onceisy

报404阿 检查一下路由写对没

onceisy avatar Mar 09 '23 08:03 onceisy

报404阿 检查一下路由写对没

额 不是覆盖代码就行了吗,不是搞nodejs的不知道咋判断....

643063150 avatar Mar 09 '23 09:03 643063150

报404阿 检查一下路由写对没

额 不是覆盖代码就行了吗,不是搞nodejs的不知道咋判断....

就是直接覆盖就行了啊

onceisy avatar Mar 10 '23 02:03 onceisy

报404阿 检查一下路由写对没

额 不是覆盖代码就行了吗,不是搞nodejs的不知道咋判断....

就是直接覆盖就行了啊

那就奇怪了.我直接把\routes文件夹下的search.js里面的代码直接覆盖成了上面发的,就一直报404错误了

643063150 avatar Mar 10 '23 02:03 643063150

报404阿 检查一下路由写对没

额 不是覆盖代码就行了吗,不是搞nodejs的不知道咋判断....

就是直接覆盖就行了啊

那就奇怪了.我直接把\routes文件夹下的search.js里面的代码直接覆盖成了上面发的,就一直报404错误了

其他的接口能调用?检查一下代码复制完整没有,改完了重启服务。

onceisy avatar Mar 10 '23 02:03 onceisy

其他接口是正常的 TYTU Q 6B{}E6CQ6H$T79MV 这是文件里的代码,我对比了下 应该是一模一样的

module.exports = {
  '/': async ({req, res, request, globalCookie, cache}) => {
    const obj = {...req.query, ...req.body};
    let { uin, qqmusic_key } = globalCookie.userCookie();
    if (Number(obj.ownCookie)) {
      uin = req.cookies.uin || uin;
    }

    const {
      pageNo = 1,
      pageSize = 20,
      key,
      t = 0, // 0:单曲,2:歌单,7:歌词,8:专辑,9:歌手,12:mv
      raw
    } = req.query;
    let total = 0;

    if (!key) {
      return res.send({
        result: 500,
        errMsg: '关键词不能为空',
      });
    }

    // 缓存
    const cacheKey = `search_${key}_${pageNo}_${pageSize}_${t}`;
    const cacheData = cache.get(cacheKey);
    if (cacheData) {
      res && res.send(cacheData);
      return cacheData;
    }

    const url = 'https://u.y.qq.com/cgi-bin/musicu.fcg'

    const typeMap = {
      0: 'song',
      2: 'album',
      1: 'singer',
      3: 'songlist',
      7: 'lyric',
      12: 'mv',
    };
    if (!typeMap[t]) {
      return res.send({
        result: 500,
        errMsg: '搜索类型错误,检查一下参数 t',
      });
    }

    const params = {
      req_1: {
        method: "DoSearchForQQMusicDesktop",
        module: "music.search.SearchCgiService",
        param: {
          num_per_page: Number(pageSize),
          page_num: Number(pageNo),
          query: key,
          search_type: Number(t)
        }
      }
    }
    let result = {}

    try {     
      result = await request({
        url,
        method: 'POST',
        data: params,
        headers: {
          Referer: 'https://y.qq.com'
        },
      });
    } catch (error) {
      return res.send({
        result: 400,
        error
      })
    }

    // 直接返回原生数据
    if (Number(raw)) {
      return res.send(result);
    }
    const response = {
      result: 100,
      data: {
        list: Number(t) === 0 ? formatSongList(result.req_1.data.body[typeMap[t]].list) : result.req_1.data.body[typeMap[t]].list,
        pageNo,
        pageSize,
        total: result.req_1.data.meta.sum,
        key: result.req_1.data.meta.query || key,
        t,
        type: typeMap[t],
      },
    }
    res.send(response);
  },

  // 热搜词
  '/hot': async ({req, res, request}) => {
    const {raw} = req.query;
    const result = await request({
      url: 'https://c.y.qq.com/splcloud/fcgi-bin/gethotkey.fcg',
    });
    if (Number(raw)) {
      return res.send(result);
    }
    res.send({
      result: 100,
      data: result.data.hotkey,
    });
  },

  // 快速搜索
  '/quick': async ({req, res, request}) => {
    const {raw, key} = req.query;
    if (!key) {
      return res.send({
        result: 500,
        errMsg: 'key ?',
      });
    }
    const result = await request(
      `https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?key=${key}&g_tk=5381`,
    );
    if (Number(raw)) {
      return res.send(result);
    }
    return res.send({
      result: 100,
      data: result.data,
    });
  },
}

function formatSongList(list) {
  if (!Array.isArray(list)) {
    return []
  }
  return list.map((item) => {
    // 美化歌曲数据
    return {
      singer: item.singer, // 、
      name: item.title,
      songid: item.id,
      songmid: item.mid,
      songname: item.title,

      albumid: item.album.id,
      albummid: item.album.mid,
      albumname: item.album.name,
      interval: item.interval,

      strMediaMid: item.file.media_mid,
      size128: item.file.size_128mp3,
      size320: item.file.size_320mp3,
      sizeape: item.file.size_ape,
      sizeflac: item.file.size_flac,
      pay: item.pay || {}
    }
  })
}

643063150 avatar Mar 10 '23 02:03 643063150

报404阿 检查一下路由写对没

额 不是覆盖代码就行了吗,不是搞nodejs的不知道咋判断....

就是直接覆盖就行了啊

那就奇怪了.我直接把\routes文件夹下的search.js里面的代码直接覆盖成了上面发的,就一直报404错误了

其他的接口能调用?检查一下代码复制完整没有,改完了重启服务。

我把服务器重启了下 好了,难道是缓存? 昨天项目重启了好几次都不行 真尴尬

643063150 avatar Mar 10 '23 02:03 643063150

你好,替换后,搜索类型为7,对应歌词,会直接崩溃;搜索类型12,对应MV,搜出来的数据为空,应该如何解决呢

sSimonz avatar Oct 26 '23 08:10 sSimonz

有用

14Kay avatar Nov 10 '23 05:11 14Kay

你好,替换后,搜索类型为7,对应歌词,会直接崩溃;搜索类型12,对应MV,搜出来的数据为空,应该如何解决呢

没有用过歌词和mv搜索,可以抓包看看对应类型的传参是否有变化

onceisy avatar Nov 13 '23 03:11 onceisy

你好,替换后,搜索类型为7,对应歌词,会直接崩溃;搜索类型12,对应MV,搜出来的数据为空,应该如何解决呢

刚刚在其他issue里看到搜索歌词崩溃的原因如下,加上结构检查就行了:

image

onceisy avatar Nov 13 '23 03:11 onceisy

你好,替换后,搜索类型为7,对应歌词,会直接崩溃;搜索类型12,对应MV,搜出来的数据为空,应该如何解决呢

刚刚在其他issue里看到搜索歌词崩溃的原因如下,加上结构检查就行了:

image

我指的是搜索接口(search.js)对应的搜索类型为歌词(t=7)时会发生崩溃,不是获取歌词的接口(lyric.js)

sSimonz avatar Nov 23 '23 01:11 sSimonz

问题已解决,抓包看了下,当搜索类型为歌词时,返回的数据没有lyric字段,实际存放的字段为song; 当搜索类型为mv时,对应的serach_type=4,而不是12。search.js的修改如下: image image

sSimonz avatar Nov 23 '23 03:11 sSimonz

谢谢你,人间尤物🌹

zhemozhiwangddd avatar Feb 20 '24 08:02 zhemozhiwangddd