QT音乐播放器(接入网易云API)

实现的功能

1.可以播放本地音乐
2.实现常用功能(上下曲,播放/暂停,显示播放时长)
3.通过网易云API搜索歌曲


实现步骤

1.在pro文件里面添加multimedia库和network库
2.设计好自己的UI界面
3.添加自己需要的头文件并定义自己需要的变量
4.打开自己存放歌曲的目录,将歌曲添加到歌曲列表然后进行播放
5.通过信号与槽机制实现常用的功能
6.接入网易云API进行歌曲搜索

ui界面展示


代码模块展示

添加本地文件


    file = QFileDialog::getOpenFileName(this,
                                         "Open File",
                                         "D:/Music",
                                         "mp3 Files (*.mp3)");//打开MP3文件,如果需要添加其余音频文件,只需继续添加过滤项即可
    playlist->addMedia(QUrl(file));//将自己需要的MP3文件添加入播放列表
    //以下是去掉前面的路径并且追加显示到plainTextEdit(将名字复制到另一个字符串)
    int fi=0,af=9;//fi为新字符串的开始位置,af为歌曲名字的第一个位置(自己的路径)
    QString s;//新字符串
    while(file[af]!='\0')将歌曲名字移动到数组开头
    {
        s[fi]=file[af];
        fi++;
        af++;
    }
    s[fi]='\0';//添加字符串结束标志
    ui->plainTextEdit->appendPlainText(s);//显示到plainTextEdit

播放/暂停

//通过标志位来实现播放与暂停
if(x==0)   //如果是停止状态或暂停就播放
{
    player->play();
    x=1;    //置1下一次点击就会暂停
}
else if(x==1)         //如果是播放状态就暂停
{
    player->pause();    
    x=0;    //置0下一次点击就会播放
}

下一曲

  //点击下一曲,如果当前歌曲是最后一首歌曲,就跳到第一首歌,其余则直接跳到下一首
    int m_Value=playlist->currentIndex();    //当前歌曲是第几个
    int m_Amount=playlist->mediaCount();    //总歌曲数量
    if(m_Value<m_Amount)    //判断当前歌曲是否为最后一首
    {
        m_Value=m_Value+1;    //播放的位置+1
        playlist->setCurrentIndex(m_Value);   //重新设置播放的位置
        player->play();    
    }
    else
    {
        m_Value=0;
        playlist->setCurrentIndex(m_Value);    //跳到第一首
        player->play();
    }

上一曲与之类似

时间显示

//通过槽函数实现
void Widget::timechange(qint64 duration)
{
    int secs = duration/1000; //全部秒数
    int mins = secs/60;//分
    secs = secs % 60;//秒
    QString str=QString::asprintf("%d:%d",mins,secs);//转换为字符串
    ui->lcdNumber->display(str);//用lcdNumber进行显示
}

正在播放歌曲显示

//通过信号与槽机制检测文件是否变化
void Widget::onDurationChanged(qint64 duration) //文件时长变化,更新当前播放文件名显示播放文件数据总大小的信号, 它可以获得文件时间长度。
{
    ui->horizontalSlider->setMaximum(duration); //设置进度条最大值 也就是歌曲时长 ms
    int m_Value=playlist->currentIndex();//获取当前歌曲的位置
    QTextBlock textLine=doc->findBlockByNumber (m_Value) ;//获取当前文本中的一段
    QString str=textLine.text();//将获取后的数据转为字符串
    int fi=0,af=9;
    QString s;
    if(str[0]=='D')//判断是否为本地文件(我的歌是在D盘里面的,所以第一个字符是D)
    {
        while(str[af]!='\0')
        {
            s[fi]=str[af];
            fi++;
            af++;
        }
    s[fi]='\0';
    ui->lineEdit->setText(s);
    }
    else
        ui->lineEdit->setText(str);
}

进度条显示

void Widget::onPositionChanged(qint64 position)//当前文件播放位置变化,更新进度显示播放到什么位置的信号, 参数是以毫秒来计算的。
{
    if(ui->horizontalSlider->isSliderDown())
        return;//如果手动调整进度条,则不处理
    ui->horizontalSlider->setSliderPosition(position);//设置进度条的位置
}

搜索歌曲ID


void Widget::on_b_search_clicked()
{

    ui->music_m->clear();
    QString str,s;
    s=ui->l_search->text();//获取在搜索框输入的数据
    str="http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={"+s+"}&type=1&offset=0&total=true&limit=1";//接入网易云API并且传入需要搜索的数据和返回的数量
    QNetworkRequest request;          //定义一个请求对象
    request.setUrl(str);      //将请求格式设置给请求对象
    manager->get(request);              //请求

}

解析返回的数据

void Widget::databack(QNetworkReply *reply)
{

    searchInfo=reply->readAll();    //读取返回的全部数据
    QJsonParseError err;               //错误信息对象
    QJsonDocument json_recv = QJsonDocument::fromJson(searchInfo,&err);//将json文本转换为 json 文件对象
    if(err.error != QJsonParseError::NoError)             //判断是否符合语法
    {
        qDebug() <<"搜索歌曲Json获取格式错误"<< err.errorString();
        return;
    }
    QJsonObject totalObject = json_recv.object();
        QStringList keys = totalObject.keys();    // 列出json里所有的key
        if(keys.contains("result"))                 //如果有结果
        {       //在 json 文本中 {}花括号里面是QJsonObject对象, []方括号里面是QJsonArray

            QJsonObject resultObject = totalObject["result"].toObject();     //就将带 result 的内容提取后转换为对象
            QStringList resultKeys = resultObject.keys();      //保存所有key
            if(resultKeys.contains("songs"))                    //如果 key 为songs ,代表找到了歌曲
            {
                QJsonArray array = resultObject["songs"].toArray();
                for(auto i : array)                   //开始获取歌曲中的信息
                {
                    QJsonObject object = i.toObject();
                    musicId = object["id"].toInt();                         // 音乐id
                    musicDuration = object["duration"].toInt();             // 音乐长度
                    musicName = object["name"].toString();                  // 音乐名
                    mvId = object["mvid"].toInt();                          // mvid
                    QStringList artistsKeys = object.keys();
                    if(artistsKeys.contains("artists"))                //如果result中包含了 artists
                    {
                        QJsonArray artistsArray = object["artists"].toArray();   //将 artist 的内容提取后保存
                        for(auto j : artistsArray)
                        {
                            QJsonObject object2 = j.toObject();
                            singerName = object2["name"].toString();         // 歌手名
                        }
                    }
                    if(artistsKeys.contains("album"))                //包含了专辑
                    {
                        QJsonObject albumObjct = object["album"].toObject();
                        albumName = albumObjct["name"].toString();            // 专辑名
                    }
                         ui->music_m->appendPlainText("音乐ID:"+QString::number(musicId));
                         ui->music_m->appendPlainText("音乐名:"+musicName);
                         ui->music_m->appendPlainText("歌手名:"+singerName);
                         ui->music_m->appendPlainText("总时长:"+QString::number(musicDuration));
                         ui->music_m->appendPlainText("专辑名:"+albumName);
                }
            }
        }
        QString url;
        url=QString("https://music.163.com/song/media/outer/url?id=%0").arg(musicId);//通过网网易云API传入之前返回的歌曲的ID实现播放
        playlist->addMedia(QUrl(url)); //添加一音乐到播放列表中
        ui->plainTextEdit->appendPlainText(musicName); //用于显示
}

遇到的问题:

1.网易云的API(自己在网上找的)

有关评论
http://music.163.com/api/v1/resource/comments/R_SO_4_{歌曲ID}?limit=20&offset=0
limit:返回数据条数(每页获取的数量),默认为20,可以自行更改
offset:偏移量(翻页),offset需要是limit的倍数
type:搜索的类型

歌单
https://music.163.com/api/playlist/detail?id={歌单ID}
网易云音乐每日推荐各种神奇歌单也是它的一大特色,我们可以利用这个api获取歌单里的所有歌曲信息。

用户信息
https://music.163.com/api/v1/user/detail/{用户ID}

歌词
https://music.163.com/api/song/lyric?id={歌曲ID}&lv=1&kv=1&tv=-1

搜索结果
http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={搜索内容}&type=1&offset=0&total=true&limit=20
limit:返回数据条数(每页获取的数量),默认为20,可以自行更改
offset:偏移量(翻页),offset需要是limit的倍数
type:搜索的类型
type=1           单曲
type=10         专辑
type=100        歌手
type=1000      歌单
type=1002      用户
type=1004      MV
type=1006      歌词
type=1009      主播电台


歌手专辑
http://music.163.com/api/artist/albums/{歌手ID}?id={歌手ID}&offset=0&total=true&limit=10

专辑信息
http://music.163.com/api/album/{专辑ID}?ext=true&id={专辑ID}&offset=0&total=true&limit=10

歌曲信息
http://music.163.com/api/song/detail/?id={歌曲ID}&ids=%5B{歌曲ID}%5D

MV
http://music.163.com/api/mv/detail?id={MV的ID}&type=mp4

2.可能报的错

qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed
大致说,Qt模块中是包含了OpenSSL库的,但是这些库不会自动部署到应用程序中。开发人员希望使用SSL的同时,它们的用户也安装了相关库。或者确保在当地使用SSL是经过许可
可以安装opssl解决

doRender: Unknown error 0x80040218.
可能是因为没有装解码组件可以去安装一个 LAVFilters:
也可能是因为播放的音乐是VIP音乐(播放VIP音乐就会报这个错)

效果视频单独发布了(用的那个游戏盒子录的屏,跳出来的文件夹没有显示)

源码

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QList>
#include <QMediaContent>
#include <QTextBlock>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();



public slots:
    void on_pushButton_2_clicked();
    void on_pushButton_clicked();
    void on_next_clicked();
    void on_up_clicked();
    void timechange(qint64 duration);
    void onDurationChanged(qint64 duration); 
    void onPositionChanged(qint64 position); 
    void on_b_search_clicked();
    void databack(QNetworkReply *reply);


private:
    Ui::Widget *ui;
    QString durationTime;
    QString positionTime;
    QNetworkAccessManager* manager;
    QMediaPlayer *player;
    QMediaPlaylist *playlist;
    QString file;
    QTextDocument* doc;
    QTextBlock textLine;
    QString str;
    int i,x;
    int musicId,musicDuration,mvId;
    QString musicName,singerName,albumName;
    QByteArray searchInfo;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QLCDNumber>
#include <QString>
#include <QBrush>



Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setMinimumSize(600,600);
    this->setMaximumSize(600,600);//我固定了窗口的大小
    ui->music_m->setReadOnly(true);//将显示信息的组件设置设置为只读
    manager = new QNetworkAccessManager(this);   //定义并实例化一个网络管家
    ui->plainTextEdit->setReadOnly(true);//将显示音乐列表的组件设置为只读
    ui->lineEdit->setReadOnly(true);//将显示正在播放音乐的组件设置为只读
    this->setWindowTitle("QT播放器");//设置窗口标题
    x=0;//初始化标志位
    doc=ui->plainTextEdit->document () ; //文本对象
    player=new QMediaPlayer(this);
    playlist=new QMediaPlaylist(this);//初始化对象
    player->setMedia(playlist);//设置播放列表
    playlist->setPlaybackMode(QMediaPlaylist::Loop);设置播放模式
    //信号与槽机制进行处理
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(timechange(qint64)));
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPositionChanged(qint64)));
    connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(onDurationChanged(qint64)));
    connect(manager,SIGNAL(finished(QNetworkReply *)),this,SLOT(databack(QNetworkReply *)));

}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_2_clicked()
{
    file = QFileDialog::getOpenFileName(this,"Open File","D:/Music","mp3 Files (*.mp3)");//打开文件
    playlist->addMedia(QUrl(file));//将选中的MP3文件添加到播放列表
    //将选中的文件去掉路径后追加显示到plainTextEdit
    int fi=0,af=9;
    QString s;
    while(file[af]!='\0')
    {
        s[fi]=file[af];
        fi++;
        af++;
    }
    s[fi]='\0';
    ui->plainTextEdit->appendPlainText(s);


}

void Widget::on_pushButton_clicked()
{

       if(x==0)   //如果是停止状态或暂停就播放
       {
            player->play();
            x=1;
       }
       else if(x==1)         //如果是播放状态就暂停
       {
           player->pause();
           x=0;
       }
}



void Widget::on_next_clicked()
{
    int m_Value=playlist->currentIndex();//当前歌曲是第几个
    int m_Amount=playlist->mediaCount();   //总歌曲数量
    if(m_Value<m_Amount)
    {
        m_Value=m_Value+1;
        playlist->setCurrentIndex(m_Value);
        player->play();
    }
    else
    {
        m_Value=0;
        playlist->setCurrentIndex(m_Value);
        player->play();
    }


}

void Widget::on_up_clicked()
{
    int m_Value=playlist->currentIndex();//当前歌曲是第几个
    int m_Amount=playlist->mediaCount();   //总歌曲数量
    if(m_Value>0)
    {
        m_Value=m_Value-1;
        playlist->setCurrentIndex(m_Value);
        player->play();
    }
    else
    {
        m_Value=m_Amount-1;
        playlist->setCurrentIndex(m_Value);
        player->play();
    }
}
void Widget::timechange(qint64 duration)
{
    int secs = duration/1000; //全部秒数
    int mins = secs/60;//分
    secs = secs % 60;//秒
    QString str=QString::asprintf("%d:%d",mins,secs);
    ui->lcdNumber->display(str);
}

void Widget::onDurationChanged(qint64 duration) //文件时长变化,更新当前播放文件名显示播放文件数据总大小的信号, 它可以获得文件时间长度。
{
    ui->horizontalSlider->setMaximum(duration); //设置进度条最大值 也就是歌曲时长 ms
    int m_Value=playlist->currentIndex();
    QTextBlock textLine=doc->findBlockByNumber (m_Value) ; // 文本中的一段
    QString str=textLine.text();
    int fi=0,af=9;
    QString s;
    if(str[0]=='D')
    {
        while(str[af]!='\0')
        {
            s[fi]=str[af];
            fi++;
            af++;
        }
    s[fi]='\0';
    ui->lineEdit->setText(s);
    }
    else
        ui->lineEdit->setText(str);
}
void Widget::onPositionChanged(qint64 position)//当前文件播放位置变化,更新进度显示播放到什么位置的信号, 参数是以毫秒来计算的。
{
    if(ui->horizontalSlider->isSliderDown())
        return;//如果手动调整进度条,则不处理
    ui->horizontalSlider->setSliderPosition(position);
}


void Widget::on_b_search_clicked()
{

    ui->music_m->clear();
    QString str,s;
    s=ui->l_search->text();
    str="http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={"+s+"}&type=1&offset=0&total=true&limit=1";
    QNetworkRequest request;          //定义一个请求对象
    request.setUrl(str);      //将请求格式设置给请求对象
    manager->get(request);              //请求

}
void Widget::databack(QNetworkReply *reply)
{

    searchInfo=reply->readAll();
    QJsonParseError err;               //错误信息对象
    QJsonDocument json_recv = QJsonDocument::fromJson(searchInfo,&err);//将json文本转换为 json 文件对象
    if(err.error != QJsonParseError::NoError)             //判断是否符合语法
    {
        qDebug() <<"搜索歌曲Json获取格式错误"<< err.errorString();
        return;
    }
    QJsonObject totalObject = json_recv.object();
        QStringList keys = totalObject.keys();    // 列出json里所有的key
        if(keys.contains("result"))                 //如果有结果
        {       //在 json 文本中 {}花括号里面是QJsonObject对象, []方括号里面是QJsonArray

            QJsonObject resultObject = totalObject["result"].toObject();     //就将带 result 的内容提取后转换为对象
            QStringList resultKeys = resultObject.keys();      //保存所有key
            if(resultKeys.contains("songs"))                    //如果 key 为songs ,代表找到了歌曲
            {
                QJsonArray array = resultObject["songs"].toArray();
                for(auto i : array)                   //开始获取歌曲中的信息
                {
                    QJsonObject object = i.toObject();
                    musicId = object["id"].toInt();                         // 音乐id
                    musicDuration = object["duration"].toInt();             // 音乐长度
                    musicName = object["name"].toString();                  // 音乐名
                    mvId = object["mvid"].toInt();                          // mvid
                    QStringList artistsKeys = object.keys();
                    if(artistsKeys.contains("artists"))                //如果result中包含了 artists
                    {
                        QJsonArray artistsArray = object["artists"].toArray();   //将 artist 的内容提取后保存
                        for(auto j : artistsArray)
                        {
                            QJsonObject object2 = j.toObject();
                            singerName = object2["name"].toString();         // 歌手名
                        }
                    }
                    if(artistsKeys.contains("album"))                //包含了专辑
                    {
                        QJsonObject albumObjct = object["album"].toObject();
                        albumName = albumObjct["name"].toString();            // 专辑名
                    }
                         ui->music_m->appendPlainText("音乐ID:"+QString::number(musicId));
                         ui->music_m->appendPlainText("音乐名:"+musicName);
                         ui->music_m->appendPlainText("歌手名:"+singerName);
                         ui->music_m->appendPlainText("总时长:"+QString::number(musicDuration));
                         ui->music_m->appendPlainText("专辑名:"+albumName);
                }
            }
        }
        QString url;
        url=QString("https://music.163.com/song/media/outer/url?id=%0").arg(musicId);
        playlist->addMedia(QUrl(url));                     //添加返回的音乐到播放列表中
        ui->plainTextEdit->appendPlainText(musicName); //用于显示
}


  • 14
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值