网络播放器系列:
- qt 布局和样式表
- 基于Qt的音乐播放器(一)添加音频文件,播放音乐,更新进度条
- 基于Qt的音乐播放器(二)切换歌曲,调节音量,调节语速,暂停
- 基于Qt的音乐播放器(三)通过酷狗音乐的api接口,返回json格式歌曲信息(播放地址,歌词,图片)
- 项目已上传GitHub(更新中),点击获取
- 代码中使用到了下面的头文件:
#include<QNetworkAccessManager>
#include<QVariant>
#include<QByteArray>
#include<QJsonParseError>
#include<QJsonDocument>
#include<QJsonObject>
#include<QJsonArray>
#include<QUrl>
#include<QPixmap>
#include<QSize>
- ==创作不易,你们的三连是我创作的动力!==
1.效果图
老规矩,空口无凭,先上动态图,抓住你们的胃。
请忽视一些小细节,小BUG,后期会慢慢修复,嘿嘿!
2.准备好前面获取的酷狗api接口
- keyword:搜索的内容。
- page:搜索的页数
- pagesize:返回的数据量,填10就是返回1首歌曲的数据。
- 第一目标个是通过该接口,实现歌曲搜索,第二个目标是通过该接口获取特定歌曲的hash和album_id的值用于下面歌曲的播放,文字图片以及歌词(下一篇讲)的显示
第二个是歌曲详细接口:
http://www.kugou.com/yy/index.php?r=play/getdata""&hash===你需要填的==&album_id===你需要填的==&_=1497972864535
- hash和album_id都是第一个接口返回json解析出来的。
- 通过该接口,我们可以得到歌曲播放地址,图片地址,歌词等等
3.网络歌曲搜索实现
别忘了添加#include<QNetworkAccessManager> 和 #include<QNetworkReply>两个头文件
mainwindow.h
//添加类成员
QNetworkAccessManager * network_manager;
QNetworkRequest * network_request;
mainwindow.cpp
//构造函数中进行信号和槽的链接
//connect 有不同的写法,replyFinished也就是replyFinished()。
network_manager = new QNetworkAccessManager();
network_request = new QNetworkRequest();
connect(network_manager, &QNetworkAccessManager::finished, this, &MainWindow::replyFinished);
//点击搜索按钮调用该函数,参数为搜索框内容
void MainWindow::search(QString str)
{
QString KGAPISTR1 = QString("http://mobilecdn.kugou.com/api/v3/search/song?format=json"
"&keyword=%1&page=1&pagesize=18").arg(str);
network_request->setUrl(QUrl(KGAPISTR1));
network_manager->get(*network_request);
}
//为了简化代码,只使用参数keyword
//槽函数
void MainWindow::replyFinished(QNetworkReply *reply)
{
//获取响应的信息,状态码为200表示正常
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
//无错误返回
if(reply->error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll(); //获取字节
QString result(bytes); //转化为字符串
qDebug()<<result;
parseJson(result);//该函数用于解析api接口返回的json
}
else
{
//处理错误
qDebug()<<"搜索失败";
}
}
void MainWindow::parseJson(QString json)
{
QString songname_original; //歌曲名
QString singername; //歌手
QString hashStr; //hash
QString album_name; //专辑
int duration; //时间
QByteArray byte_array;
QJsonParseError json_error;
QJsonDocument parse_doucment = QJsonDocument::fromJson(byte_array.append(json), &json_error);
if (json_error.error == QJsonParseError::NoError)
{
if (parse_doucment.isObject())
{
QJsonObject rootObj = parse_doucment.object();
if (rootObj.contains("data"))
{
QJsonValue valuedata = rootObj.value("data");
if (valuedata.isObject())
{
QJsonObject valuedataObject = valuedata.toObject();
if (valuedataObject.contains("info"))
{
QJsonValue valueArray = valuedataObject.value("info");
if (valueArray.isArray())
{
QJsonArray array = valueArray.toArray();
int size = array.size();
for (int i = 0; i < size; i++)
{
QJsonValue value = array.at(i);
if (value.isObject())
{
QJsonObject object = value.toObject();
if (object.contains("songname_original"))//歌曲名
{
QJsonValue AlbumID_value = object.take("songname_original");
if (AlbumID_value.isString())
{
songname_original = AlbumID_value.toString();
}
}
if (object.contains("singername"))//歌手
{
QJsonValue AlbumID_value = object.take("singername");
if (AlbumID_value.isString())
{
singername = AlbumID_value.toString();
}
}
if (object.contains("album_name"))//专辑
{
QJsonValue AlbumID_value = object.take("album_name");
if (AlbumID_value.isString())
{
album_name = AlbumID_value.toString();
}
}
if (object.contains("hash")) //hash
{
QJsonValue FileHash_value = object.take("hash");
if (FileHash_value.isString())
{
hashStr = FileHash_value.toString();
//用Vector保存每首歌曲的hash
m_Vectorlist.append(FileHash_value.toString());
}
}
if (object.contains("album_id"))
{
QJsonValue FileHash_value = object.take("album_id");
if (FileHash_value.isString())
{
//用Vector保存每首歌曲的album_id
m_ID.append(FileHash_value.toString());
}
}
if (object.contains("duration"))//时长
{
QJsonValue AlbumID_value = object.take("duration").toInt();
duration = AlbumID_value.toInt();
}
//将解析出的内容放到列表中
ui->tableWidget->setItem(i,0,new QTableWidgetItem(songname_original));
//文字居中
ui->tableWidget->item(i,0)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->tableWidget->setItem(i,1,new QTableWidgetItem(singername));
ui->tableWidget->item(i,1)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
ui->tableWidget->setItem(i,2,new QTableWidgetItem(album_name));
ui->tableWidget->item(i,2)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
QString time = QString("%1:%2").arg(duration/60).arg(duration%60);
ui->tableWidget->setItem(i,4,new QTableWidgetItem(time));
ui->tableWidget->item(i,4)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
}
}
}
}
}
}
}
}
else
{
qDebug() << json_error.errorString();
}
}
如果有一天,这个代码不能用了,要注意查询的值对不对,酷狗可能是为了防止被爬,data,info,等等这些值有可能被更换成别的,要观察json。
4.网络歌曲播放的实现
当搜索列表有了内容,我们希望双击播放音乐,所以我们的第二个接口通过双击信号调用。
mainwindow.h
//类成员添加
QNetworkAccessManager * network_manager2;
QNetworkRequest * network_request2;
mainwindow.cpp
//构造函数中添加
network_manager2 = new QNetworkAccessManager();
network_request2 = new QNetworkRequest();
connect(network_manager2, &QNetworkAccessManager::finished, this, &MainWindow::replyFinished2);
void MainWindow::on_tableWidget_cellDoubleClicked(int row, int column)
{
//歌曲请求 row 是行号
QString KGAPISTR1 =QString("http://www.kugou.com/yy/index.php?r=play/getdata"
"&hash=%1&album_id=%2&_=1497972864535").arg(m_Vectorlist.at(row)).arg(m_ID.at(row));
network_request2->setUrl(QUrl(KGAPISTR1));
//这句话很重要,我们手动复制url放到浏览器可以获取json,但是通过代码不行,必须加上下面这句才可以
network_request2->setRawHeader("Cookie","kg_mid=2333");
network_request2->setHeader(QNetworkRequest::CookieHeader, 2333);
network_manager2->get(*network_request2);
}
void MainWindow::replyFinished2(QNetworkReply *reply)
{
//获取响应的信息,状态码为200表示正常
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
//无错误返回
if(reply->error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll(); //获取字节
QString result(bytes); //转化为字符串
parseJsonSongInfo(result);//解析json
}
else
{
//处理错误
qDebug()<<"歌曲播放失败";
}
}
void MainWindow::parseJsonSongInfo(QString json)
{
QString audio_name;//歌手-歌名
QString play_url;//播放地址
QString img;
QByteArray byte_array;
QJsonParseError json_error;
QJsonDocument parse_doucment = QJsonDocument::fromJson(byte_array.append(json), &json_error);
if(json_error.error == QJsonParseError::NoError)
{
if(parse_doucment.isObject())
{
QJsonObject rootObj = parse_doucment.object();
if(rootObj.contains("data"))
{
QJsonValue valuedata = rootObj.value("data");
if(valuedata.isObject())
{
QJsonObject valuedataObject = valuedata.toObject();
QString play_urlStr("");
if(valuedataObject.contains("play_url"))
{
QJsonValue play_url_value = valuedataObject.take("play_url");
if(play_url_value.isString())
{
play_urlStr = play_url_value.toString(); //歌曲的url
if(play_urlStr!="")
{
qDebug()<<play_urlStr;
player->setMedia(QUrl(play_urlStr));
player->setVolume(50);
player->play();
}
}
}
if(valuedataObject.contains("audio_name"))
{
QJsonValue play_name_value = valuedataObject.take("audio_name");
if(play_name_value.isString())
{
QString audio_name = play_name_value.toString(); //歌曲名字
if(audio_name!="")
{
//显示
qDebug()<<audio_name;
ui->label_2->setText(audio_name);
}
}
}
//下一篇的歌词获取也是在这里添加代码
//图片显示代码在这里添加
}
else
{
qDebug()<<"出错";
}
}
}
}
}
5.歌曲图片显示
mainwindow.h
//类成员添加
QNetworkAccessManager * network_manager3;
QNetworkRequest * network_request3;
mainwindow.cpp
network_manager3 = new QNetworkAccessManager();
network_request3 = new QNetworkRequest();
connect(network_manager3, &QNetworkAccessManager::finished,this, &MainWindow::replyFinished3);
//这段代码添加到上面的图片显示位置即可
if (valuedataObject.contains("img"))
{
QJsonValue play_name_value = valuedataObject.take("img");
if (play_name_value.isString())
{
QString audio_name = play_name_value.toString();
if (audio_name != "")
{
m_Jpg.append(audio_name);
network_request3->setUrl(QUrl(audio_name));
network_manager3->get(*network_request3);
}
}
}
void MainWindow::replyFinished3(QNetworkReply *reply)
{
//获取响应的信息,状态码为200表示正常
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
//无错误返回
if(reply->error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll(); //获取字节
//由于获取的图片像素过大,而我们显示的图片很小,所以我们需要压缩图片的像素,我们label的大小为45*45,所以我们把图片压缩为45*45
QPixmap pixmap;
QSize picSize(45,45);
pixmap.loadFromData(bytes);
//pixmap.save("url"); 也可以现在图片
ui->label_10->setPixmap(pixmap.scaled(picSize));
}
else
{
//处理错误
qDebug()<<"处理错误3";
}
}
上述代码还有很大的优化空间,代码重复性过大,有时间的话进行优化一波,这篇就到这里,下篇歌词的显示,不见不散。