1

播放器歌词数据需要从qq官网上抓取,打开qq音乐任意一首歌曲的播放页面,在chrome的Network中搜索lyric,即获取歌词的接口
歌词获取接口

1. 配置接口

qq对接口进行了安全控制,在devserver中模拟请求头等从而避开
在config文件夹中index.js文件中,配置proxyTable

proxyTable: {
      //target:真实请求的值
      //bypass:对应的函数是请求之前可以进行的操作
      //req这个参数是请求的信息,可以在这里设置请求头信息
      '/api/lyric':{
        target: 'https://szc.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg',
        bypass: function (req, res, proxyOptions) {
          req.headers.referer = 'https://c.y.qq.com';
          req.headers.host = 'c.y.qq.com';
        },
        pathRewrite: {
          '^/api/lyric': ''
        }
      }
    }

2. 调取接口的API

在api文件夹下创建song.js

export function getLyric(mid) {
  const url = '/api/lyric'
  const data = Object.assign({}, commonParams, {
    songmid: mid,
    platform: 'yqq',
    hostUin: 0,
    needNewCode: 0,
    pcachetime: +new Date(),
    format: 'json',
    g_tk: 67232076
  })

  return axios.get(url, {
    params: data
  }).then((res) => {
    if (typeof res.data === 'string') {
      //返回的jsonp格式,利用正则,提取我们需要的json字段
      const reg = /^\w+\(({[^()]+})\)$/
      var matches = res.data.match(reg)
      if (matches) {
        let val = JSON.parse(matches[1])
        //为什么用Promise:为了后边的方法调用的时候,进一步then,操作数据
        return Promise.resolve(val)
      }
    }
  })
}

3.在Song类中调用

为什么写在class Song{}中:因为这样可以它的实例直接调用自己的歌词

export default class Song {
  ....
  //当初没有搞懂为什么lyric不再constructor中定义:下面的if判断,防止重复请求歌词
  getLyric() {
    if (this.lyric) {
      return Promise.resolve(this.lyric)
    }
    //这里用Promsie返回,同样的道理:后面调用这个方法,方便进一步操作数据,同2中的promsie
    return new Promise((resolve, reject) => {
      getLyric(this.mid).then((res) => {
        if (res.code === ERR_OK) {
          //返回数据的是 base64 的字符串,需要解码,这里用到了第三方库: js-base64
          this.lyric = Base64.decode(res.lyric)
          resolve(this.lyric)
        } else {
          reject(new Error('no lyric'))
        }
      })
    })
  }
}

3.真正调取方法

在player.vue中methods,调取方法

getLyric() {
  //在2中,方法定义在class Song{}类中,这个时候this.currentSong是类的实例,可以直接调用定义的实例方法
  this.currentSong.getLyric().then((lyric) => {
    //利用第三方库: js-lyric ,解析我们的歌词,生成方便操作的对象
    //new Lyric生成的实例,还有一些api方便使用play、stop等等
    //this.handleLyric回调函数handleLyric(lineNum,txt):(当前播放的行数,当前播放的文字)
    this.currentLyric = new Lyric(lyric, this.handleLyric)
    if (this.playing) {
      this.currentLyric.play()
    }
  }).catch(() => {
    //如果歌词有问题,初始化
    this.currentLyric = null
    this.playingLyric = ''
    this.currentLineNum = 0
  })
},

4.在watch里的currentSong中调用this.getLyric()


云深不知处
431 声望10 粉丝