【VUE音乐播放器】获取QQ音乐播放源地址

前言:在学习慕课网课程制作企业级音乐app中,发现之前的qq音乐播放地址均不可用了。于是折腾了一下,重新抓包获取地址。

 1、获取分类歌单里面的歌曲列表

在之前的代码里,如下红色圆中的歌单-歌曲列表显示不出来,因为之前qq音乐改变了源地址,现在只能通过node来做接入层转发一下。

原来获取歌单列表的代码:

发现不能获取了,如果发现报错Uncaught ReferenceError: jp1 is not defined之类的东西,这是jsonp的问题,去config.js添加prefix:‘playlistinfoCallback’能解决,但是还是不能获得数据

去打开qq音乐pc版,找到https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&disstid=6543771358&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0 的链接,如果没有多刷新几次 

双击链接,返回msg invalid referer,这个链接不能直接获取了,需要node转发

 所以现在结构明确了

新代码如下:

在dev-server.js中添加

可能会注意到 我这里多了一部分内容

const url = '' + prefixHost.prefixHost + '/api/getplaysongvkey'

这是我用来判断是否是dev环境启动,还是直接打开打包好的build/index.html,这样做我可以在连接局域网的情况下直接用手机访问这个页面,如果要用手机访问,记得开启一个新的node服务器,比如node prod.server.js用来做转发。然后手机输入电脑ip和node服务器开启的端口即可。

这部分代码在config中添加host.js,

module.exports = {
 prefixHost: process.env.NODE_ENV === 'development' ? '' :'http://192.168.1.104:9000'
}

然后在recommend.js中引入的,来做判断的

var prefixHost = require('../../config/host')

经过这样就可以顺利获取榜单中的歌曲列表。

2、获取音乐播放源地址

随便找到榜单列表的一首歌,比如《知否知否》,点击进入下面这个音乐播放页面(目前是这个页面才能抓到需要的包,不知以后是否会变)

先清空或刷新下,在点击播放,可以看到这个地址,双击能拿到真正的播放地址

拿到这个地址http://dl.stream.qqmusic.qq.com/C400002krvKI4Jgvq9.m4a?guid=7347620869&vkey=0FA4AD518A295E845C2E2F375494A197473C3B7266A7DBB5D81C9D70204380FD5044DD1CA8209DF0C49C0FC182647AD8AEF441D49396FA16&uin=0&fromtag=66 

仔细分析一下,再去之前榜单列表中,抓到的包中展开看看点击的这首歌《知否知否》的情况,

不难发现真正的地址是由

http://dl.stream.qqmusic.qq.com/C400${songmid}.m4a?guid=7347620869&vkey=${vkey}&uin=0&fromtag=66

 构成,多次抓取不同歌曲后发现只要能获取vkey就行,然后就可以拼接成播放源地址。

下面找看那个url里面返回了vkey,主要还是在当前播放页面瞎找或上一个页面找找,找不到刷新刷新看看

突然,找到了这个请求,这不就是需要的vkey吗,而且看到purl正是拼接后的请求链接

看看Headers,发现这是需要设置请求源地址的,那么就要node转发了

origin:https://y.qq.com  

referer:https://y.qq.com/portal/player.html

在看看Query parmeters这些参数我们都可以伪造的,里面data需要一个songmid也是可以拿到的

 所以现在思路清晰了

代码如下先获取vkey

export function getplaysongvkey(songmid) {
  const url = '' + prefixHost.prefixHost + '/api/getplaysongvkey'
  const data = Object.assign({}, commonParams, {
    // -: 'getplaysongvkey7257571376863041',
    g_tk: 5381,
    loginUin: 0,
    hostUin: 0,
    format: 'json',
    inCharset: 'utf8',
    outCharset: 'utf-8',
    notice: 0,
    platform: 'yqq.json',
    needNewCode: 0,
    data: `{"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"7347620869","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"7347620869","songmid":["${songmid}"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":24,"cv":0}}`
  })
 return axios.get(url, {
    params: data
  }).then((res) => {
   return Promise.resolve(res.data.req_0.data.midurlinfo[0].purl)
  })
}
apiRoutes.get('/getplaysongvkey', function (req, res) {
  var url = 'https://u.y.qq.com/cgi-bin/musicu.fcg'
  axios.get(url, {
    headers: {
      origin: 'https://y.qq.com',
      referer: 'https://y.qq.com/portal/player.html'
    },
    params: req.query
  }).then((response) => {
    res.json(response.data)
  }).catch((e)=>{
    console.log(e)
  })
})

由于在之前的代码recommend.vue点击一个热门榜单,就会进入disc.vue中传入榜单id,就会获得榜单歌曲列表,构建一个songs类,包含该榜单中的所有歌曲信息

正是因为之前songs类中的url拼接不对(被qq音乐屏蔽掉了),所以先去掉,变成没有url的songs集合,显示如下

 考虑到歌曲的源地址需要一个个去请求才能拿到,所以为了优化性能,在点击播放一首歌时,才通过这首歌的songmid获取其vkey,再更改songs类中的url形成这首歌的播放源地址

比如我点击了《知否知否》这首歌,就会去做如下改变,只更改获取该歌曲的url播放源地址,其他歌曲的url还是为空

因为是在点击时才请求vkey,所以修改music-list.vue中点击部分代码,还有songs是保存在vuex中,this.setlectPlay({list:this.songs,index}),所以要修改songs中的url,必须通过mapMutations,

在musci-list.vue中更改如下:

selectItem(item, index) {
        getplaysongvkey(item.mid).then((vkey) => {
          let url = `http://dl.stream.qqmusic.qq.com/${vkey}`
          this.setPlaylistUrl({
            index,
            url,
          })
        })

        this.selectPlay({
          list: this.songs,
          index
        })
      },
...mapMutations({
        setPlaylistUrl: 'SET_PLAYLIST_URL'
      })

在mutations.js中添加 

[types.SET_PLAYLIST_URL](state, keyUrl) {
    let index = keyUrl.index
    let url = keyUrl.url
    state.playlist[index].url = url
  }

全部完成,经测试迄今为止这是有效方式~~~