diff --git a/src/enclosure.cpp b/src/enclosure.cpp index 3d71c0af..0ff321f3 100644 --- a/src/enclosure.cpp +++ b/src/enclosure.cpp @@ -28,19 +28,6 @@ Enclosure::Enclosure(Entry *entry) { connect(this, &Enclosure::statusChanged, &DownloadModel::instance(), &DownloadModel::monitorDownloadStatus); connect(this, &Enclosure::downloadError, &ErrorLogModel::instance(), &ErrorLogModel::monitorErrorMessages); - connect(&Fetcher::instance(), &Fetcher::downloadFileSizeUpdated, this, [this](QString url, int fileSize, int resumedAt) { - if ((url == m_url) && ((m_size != fileSize) && (m_size != fileSize + resumedAt)) && (fileSize > 1000)) { - // Sometimes, when resuming a download, the complete file size is - // reported. Other times only the remaining part. - // Sometimes the value is rubbish (e.g. 2) - // We assume that the value when starting a new download is correct. - if (fileSize < resumedAt) { - fileSize += resumedAt; - } - qDebug() << "Correct filesize for enclosure" << url << "from" << m_size << "to" << fileSize; - setSize(fileSize); - } - }); QSqlQuery query; query.prepare(QStringLiteral("SELECT * FROM Enclosures WHERE id=:id")); @@ -60,27 +47,7 @@ Enclosure::Enclosure(Entry *entry) m_status = dbToStatus(query.value(QStringLiteral("downloaded")).toInt()); m_playposition_dbsave = m_playposition; - // In principle the database contains this status, we check anyway in case - // something changed on disk - QFile file(path()); - if (file.exists()) { - if (file.size() == m_size && file.size() > 0) { - // file is on disk and has correct size, write to database if it - // wasn't already registered so - // this should, in principle, never happen unless the db was deleted - setStatus(Downloaded); - } else if (file.size() > 0) { - // file was downloaded, but there is a size mismatch - // set to PartiallyDownloaded such that download can be resumed - setStatus(PartiallyDownloaded); - } else { - // file is empty - setStatus(Downloadable); - } - } else { - // file does not exist - setStatus(Downloadable); - } + checkSizeOnDisk(); } int Enclosure::statusToDb(Enclosure::Status status) @@ -117,9 +84,11 @@ Enclosure::Status Enclosure::dbToStatus(int value) void Enclosure::download() { + checkSizeOnDisk(); EnclosureDownloadJob *downloadJob = new EnclosureDownloadJob(m_url, path(), m_entry->title()); downloadJob->start(); + qint64 resumedAt = m_sizeOnDisk; m_downloadProgress = 0; Q_EMIT downloadProgressChanged(); @@ -127,6 +96,7 @@ void Enclosure::download() m_entry->feed()->setErrorString(QString()); connect(downloadJob, &KJob::result, this, [this, downloadJob]() { + checkSizeOnDisk(); if (downloadJob->error() == 0) { processDownloadedFile(); } else { @@ -148,6 +118,7 @@ void Enclosure::download() connect(this, &Enclosure::cancelDownload, this, [this, downloadJob]() { downloadJob->doKill(); + checkSizeOnDisk(); QFile file(path()); if (file.exists() && file.size() > 0) { setStatus(PartiallyDownloaded); @@ -157,9 +128,24 @@ void Enclosure::download() disconnect(this, &Enclosure::cancelDownload, this, nullptr); }); - connect(downloadJob, &KJob::percentChanged, this, [=](KJob *, unsigned long percent) { - m_downloadProgress = percent; + connect(downloadJob, &KJob::processedAmountChanged, this, [=](KJob *kjob, KJob::Unit unit, qulonglong amount) { + Q_ASSERT(unit == KJob::Unit::Bytes); + + qint64 totalSize = static_cast(kjob->totalAmount(unit)); + qint64 currentSize = static_cast(amount); + + if ((totalSize > 0) && (m_size != totalSize + resumedAt)) { + qCDebug(kastsEnclosure) << "Correct filesize for enclosure" << m_entry->title() << "from" << m_size << "to" << totalSize + resumedAt; + setSize(totalSize + resumedAt); + } + + m_downloadSize = currentSize + resumedAt; + m_downloadProgress = static_cast(m_downloadSize) / static_cast(m_size); Q_EMIT downloadProgressChanged(); + + qCDebug(kastsEnclosure) << "m_downloadSize" << m_downloadSize; + qCDebug(kastsEnclosure) << "m_downloadProgress" << m_downloadProgress; + qCDebug(kastsEnclosure) << "m_size" << m_size; }); setStatus(Downloading); @@ -171,8 +157,8 @@ void Enclosure::processDownloadedFile() // First check if file size is larger than 0; otherwise something unexpected // must have happened - QFile file(path()); - if (file.size() == 0) { + checkSizeOnDisk(); + if (m_sizeOnDisk == 0) { deleteFile(); return; } @@ -180,15 +166,16 @@ void Enclosure::processDownloadedFile() // Check if reported filesize in rss feed corresponds to real file size // if not, correct the filesize in the database // otherwise the file will get deleted because of mismatch in signature - if (file.size() != m_size) { - qCDebug(kastsEnclosure) << "enclosure file size mismatch" << m_entry->title() << "from" << m_size << "to" << file.size(); - setSize(file.size()); + if (m_sizeOnDisk != size()) { + qCDebug(kastsEnclosure) << "Correcting enclosure file size mismatch" << m_entry->title() << "from" << size() << "to" << m_sizeOnDisk; + setSize(m_sizeOnDisk); + setStatus(Downloaded); } - setStatus(Downloaded); // Unset "new" status of item - if (m_entry->getNew()) + if (m_entry->getNew()) { m_entry->setNew(false); + } } void Enclosure::deleteFile() @@ -198,11 +185,16 @@ void Enclosure::deleteFile() qCDebug(kastsEnclosure) << "Track is still playing; let's unload it before deleting"; AudioManager::instance().setEntry(nullptr); } + // First check if file still exists; you never know what has happened - if (QFile(path()).exists()) + if (QFile(path()).exists()) { QFile(path()).remove(); + } + // If file disappeared unexpectedly, then still change status to downloadable setStatus(Downloadable); + m_sizeOnDisk = 0; + Q_EMIT sizeOnDiskChanged(); } QString Enclosure::path() const @@ -225,11 +217,16 @@ qint64 Enclosure::duration() const return m_duration; } -int Enclosure::size() const +qint64 Enclosure::size() const { return m_size; } +qint64 Enclosure::sizeOnDisk() const +{ + return m_sizeOnDisk; +} + void Enclosure::setStatus(Enclosure::Status status) { if (m_status != status) { @@ -286,7 +283,7 @@ void Enclosure::setDuration(const qint64 &duration) } } -void Enclosure::setSize(const int &size) +void Enclosure::setSize(const qint64 &size) { if (m_size != size) { m_size = size; @@ -303,11 +300,53 @@ void Enclosure::setSize(const int &size) } } +void Enclosure::checkSizeOnDisk() +{ + // In principle the database contains this status, we check anyway in case + // something changed on disk + QFile file(path()); + if (file.exists()) { + if (file.size() == m_size && file.size() > 0) { + // file is on disk and has correct size, write to database if it + // wasn't already registered so + // this should, in principle, never happen unless the db was deleted + setStatus(Downloaded); + } else if (file.size() > 0) { + // file was downloaded, but there is a size mismatch + // set to PartiallyDownloaded such that download can be resumed + setStatus(PartiallyDownloaded); + } else { + // file is empty + setStatus(Downloadable); + } + if (file.size() != m_sizeOnDisk) { + m_sizeOnDisk = file.size(); + m_downloadSize = m_sizeOnDisk; + m_downloadProgress = (m_size == 0) ? 0.0 : static_cast(m_sizeOnDisk) / static_cast(m_size); + Q_EMIT sizeOnDiskChanged(); + } + } else { + // file does not exist + setStatus(Downloadable); + if (m_sizeOnDisk != 0) { + m_sizeOnDisk = 0; + m_downloadSize = 0; + m_downloadProgress = 0.0; + Q_EMIT sizeOnDiskChanged(); + } + } +} + QString Enclosure::formattedSize() const { return m_kformat.formatByteSize(m_size); } +QString Enclosure::formattedDownloadSize() const +{ + return m_kformat.formatByteSize(m_downloadSize); +} + QString Enclosure::formattedDuration() const { return m_kformat.formatDuration(m_duration * 1000); diff --git a/src/enclosure.h b/src/enclosure.h index f8dac263..b6a98850 100644 --- a/src/enclosure.h +++ b/src/enclosure.h @@ -21,13 +21,15 @@ class Enclosure : public QObject { Q_OBJECT - Q_PROPERTY(int size READ size WRITE setSize NOTIFY sizeChanged) + Q_PROPERTY(qint64 size READ size WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(QString formattedSize READ formattedSize NOTIFY sizeChanged) + Q_PROPERTY(qint64 sizeOnDisk READ sizeOnDisk NOTIFY sizeOnDiskChanged) Q_PROPERTY(QString title MEMBER m_title CONSTANT) Q_PROPERTY(QString type MEMBER m_type CONSTANT) Q_PROPERTY(QString url MEMBER m_url CONSTANT) Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged) Q_PROPERTY(double downloadProgress MEMBER m_downloadProgress NOTIFY downloadProgressChanged) + Q_PROPERTY(QString formattedDownloadSize READ formattedDownloadSize NOTIFY downloadProgressChanged) Q_PROPERTY(QString path READ path CONSTANT) Q_PROPERTY(qint64 playPosition READ playPosition WRITE setPlayPosition NOTIFY playPositionChanged) Q_PROPERTY(QString formattedPlayPosition READ formattedPlayPosition NOTIFY playPositionChanged); @@ -56,15 +58,18 @@ public: Status status() const; qint64 playPosition() const; qint64 duration() const; - int size() const; + qint64 size() const; + qint64 sizeOnDisk() const; QString formattedSize() const; QString formattedDuration() const; QString formattedPlayPosition() const; + QString formattedDownloadSize() const; void setStatus(Status status); void setPlayPosition(const qint64 &position); void setDuration(const qint64 &duration); - void setSize(const int &size); + void setSize(const qint64 &size); + void checkSizeOnDisk(); Q_SIGNALS: void statusChanged(Entry *entry, Status status); @@ -73,6 +78,7 @@ Q_SIGNALS: void playPositionChanged(); void durationChanged(); void sizeChanged(); + void sizeOnDiskChanged(); void downloadError(const Error::Type type, const QString &url, const QString &id, const int errorId, const QString &errorString); private: @@ -80,13 +86,15 @@ private: Entry *m_entry; qint64 m_duration; - int m_size; + qint64 m_size = 0; + qint64 m_sizeOnDisk; QString m_title; QString m_type; QString m_url; qint64 m_playposition; qint64 m_playposition_dbsave; double m_downloadProgress = 0; + qint64 m_downloadSize = 0; Status m_status; KFormat m_kformat; }; diff --git a/src/fetcher.cpp b/src/fetcher.cpp index dbd6325e..583bbf35 100644 --- a/src/fetcher.cpp +++ b/src/fetcher.cpp @@ -376,15 +376,16 @@ QNetworkReply *Fetcher::download(const QString &url, const QString &filePath) co file->open(QIODevice::WriteOnly); } + /* QNetworkReply *headerReply = head(request); connect(headerReply, &QNetworkReply::finished, this, [=]() { if (headerReply->isOpen()) { int fileSize = headerReply->header(QNetworkRequest::ContentLengthHeader).toInt(); qCDebug(kastsFetcher) << "Reported download size" << fileSize; - Q_EMIT downloadFileSizeUpdated(url, fileSize, resumedAt); } headerReply->deleteLater(); }); + */ QNetworkReply *reply = get(request); diff --git a/src/fetcher.h b/src/fetcher.h index 2a661e1b..2f3eff24 100644 --- a/src/fetcher.h +++ b/src/fetcher.h @@ -54,7 +54,6 @@ Q_SIGNALS: void error(Error::Type type, const QString &url, const QString &id, const int errorId, const QString &errorString); void entryAdded(const QString &feedurl, const QString &id); void downloadFinished(QString url) const; - void downloadFileSizeUpdated(QString url, int fileSize, int resumedAt) const; void updateProgressChanged(int progress); void updateTotalChanged(int nrOfFeeds); diff --git a/src/qml/EntryPage.qml b/src/qml/EntryPage.qml index 02c272d5..0e4e58d6 100644 --- a/src/qml/EntryPage.qml +++ b/src/qml/EntryPage.qml @@ -121,7 +121,7 @@ Kirigami.ScrollablePage { text: i18n("Delete Download") icon.name: "delete" onTriggered: entry.enclosure.deleteFile(); - visible: entry.enclosure && (entry.enclosure.status === Enclosure.Downloaded || entry.enclosure.status === Enclosure.PartiallyDownloaded) && entry.queueStatus + visible: entry.enclosure && ((entry.enclosure.status === Enclosure.Downloaded && entry.queueStatus) || entry.enclosure.status === Enclosure.PartiallyDownloaded) } contextualActions: [ diff --git a/src/qml/GenericEntryDelegate.qml b/src/qml/GenericEntryDelegate.qml index 1f2918b4..e868ad39 100644 --- a/src/qml/GenericEntryDelegate.qml +++ b/src/qml/GenericEntryDelegate.qml @@ -104,7 +104,7 @@ Kirigami.SwipeListItem { font.weight: Font.Normal } Loader { - sourceComponent: entry.enclosure && entry.enclosure.status === Enclosure.Downloading ? downloadProgress : ( entry.enclosure && entry.enclosure.playPosition > 0 ? playProgress : subtitle) + sourceComponent: entry.enclosure && (entry.enclosure.status === Enclosure.Downloading || (isDownloads && entry.enclosure.status === Enclosure.PartiallyDownloaded)) ? downloadProgress : ( entry.enclosure && entry.enclosure.playPosition > 0 ? playProgress : subtitle) Layout.fillWidth: true } Component { @@ -120,12 +120,25 @@ Kirigami.SwipeListItem { } Component { id: downloadProgress - Controls.ProgressBar { - from: 0 - to: 100 - value: entry.enclosure.downloadProgress - visible: entry.enclosure && entry.enclosure.status === Enclosure.Downloading - Layout.fillWidth: true + RowLayout { + Controls.Label { + text: entry.enclosure.formattedDownloadSize + elide: Text.ElideRight + font: Kirigami.Theme.smallFont + opacity: 0.7 + } + Controls.ProgressBar { + from: 0 + to: 1 + value: entry.enclosure.downloadProgress + Layout.fillWidth: true + } + Controls.Label { + text: entry.enclosure.formattedSize + elide: Text.ElideRight + font: Kirigami.Theme.smallFont + opacity: 0.7 + } } } Component {