|
@@ -0,0 +1,254 @@
|
|
|
+#include "downloader.h"
|
|
|
+#include <QEventLoop>
|
|
|
+#include <QApplication>
|
|
|
+#include <QDebug>
|
|
|
+#include <QTime>
|
|
|
+
|
|
|
+Downloader::Downloader(QObject *parent) : QObject(parent), busy_(false), m_WebCtrl(this)
|
|
|
+{
|
|
|
+ qRegisterMetaType<Downloader::Status>();
|
|
|
+ connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)), this, SLOT(onDownloadFinished(QNetworkReply*)));
|
|
|
+}
|
|
|
+
|
|
|
+Downloader::~Downloader() {
|
|
|
+}
|
|
|
+
|
|
|
+QUrl Downloader::getUrl() const
|
|
|
+{
|
|
|
+ return url_;
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::setUrl(const QUrl &_url)
|
|
|
+{
|
|
|
+ url_ = _url;
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::waitForDownloaded() const
|
|
|
+{
|
|
|
+ if (!busy_)
|
|
|
+ return;
|
|
|
+
|
|
|
+ QEventLoop loop;
|
|
|
+ connect(this, &Downloader::downloadFinished, &loop, &QEventLoop::quit);
|
|
|
+ loop.exec();
|
|
|
+}
|
|
|
+
|
|
|
+bool Downloader::isStarted() const
|
|
|
+{
|
|
|
+ return busy_;
|
|
|
+}
|
|
|
+
|
|
|
+double Downloader::getPercent() const
|
|
|
+{
|
|
|
+ return bytes_total_ > 0.01 ? double(bytes_downloaded_) * 100.0 / double(bytes_total_) : 0;
|
|
|
+}
|
|
|
+
|
|
|
+quint64 Downloader::getBytesTotal() const
|
|
|
+{
|
|
|
+ return bytes_total_;
|
|
|
+}
|
|
|
+
|
|
|
+quint64 Downloader::getBytesDownloaded() const
|
|
|
+{
|
|
|
+ return bytes_downloaded_;
|
|
|
+}
|
|
|
+
|
|
|
+quint64 Downloader::getElapsedTime() const
|
|
|
+{
|
|
|
+ quint64 delta_size = getBytesTotal() - getBytesDownloaded();
|
|
|
+ quint64 avg_speed = qMax(quint64(1), getAverageSpeed());
|
|
|
+
|
|
|
+ while (delta_size > 1024 && avg_speed > 1024) { // Making precision smaller to get smoother dynamics
|
|
|
+ delta_size /= 1024;
|
|
|
+ avg_speed /= 1024;
|
|
|
+ }
|
|
|
+
|
|
|
+ return delta_size / avg_speed;
|
|
|
+}
|
|
|
+
|
|
|
+quint64 Downloader::getCurrentSpeed() const
|
|
|
+{
|
|
|
+ return download_speed_;
|
|
|
+}
|
|
|
+
|
|
|
+quint64 Downloader::getAverageSpeed() const
|
|
|
+{
|
|
|
+ return average_speed_;
|
|
|
+}
|
|
|
+
|
|
|
+Downloader::Status Downloader::getDownloadStatus() const
|
|
|
+{
|
|
|
+ return {isStarted(), getPercent(), getBytesTotal(), getBytesDownloaded(), getCurrentSpeed(), getAverageSpeed(), getElapsedTime()};
|
|
|
+}
|
|
|
+
|
|
|
+QString Downloader::getSpeedFormatted(quint64 speed_bytes_per_sec)
|
|
|
+{
|
|
|
+ float speed = speed_bytes_per_sec;
|
|
|
+
|
|
|
+ QString unit;
|
|
|
+ if (speed < 1024) {
|
|
|
+ unit = "bytes/sec";
|
|
|
+ } else if (speed < 1024*1024) {
|
|
|
+ speed /= 1024;
|
|
|
+ unit = "kB/s";
|
|
|
+ } else {
|
|
|
+ speed /= 1024*1024;
|
|
|
+ unit = "MB/s";
|
|
|
+ }
|
|
|
+ return QString::number(speed, 'f', 1) + " " + unit;
|
|
|
+}
|
|
|
+
|
|
|
+QString Downloader::getSizeFormatted(quint64 bytes)
|
|
|
+{
|
|
|
+ float size = bytes;
|
|
|
+ QString unit;
|
|
|
+ if (size < 1024) {
|
|
|
+ unit = "байт";
|
|
|
+ } else if (size < 1024 * 1024) {
|
|
|
+ size /= 1024;
|
|
|
+ unit = "кб";
|
|
|
+ } else if (size < 1024 * 1024 * 1024){
|
|
|
+ size /= 1024*1024;
|
|
|
+ unit = "мб";
|
|
|
+ } else {
|
|
|
+ size /= 1024 * 1024 * 1024;
|
|
|
+ unit = "гб";
|
|
|
+ }
|
|
|
+ return QString::number(size, 'f', 1) + " " + unit;
|
|
|
+}
|
|
|
+
|
|
|
+QString Downloader::getElapsedTimeFormatted(quint64 elapsed_time_secs)
|
|
|
+{
|
|
|
+ qint64 secs = elapsed_time_secs;
|
|
|
+ qint64 mins = 0;
|
|
|
+ qint64 hours = 0;
|
|
|
+ qint64 days = 0;
|
|
|
+
|
|
|
+ if (secs > 60) {
|
|
|
+ mins = secs / 60;
|
|
|
+ secs %= 60;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mins > 60) {
|
|
|
+ hours = mins / 60;
|
|
|
+ mins %= 60;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hours > 24) {
|
|
|
+ days = hours / 24;
|
|
|
+ hours %= 24;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (days > 0)
|
|
|
+ return " очень много (низкая скорость)";
|
|
|
+
|
|
|
+ QString result = "";
|
|
|
+
|
|
|
+ if (hours > 0) {
|
|
|
+ result += QString::number(hours);
|
|
|
+ if (hours % 10 == 1 && hours / 10 != 1)
|
|
|
+ result += " час ";
|
|
|
+ else if (hours % 10 > 1 && hours % 10 < 5 && hours / 10 != 1)
|
|
|
+ result += " часа ";
|
|
|
+ else
|
|
|
+ result += " часов ";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mins > 0) {
|
|
|
+ result += QString::number(mins);
|
|
|
+ if (mins % 10 == 1 && mins / 10 != 1)
|
|
|
+ result += " минута ";
|
|
|
+ else if (mins % 10 > 1 && mins % 10 < 5 && mins / 10 != 1)
|
|
|
+ result += " минуты ";
|
|
|
+ else
|
|
|
+ result += " минут ";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (secs > 0 && hours == 0) {
|
|
|
+ result += QString::number(secs);
|
|
|
+ if (secs % 10 == 1 && secs / 10 != 1)
|
|
|
+ result += " секунда ";
|
|
|
+ else if (secs % 10 > 1 && secs % 10 < 5 && secs / 10 != 1)
|
|
|
+ result += " секунды ";
|
|
|
+ else
|
|
|
+ result += " секунд ";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (result == "")
|
|
|
+ result = "совсем чуть-чуть";
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::start()
|
|
|
+{
|
|
|
+ if (busy_) {
|
|
|
+ qDebug() << "Cannot download " << url_ << ", downloader is busy!";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ qDebug() << "Starting download " << url_;
|
|
|
+
|
|
|
+ last_tick_time_.restart();
|
|
|
+ bytes_downloaded_ = 0;
|
|
|
+ bytes_total_ = 0;
|
|
|
+ download_speed_ = 0;
|
|
|
+ bytes_downloaded_before_tick_ = 0;
|
|
|
+
|
|
|
+ busy_ = true;
|
|
|
+ QNetworkRequest request(url_);
|
|
|
+ m_CurrentReply = m_WebCtrl.get(request);
|
|
|
+ m_CurrentReply->setReadBufferSize(download_speed_limit);
|
|
|
+ connect(m_CurrentReply, &QNetworkReply::readyRead, this, &Downloader::onReadyRead);
|
|
|
+ connect(m_CurrentReply, &QNetworkReply::downloadProgress, this, &Downloader::onDownloadProgressChanged);
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::updateDownloadSpeedLimit(int bytes_per_sec)
|
|
|
+{
|
|
|
+ download_speed_limit = bytes_per_sec;
|
|
|
+ if (m_CurrentReply)
|
|
|
+ m_CurrentReply->setReadBufferSize(bytes_per_sec);
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::onDownloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal)
|
|
|
+{
|
|
|
+ bytes_downloaded_ = bytesReceived;
|
|
|
+ bytes_total_ = bytesTotal;
|
|
|
+
|
|
|
+ if (last_tick_time_.elapsed() >= 100) {
|
|
|
+ download_speed_ = (bytes_downloaded_ - bytes_downloaded_before_tick_) * 1000.0 / (last_tick_time_.elapsed());
|
|
|
+
|
|
|
+ average_speed_ = (average_speed_ * update_ticks_counter_ + download_speed_) / (update_ticks_counter_ + 1);
|
|
|
+ ++update_ticks_counter_;
|
|
|
+
|
|
|
+ last_tick_time_.restart();
|
|
|
+ bytes_downloaded_before_tick_ = bytes_downloaded_;
|
|
|
+ emit progressChanged(this, getDownloadStatus());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::stop()
|
|
|
+{
|
|
|
+ if (m_CurrentReply) {
|
|
|
+ m_CurrentReply->abort();
|
|
|
+ }
|
|
|
+ busy_ = false;
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::onDownloadFinished(QNetworkReply*) {
|
|
|
+ if (m_CurrentReply)
|
|
|
+ m_CurrentReply->deleteLater();
|
|
|
+
|
|
|
+ download_speed_ = 0;
|
|
|
+ busy_ = false;
|
|
|
+
|
|
|
+ emit downloadFinished(this);
|
|
|
+}
|
|
|
+
|
|
|
+void Downloader::onReadyRead()
|
|
|
+{
|
|
|
+ QByteArray readdata = m_CurrentReply->readAll();
|
|
|
+ if (targetFile && targetFile->isWritable())
|
|
|
+ targetFile->write(readdata);
|
|
|
+ if (targetBytearray)
|
|
|
+ targetBytearray->append(readdata);
|
|
|
+}
|