site logo

by Frank Lin in Front-end
2018-04-05 7 minutes to read 1 views 0 comments

Get lyric for music can be easily done by several 3rd-party services. Especially in Foobar, the ESLyric component makes it easy to auto-fetch .lrc by JavaScript. But sometimes it may fail to work for certain music or from a certain lyric provider. Recently, as I installed a newer version of foobox 6, I found the lyrics from QQ music is getting some problems with the build-in script. So I would like to know what happens and try to fix it.

old script

Following is a snippet from the build-in qqmusic 0.0.2.js come along with foobox 6 (the author is btx258 but I couldn’t find more information about the author):

var QM_CFG = {
    // DEBUG: true,
    E_SRV: "https://y.qq.com/portal/player.html",
    S_SRV: "https://c.y.qq.com/soso/fcgi-bin/client_search_cp",
    L_SRV: "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.fcg",
    G_PRM: "&format=json&inCharset=utf8&outCharset=utf-8",
    P_MAX: 3,
    P_NUM: 30,
    L_LOW: 5,
    L_MAX: 10,
    RETRY: 1,
};

We could see the lyric is fetched from the L_SRV. I found some Chinese posts about this API, some say it is no longer working1 2; while others report that it has some limits and only working with back end3. From the present QQ music webpage, we can find that they are using a newer URL: https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.new.fcg. Directly request data from this API address though Ajax will give you some null data, and need a back-end server for requesting. Alternatively, we can build some URLs like https://music.qq.com/miniportal/static/lyric/10/4900010.xml that give you lrc data.

newer script

Okay, in the following part of this post, I will explain more with examples that step through the process to get the lyrics.

query music information

Well, before we request the lyric, we should know more information about a certain song, such as songid, songmid that from QQ music. So we should check the existence of a certain song first.

For simplicity, build a form that accepts input keywords (song name, artist, or album information) to search for certain music from QQ music.

<form class="form-row">
  <div class="form-group col-10">
    <label for="inputKewords" class="sr-only">keywords</label>
    <input type="text" class="form-control" id="inputKeywords" placeholder="keywords">
  </div>
  <div class="col-2"><button type="submit" class="btn btn-primary mb-2">Search</button></div>
</form>

URL for searching music is3:

https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?g_tk=5381&uin=0&format=jsonp&jsonpCallback=callback&inCharset=utf-8&outCharset=utf-8&notice=0&platform=h5&needNewCode=1&w=%E6%AC%A7%E9%98%B3%E6%9C%B5&zhidaqu=1&catZhida=1&t=0&flag=1&ie=utf-8&sem=1&aggr=0&perpage=20&n=20&p=1&remoteplace=txt.mqq.all&_=1512564562121
  • w: the keywords for searching
  • p: the present page
  • n: the number of songs per page
  • format: the string format, typically is utf-8
  • jsonpCallback: the jsonp callback function, you can define your own callback function name

with Ajax, we can request the information like:

function queryData(keywords) {
  let urlString = `https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?g_tk=5381&uin=0&format=jsonp&jsonpCallback=callback&inCharset=utf-8&outCharset=utf-8&notice=0&platform=h5&needNewCode=1&w=${keywords}&zhidaqu=1&catZhida=1&t=0&flag=1&ie=utf-8&sem=1&aggr=0&perpage=20&n=20&p=1&remoteplace=txt.mqq.all`;

  $.ajax({
    type: "get",
    url: urlString,
    dataType: "jsonp",
    jsonp: "callback",
    jsonpCallback: "callback",
    scriptCharset: 'utf-8',
    success: function(data) {
      // todo
    },
    error: function() {
      alert('fail')
    }
  });
}

OK, try it use the following form, it will give at most 5 results for your keywords (sets in n parameter) and fill in a table. If you’re using a http proxy (such as unBlock youku), this form will fail to work.

In the console log, you could find a returned array about the search results.

query the lyric

To get the lyric, we need to know the songid that included in the results of the previous step.

The lyric URL is something like: https://music.qq.com/miniportal/static/lyric/10/4900010.xml.

  • 10: the result of songid%10
  • 4900010: the songid

I have injected the id to the table items. You can now click on the table item to get the URL of the lyric, and it will present in the pre tag below. Notice that, this will only return an URL to you, not guarantee the URL really exists. After that, you can fetch lyric data from the XML address via Ajax request.

loading

Click the button will toggle the real lyric or a no lyric string if lyric does not exist. If it shows ‘loading’, just wait a few moment…

Will, to get this xml lyric you have to deal with CORS issue, and it seems that this xml method typically return you null data. So, back to the old script, actually you can fetch lyric from https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.new.fcg with the help of node.js with axios module. Something like this:

function getLyric(songmid, response) {
  const link = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg';
  axios.get(link, {
    params: {
      songmid: songmid, // songmid passed here
      g_tk: 5381
    },
    headers: {
      referer: 'https://y.qq.com/portal/player.html' // must have this referer for lyric
    }
  })
  .then(res => {
    let data = res.data.slice(18, -1);
    data = JSON.parse(data);
    if (data.lyric) {
      let lyric = new Buffer(data.lyric, 'base64').toString('utf-8'); // decode base64 lyric
      response.send(lyric);
    } else {
      response.send('not available')
    }
    response.end();
  })
  .catch(error => {
    response.send('error');
    response.end();
  })
}

This will return the lyric as text. Try the following button if you get “null” data from previous button. (No button below? try to enter some keywords in the form above, and click certain items in the table follows.)

loading

This is actually get data from

https://muzapi-shhprftrrt.now.sh/qmlyric?mid=${mid}

that I made for demo. Pass the songmid parameter to query the exact lyric.

This is just a simple demo, you can play around with those APIs from the reference list below and make things happen. But, I have to say, all these is just for study useage…

lyric QQ ajax