Add filesize units to download progress

This adds the currently downloaded size and the total enclosure size to
the entry delegate.
This commit is contained in:
Bart De Vries 2021-06-24 17:12:07 +02:00
parent d7debaaf30
commit bcafb26c8c
6 changed files with 120 additions and 60 deletions

View File

@ -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<qint64>(kjob->totalAmount(unit));
qint64 currentSize = static_cast<qint64>(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<double>(m_downloadSize) / static_cast<double>(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<double>(m_sizeOnDisk) / static_cast<double>(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);

View File

@ -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;
};

View File

@ -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);

View File

@ -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);

View File

@ -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: [

View File

@ -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 {