Search code examples
qtc++11qwebengineview

QWebEngine download restart after a reboot


I did an application to download softwares. It's works well with QWebengine.

For the second version, I need to implement the restart of the download after the application is turned off.

My goal is to get possible to restart the same download at the same status after a reboot.

Is it possible?

How to save the status of the current download in a file with WebEngineDownloadItem ?

Thank you for your help


Solution

  • This is how I did :

    DownloaderWidget.hpp

    #ifndef DOWNLOADERWIDGET_HPP
    #define DOWNLOADERWIDGET_HPP
    
    # include <QUrl>
    # include <QApplication>
    # include <QPushButton>
    # include <QString>
    # include <QWidget>
    # include <QLabel>
    # include <QVBoxLayout>
    # include <QProgressBar>
    # include "downloadermanager.hpp"
    
    
    class DownloaderWidget : public QWidget
    {
            Q_OBJECT
        public:
            explicit DownloaderWidget(QWidget *parent = nullptr);
    
        signals:
    
        public slots:
            void                download(void);
            void                pause(void);
            void                resume(void);
        private slots:
            void                progress(int percent);
        private:
            static QString const
                                URL;
            QLabel              *m_url;
            QPushButton         *m_start;
            QPushButton         *m_resume;
            QPushButton         *m_pause;
            QProgressBar        *m_status;
            DownloaderManager   *m_download_manager;
    };
    
    #endif // DOWNLOADERWIDGET_HPP
    

    DownloaderManager.hpp

        #ifndef DOWNLOADERMANAGER_HPP
    #define DOWNLOADERMANAGER_HPP
    
    # include <QUrl>
    # include <QObject>
    # include <QDebug>
    # include <QNetworkAccessManager>
    # include <QNetworkRequest>
    # include <QNetworkReply>
    # include <QFile>
    # include <QByteArray>
    # include <QStandardPaths>
    
    class DownloaderManager : public QObject
    {
            Q_OBJECT
        public:
            explicit            DownloaderManager(QObject *parent = nullptr);
    
        signals:
            void                downloadComplete(void);
            void                progress(int const percentage);
        public slots:
            void                download(QUrl const &url);
            void                pause();
            void                resume();
        private slots:
            void                download(QNetworkRequest &request);
            void                finished();
            void                downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
            void                error(QNetworkReply::NetworkError code);
        private:
            QNetworkAccessManager
                                *m_manager;
            QNetworkRequest     m_request;
            QNetworkReply       *m_reply;
            QFile               *m_file;
            qint64              m_downloadSizeAtPause;
            QString             m_name;
            QString             get_file_name(QUrl const &url);
    };
    
    #endif // DOWNLOADERMANAGER_HPP
    

    DownloaderWidget.cpp

        #include "downloaderwidget.hpp"
    
    QString const               DownloaderWidget::URL = "My great URL";
    
                                DownloaderWidget::DownloaderWidget(QWidget *parent)
            : QWidget(parent),
            m_url(new QLabel(URL, this)),
            m_start(new QPushButton("Start", this)),
            m_resume(new QPushButton("Resume", this)),
            m_pause(new QPushButton("Pause", this)),
            m_status(new QProgressBar(this)),
            m_download_manager(new DownloaderManager(this))
    {
        QVBoxLayout             *main_layout = new QVBoxLayout(this);
    
        m_status->setOrientation(Qt::Horizontal);
        main_layout->addWidget(m_url);
        main_layout->addWidget(m_status);
        main_layout->addWidget(m_start);
        main_layout->addWidget(m_pause);
        main_layout->addWidget(m_resume);
        QObject::connect(m_start, SIGNAL(clicked()), this, SLOT(download()));
        QObject::connect(m_pause, SIGNAL(clicked()), this, SLOT(pause()));
        QObject::connect(m_resume, SIGNAL(clicked()), this, SLOT(resume()));
        QObject::connect(m_download_manager, SIGNAL(downloadComplete()), qApp, SLOT(quit()));
        QObject::connect(m_download_manager, SIGNAL(progress(int)), this, SLOT(progress(int)));
        this->m_pause->setEnabled(false);
        this->m_resume->setEnabled(false);
    }
    
    void                        DownloaderWidget::download(void)
    {
        this->m_download_manager->download(QUrl(URL));
        this->m_start->setEnabled(false);
        this->m_pause->setEnabled(true);
    }
    
    void                        DownloaderWidget::pause()
    {
        this->m_download_manager->pause();
        this->m_pause->setEnabled(false);
        this->m_resume->setEnabled(true);
    }
    
    void                        DownloaderWidget::resume(void)
    {
        this->m_download_manager->resume();
        this->m_pause->setEnabled(true);
        this->m_resume->setEnabled(false);
    }
    
    void                        DownloaderWidget::progress(int percent)
    {
        this->m_status->setValue(percent);
    }
    

    DownloaderManager.cpp

        #include "downloadermanager.hpp"
    
                                DownloaderManager::DownloaderManager(QObject *parent) :
            QObject(parent),
            m_manager(new QNetworkAccessManager(this)),
            m_request(),
            m_reply(nullptr),
            m_file(nullptr),
            m_downloadSizeAtPause(0),
            m_name("")
    {
    
    }
    
    QString                     DownloaderManager::get_file_name(QUrl const &url)
    {
        QStringList             list = url.toString().split("/");
        this->m_name = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/" + list[list.length() - 1];
    
        return (this->m_name + ".download");
    }
    
    void                        DownloaderManager::download(QUrl const &url)
    {
        this->m_name = this->get_file_name(url);
        qDebug() << "Download : file = " << this->m_name;
        this->m_downloadSizeAtPause = 0;
        this->m_request = QNetworkRequest(url);
        this->m_file = new QFile(this->m_name);
        this->m_file->open(QIODevice::ReadWrite | QIODevice::Append);
        if (this->m_file->size() != 0)
            this->resume();
        else
            this->download(this->m_request);
    }
    
    void                        DownloaderManager::pause(void)
    {
        qDebug() << "pause()";
        if(this->m_reply == nullptr)
            return;
        QObject::disconnect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
        QObject::disconnect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
                this, SLOT(downloadProgress(qint64, qint64)));
        QObject::disconnect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
                this, SLOT(error(QNetworkReply::NetworkError)));
    
        this->m_reply->abort();
        this->m_file->write(this->m_reply->readAll());
        this->m_reply = nullptr;
    }
    
    void                        DownloaderManager::resume(void)
    {
        qDebug() << "resume()";
    
        this->m_file->flush();
        this->m_downloadSizeAtPause = this->m_file->size();
        QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(this->m_downloadSizeAtPause) + "-";
        this->m_request.setRawHeader("Range",rangeHeaderValue);
    
        this->download(this->m_request);
    }
    
    void                        DownloaderManager::download(QNetworkRequest &request)
    {
        qDebug() << "download( QNetworkRequest& request )";
    
        this->m_reply = this->m_manager->get(request);
        QObject::connect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
        QObject::connect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
                this, SLOT(downloadProgress(qint64, qint64)));
        QObject::connect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
                this, SLOT(error(QNetworkReply::NetworkError)));
    }
    
    void                        DownloaderManager::finished(void)
    {
        qDebug() << "finihsed";
    
        this->m_file->rename(this->m_name + ".download", this->m_name);
        this->m_file->close();
        this->m_file = nullptr;
        this->m_reply = nullptr;
        emit downloadComplete();
    }
    
    void                        DownloaderManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
    {
        qDebug() << "Download Progress: Received=" << this->m_downloadSizeAtPause + bytesReceived <<": Total=" << this->m_downloadSizeAtPause + bytesTotal;
    
        this->m_file->write(this->m_reply->readAll());
        int                     percentage =
                static_cast<int>((this->m_downloadSizeAtPause + bytesReceived) * 100 ) / (this->m_downloadSizeAtPause + bytesTotal);
        qDebug() << percentage;
        emit progress(percentage);
    }
    
    void                        DownloaderManager::error(QNetworkReply::NetworkError code)
    {
        qDebug() << "Error:" <<code;
    }
    

    main.cpp

        #include <QApplication>
    #include "downloaderwidget.hpp"
    
    int                         main(int argc, char **argv)
    {
        QApplication            app(argc, argv);
        DownloaderWidget        downloader;
    
        downloader.show();
        return (app.exec());
    }
    

    I hope this piece of code will help some one in the same case than me Thank you