使用QT开发的简易音乐播放器

项目地址

项目简介:

自己用C With Class C++做的一个小项目,GUI界面使用的是Qt5.12,播放模块一开始使用Qt自带的multimedia模块,后改为VLC-qt以支持更多格式。
本项目主要用于学习目的,需要的可以借鉴,也欢迎提出意见和建议。
功能特点与展望:
支持打开文件夹并自动搜索合法音频文件(暂不支持递归搜索),还可以拖拽文件到界面上。

支持多种格式。

支持简单的播放列表。可以保存、加载播放列表。也支持下次启动时自动装入上次退出时的播放列表。后期或将加入多个播放列表的支持。

目前界面比较丑,后期可能会美化界面,还可能加入网络音乐播放功能之类的功能。

分模块介绍:

音乐信息模块:实现存放音乐信息,并具有对文件合法性的简单判断功能。
类定义:

class Music {
private:
    QString formattedTime;
    QUrl url;
    //歌曲名
    QString title,description,album;
    QUrl albumImage;
    int length;
    static bool isMPEG(QFile *media,QDataStream &reader);
    static bool isWav(QFile *media,QDataStream &reader);
    static bool isWma(QFile *media,QDataStream &reader);
    static bool isAiff(QFile *media,QDataStream &reader);
    static bool isFlac(QFile *media,QDataStream &reader); 
    static bool isAAC(QFile *media,QDataStream &reader);
    static bool isM4A(QFile *media,QDataStream &reader);
    static bool isAPE(QFile *media,QDataStream &reader);
    static bool isVorbis(QFile *media,QDataStream &reader);
    static bool isAU(QFile *media,QDataStream &reader);
public:
    /**
     * 根据指定的URL建立音乐对象
     * @param uri 给定的URL
     * @note 本构造函数**不会**判断URL是否合法
     */
    Music(const QUrl &uri = QUrl());
    Music(const Music &a) = default;
    ///获取包含标题、时间、唱片集、描述的音乐信息
    QString toString();
    /**
     * 比较两个Music是否相等
     * @param a 另一个Music
     * @return 当且仅当满足以下条件之一时返回true:
     * 1.url相同
     * 2.长度,标题均相同
     */
    bool equals(const Music &a) const;
    friend bool operator==(const Music &a,const Music &b) {
        return a.equals(b);
    }
    friend bool operator!=(const Music &a,const Music &b) {
        return !a.equals(b);
    }
    //hash相同,可能不同,但若hash不同,则认为一定不同
    friend uint qHash(const Music &key,uint seed = 0) {
        return qHash(key.title,seed) ^ qHash(key.length,seed);
    }
    //getters
    ///获取Url
    const QUrl &getUrl() const;
    /// 获取标题
    const QString &getTitle() const;
    /// 获取介绍
    const QString &getDcrp() const;
    /// 获取专辑图片 注意:可能不准
    const QUrl &getAlbumImage() const;
    ///获取经格式化后的时间
    QString formatTime();
    /**
     * @brief 检查文件是否合法
     * @param media  被检查的文件名。
     * @return 当文件>1KB且符合任意一种支持的格式时,返回true,否则返回false
     */
    static bool isLegal(QString media);

};
#endif // MUSIC_H

UI模块,包括主窗口模块和自定义控件模块。
主窗口(Playerwindow)模块就是整个播放器的主窗口。模块负责用户与播放器的交互。继承于QMainWindow。
自定义控件模块,包括播放列表(PlayListView),播放器控件(PlayerButton),进度条(PlayerSlider)。分别继承于QListView,QLabel,QSlider,为适应功能需求进行了扩展。

播放器核心模块(PlayerCore)继承于VlcMediaPlayer,其实就是对VlcMediaPlayer的一些封装与扩展。内部有一个静态VlcInstance对象,不同player之间共享。

类定义:

class PlayerCore : public VlcMediaPlayer{
    Q_OBJECT
private:
    static VlcInstance ins;
    VlcEqualizer *equ;
    VlcMedia *curMedia;
    QSet<Music> medias;
    QList<QUrl> list;
    int current = -1;
    int startLoc = 0;
    void connectSlots();
    void setMedia(const QString &media);
public:
    static constexpr int MAX_MEDIA_COUNT = 10000;
    static constexpr int MODE_COUNT = 4,FORMAT_COUNT = 16;
    static const QString Formats[FORMAT_COUNT];
    /// 各模式的提示文字
    static const QString MODE_TIPS[MODE_COUNT];
    /// 播放模式
    enum PlayMode{SIGNLE = 0,SEQUENTIAL,SIGNLE_LOOP,LIST_LOOP};
    PlayMode mode = SIGNLE;
    explicit PlayerCore(QObject *parent = nullptr);
    ///获取当前媒体url
    QUrl getMedia();
    ///获取指定编号的媒体目录url
    const QUrl &getMedia(int i);
    ///获取媒体详细信息
    Music getMediaDetail(int i);
    Music getMediaDetail();
    ///获取以秒为单位的时间
    int getPosInSecond();
    int getCurrentMediaIndex();
    ///设置时间,以秒为单位
    void setPos(int pos);
    ///设置播放列表位置
    void setCurrentMediaIndex(int i);
    ///添加到播放列表
    bool addToList(const QString &media,bool local = true);
    /**
     * 从播放列表中移除特定媒体
     * 若移除的是当前活动媒体,则自动将当前活动媒体设为上一个,如果同时是第一个则设为删除后的第一个(即原来的第二个)
     */
    bool removeFromList(int loc);
    ///清空播放列表
    void clear();
    bool isLocal(int i);
    ~PlayerCore();
public slots:
    void play();
    void goNext();
    void goPrevious();
    /**
     * @brief moveUp 将指定媒体上移
     * @param i 要移动哪个媒体
     * @param k 移动多少个单位
     * @return 当i位置合法且移动后的位置仍合法,返回true,否则返回false
     * @note moveDown类似
     */
    bool moveUp(int i,int k = 1);
    bool moveDown(int i, int k = 1);
    void setSoundEffect(uint index);
signals:
    void finished();
    //void mediaSourceChanged(qint64 newTime);
};

网络模块:支持网络音乐搜索、播放。实现搜索的核心采用python爬虫脚本实现,用pyinstaller编译成可执行文件后供C++调用,通过参数传递搜索关键词
爬虫的核心代码如下

host = "https://www.xzmp3.com"
pool = ThreadPool(20)
fp = open("links.tmp","w",encoding="utf-8")
# 第一步:获取下载页面的URLs
def get_downpage_list(name:str):
    search_page = host + "/xiazai/"
    uri = search_page + parse.quote(name) + ".htm"
    response = request.urlopen(request.Request(uri,headers=head,method="GET"))
    page_text = response.read().decode("utf-8")
    tree = etree.HTML(page_text)
    # html/body/div/div[2]/div/div[2](截止到这里是"body")/div[1]/div/div[3]/div[1]/div[i]/a
    result = tree.xpath("//body/div/div[2]/div/div[2]//div[@class=\"list_row\"]")
    #print(result)
    #开始查找urls
    url_list = []
    for each in result:
        location = each.xpath("./div[1]/a/@href")
        title = each.xpath("./div[1]/a/text()")
        singer = each.xpath("./div[2]/a/text()")
        if len(location)>0:
            url_list.append(title[0] + ';' + singer[0] + ';' + host+location[0])
    for i in range(0,len(url_list),10):
        pool.map(get_downlink,url_list[i,min(len(url_list),i+10)]) # 分成10个1组
    pool.close()
    pool.join()
# 第二步:从获取到的URLs中提取实际下载地址,保存在文件中
def get_downlink(info:str):
    lst = info.split(';')
    response = request.urlopen(request.Request(url=lst[2],headers=head,method="GET"))
    page_text = response.read().decode("utf-8")
    tree = etree.HTML(page_text)
    result_addr = tree.xpath("//body/div/div[2]/div[1]/div[2]/div[1]/div/div[2]/div[1]/a")
    # fp.write(result_addr[0].xpath("./@href")[0])
    response = request.urlopen(request.Request(url=result_addr[0].xpath("./@href")[0],headers=head,method="GET"))
    true_url = response.geturl()
    if(true_url.find(host) < 0 and (not true_url.endswith("/404"))):
        fp.write(lst[0] + ';' + lst[1] + ';' +  true_url + '\n')
if __name__ == "__main__":
    if len(sys.argv) < 2:
        fp.close()
        raise Exception("错误:未指定关键词")
    # st = time.time()
    get_downpage_list(sys.argv[1])
    # print(time.time() - st)
    fp.close()

实现效果:
(左下角为专辑图片)

初始界面
使用QT开发的简易音乐播放器_第1张图片

正在播放
使用QT开发的简易音乐播放器_第2张图片

拖拽
使用QT开发的简易音乐播放器_第3张图片
加载播放列表
8.20更新:支持网络音乐搜索和打开外部文件,效果如下:
使用QT开发的简易音乐播放器_第4张图片
9.20更新:更新代码
10.4更新:更新部分截图

你可能感兴趣的:(C++,qt,开发语言)