#include "downloader.h" #include #include #include #include Downloader::Downloader(QObject *parent) : QObject(parent), busy_(false), m_WebCtrl(this) { qRegisterMetaType(); 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 double(bytes_downloaded_) * 100.0 / double(bytes_total_); } 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() >= 300) { 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); }