playlistGET = (type, callback = null) => {
  return (dispatch, getState) => {
    // loading before get playlist songs
    if (type !== 'rate' && type !== 'unrate' && type !== 'end') {
      dispatch(actions.playlistLoading())
    }
    dispatch(playlistTypes[type]()) // dispatch action according playlistTypes

    if (
      !alreadySetOpenPattern &&
      type === 'new' &&
      getState().authReducer._id === 1 &&
      getState().settingReducer.openPattern === 'personal'
    ) {
      dispatch(actions.appChannelSet(0))
    }
    alreadySetOpenPattern = true

    const { authReducer, fmReducer, settingReducer } = getState()
    axios(
      Object.assign(
        {
          method: 'GET',
          url:
            playlistOriginUrl +
            genBitRate(
              authReducer.userInfo.pro_status && authReducer.userInfo.pro_status === 'S',
              settingReducer.preferBitRate
            ) +
            '&pt=' +
            fmReducer.playtime +
            '&channel=' +
            fmReducer.channelId +
            '&type=' +
            fmReducer.type +
            '&sid=' +
            (type !== 'new' ? fmReducer.sid : ''),
        },
        // is login
        authReducer._id === 1 && {
          headers: {
            Authorization: 'Bearer ' + authReducer.userToken.access_token,
          },
        }
      )
    )
      .then((response) => {
        if (type === 'end' || type === 'rate' || type === 'unrate') {
          return
        }
        let playlist = response.data,
          song = playlist.song[0],
          sid = song.sid,
          ssid = song.ssid
        // if type is rate or unrate, the next similar song will add into current songs array
        dispatch(actions.playlistResponse(sid, ssid, song))
        if (callback !== null && typeof callback === 'function') {
          callback()
        }
      })
      .catch(console.log)
  }
}
Core function, get playlist

@param {string} type - playlist type
@returns - a thunk function which handle playlist operation