mirror of https://github.com/KDE/kasts.git
252 lines
9.1 KiB
C++
252 lines
9.1 KiB
C++
/**
|
|
* SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
|
|
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
*/
|
|
|
|
#include "enclosure.h"
|
|
|
|
#include <QFile>
|
|
#include <QNetworkReply>
|
|
#include <QSqlQuery>
|
|
|
|
#include "database.h"
|
|
#include "datamanager.h"
|
|
#include "downloadprogressmodel.h"
|
|
#include "enclosuredownloadjob.h"
|
|
#include "entry.h"
|
|
#include "errorlogmodel.h"
|
|
#include "fetcher.h"
|
|
|
|
Enclosure::Enclosure(Entry *entry)
|
|
: QObject(entry)
|
|
, m_entry(entry)
|
|
{
|
|
connect(this, &Enclosure::statusChanged, &DownloadProgressModel::instance(), &DownloadProgressModel::monitorDownloadProgress);
|
|
connect(this, &Enclosure::downloadError, &ErrorLogModel::instance(), &ErrorLogModel::monitorErrorMessages);
|
|
|
|
QSqlQuery query;
|
|
query.prepare(QStringLiteral("SELECT * FROM Enclosures WHERE id=:id"));
|
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
|
Database::instance().execute(query);
|
|
|
|
if (!query.next()) {
|
|
return;
|
|
}
|
|
|
|
m_duration = query.value(QStringLiteral("duration")).toInt();
|
|
m_size = query.value(QStringLiteral("size")).toInt();
|
|
m_title = query.value(QStringLiteral("title")).toString();
|
|
m_type = query.value(QStringLiteral("type")).toString();
|
|
m_url = query.value(QStringLiteral("url")).toString();
|
|
m_playposition = query.value(QStringLiteral("playposition")).toLongLong();
|
|
m_status = query.value(QStringLiteral("downloaded")).toBool() ? Downloaded : Downloadable;
|
|
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) {
|
|
if (m_status == Downloadable) {
|
|
// file is on disk, but was not expected, write to database
|
|
// this should never happen
|
|
m_status = Downloaded;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET downloaded=:downloaded WHERE id=:id;"));
|
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
|
query.bindValue(QStringLiteral(":downloaded"), true);
|
|
Database::instance().execute(query);
|
|
}
|
|
} else {
|
|
if (m_status == Downloaded) {
|
|
// file was downloaded, but there is a size mismatch or file is empty
|
|
// delete file and update status in database
|
|
file.remove();
|
|
m_status = Downloadable;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET downloaded=:downloaded WHERE id=:id;"));
|
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
|
query.bindValue(QStringLiteral(":downloaded"), false);
|
|
Database::instance().execute(query);
|
|
}
|
|
}
|
|
} else {
|
|
if (m_status == Downloaded) {
|
|
// file was supposed to be on disk, but isn't there
|
|
// update status and write to the database
|
|
file.remove();
|
|
m_status = Downloadable;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET downloaded=:downloaded WHERE id=:id;"));
|
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
|
query.bindValue(QStringLiteral(":downloaded"), false);
|
|
Database::instance().execute(query);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Enclosure::download()
|
|
{
|
|
EnclosureDownloadJob *downloadJob = new EnclosureDownloadJob(m_url, path(), m_entry->title());
|
|
downloadJob->start();
|
|
|
|
m_downloadProgress = 0;
|
|
Q_EMIT downloadProgressChanged();
|
|
|
|
m_entry->feed()->setErrorId(0);
|
|
m_entry->feed()->setErrorString(QString());
|
|
|
|
connect(downloadJob, &KJob::result, this, [this, downloadJob]() {
|
|
if (downloadJob->error() == 0) {
|
|
processDownloadedFile();
|
|
} else {
|
|
m_status = Downloadable;
|
|
if (downloadJob->error() != QNetworkReply::OperationCanceledError) {
|
|
m_entry->feed()->setErrorId(downloadJob->error());
|
|
m_entry->feed()->setErrorString(downloadJob->errorString());
|
|
Q_EMIT downloadError(m_entry->feed()->url(), m_entry->id(), downloadJob->error(), downloadJob->errorString());
|
|
}
|
|
}
|
|
disconnect(this, &Enclosure::cancelDownload, this, nullptr);
|
|
Q_EMIT statusChanged(m_entry, m_status);
|
|
});
|
|
|
|
connect(this, &Enclosure::cancelDownload, this, [this, downloadJob]() {
|
|
downloadJob->doKill();
|
|
m_status = Downloadable;
|
|
Q_EMIT statusChanged(m_entry, m_status);
|
|
Q_EMIT DataManager::instance().downloadCountChanged(m_entry->feed()->url());
|
|
disconnect(this, &Enclosure::cancelDownload, this, nullptr);
|
|
});
|
|
|
|
connect(downloadJob, &KJob::percentChanged, this, [=](KJob *, unsigned long percent) {
|
|
m_downloadProgress = percent;
|
|
Q_EMIT downloadProgressChanged();
|
|
});
|
|
|
|
m_status = Downloading;
|
|
Q_EMIT statusChanged(m_entry, m_status);
|
|
}
|
|
|
|
void Enclosure::processDownloadedFile()
|
|
{
|
|
// This will be run if the enclosure has been downloaded successfully
|
|
|
|
// First check if file size is larger than 0; otherwise something unexpected
|
|
// must have happened
|
|
QFile file(path());
|
|
if (file.size() == 0) {
|
|
deleteFile();
|
|
return;
|
|
}
|
|
|
|
// 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) {
|
|
qDebug() << "enclosure file size mismatch" << m_entry->title();
|
|
setSize(file.size());
|
|
}
|
|
|
|
m_status = Downloaded;
|
|
QSqlQuery query;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET downloaded=:downloaded WHERE id=:id;"));
|
|
query.bindValue(QStringLiteral(":id"), m_entry->id());
|
|
query.bindValue(QStringLiteral(":downloaded"), true);
|
|
Database::instance().execute(query);
|
|
// Unset "new" status of item
|
|
if (m_entry->getNew())
|
|
m_entry->setNew(false);
|
|
|
|
Q_EMIT DataManager::instance().downloadCountChanged(m_entry->feed()->url());
|
|
}
|
|
|
|
void Enclosure::deleteFile()
|
|
{
|
|
// qDebug() << "Trying to delete enclosure file" << path();
|
|
// First check if file still exists; you never know what has happened
|
|
if (QFile(path()).exists())
|
|
QFile(path()).remove();
|
|
// If file disappeared unexpectedly, then still change status to downloadable
|
|
m_status = Downloadable;
|
|
QSqlQuery query;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET downloaded=:downloaded WHERE id=:id;"));
|
|
query.bindValue(QStringLiteral(":id"), m_entry->id());
|
|
query.bindValue(QStringLiteral(":downloaded"), false);
|
|
Database::instance().execute(query);
|
|
Q_EMIT statusChanged(m_entry, m_status);
|
|
Q_EMIT DataManager::instance().downloadCountChanged(m_entry->feed()->url());
|
|
}
|
|
|
|
QString Enclosure::path() const
|
|
{
|
|
return Fetcher::instance().enclosurePath(m_url);
|
|
}
|
|
|
|
Enclosure::Status Enclosure::status() const
|
|
{
|
|
return m_status;
|
|
}
|
|
|
|
qint64 Enclosure::playPosition() const
|
|
{
|
|
return m_playposition;
|
|
}
|
|
|
|
qint64 Enclosure::duration() const
|
|
{
|
|
return m_duration;
|
|
}
|
|
|
|
int Enclosure::size() const
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
void Enclosure::setPlayPosition(const qint64 &position)
|
|
{
|
|
m_playposition = position;
|
|
// qDebug() << "save playPosition" << position << m_entry->title();
|
|
Q_EMIT playPositionChanged();
|
|
|
|
// let's only save the play position to the database every 15 seconds
|
|
if ((abs(m_playposition - m_playposition_dbsave) > 15000) || position == 0) {
|
|
// qDebug() << "save playPosition to database" << position << m_entry->title();
|
|
QSqlQuery query;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET playposition=:playposition WHERE id=:id AND feed=:feed"));
|
|
query.bindValue(QStringLiteral(":id"), m_entry->id());
|
|
query.bindValue(QStringLiteral(":feed"), m_entry->feed()->url());
|
|
query.bindValue(QStringLiteral(":playposition"), m_playposition);
|
|
Database::instance().execute(query);
|
|
m_playposition_dbsave = m_playposition;
|
|
}
|
|
}
|
|
|
|
void Enclosure::setDuration(const qint64 &duration)
|
|
{
|
|
m_duration = duration;
|
|
Q_EMIT durationChanged();
|
|
|
|
// also save to database
|
|
// qDebug() << "updating entry duration" << duration << m_entry->title();
|
|
QSqlQuery query;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET duration=:duration WHERE id=:id AND feed=:feed"));
|
|
query.bindValue(QStringLiteral(":id"), m_entry->id());
|
|
query.bindValue(QStringLiteral(":feed"), m_entry->feed()->url());
|
|
query.bindValue(QStringLiteral(":duration"), m_duration);
|
|
Database::instance().execute(query);
|
|
}
|
|
|
|
void Enclosure::setSize(const int &size)
|
|
{
|
|
m_size = size;
|
|
Q_EMIT sizeChanged();
|
|
|
|
// also save to database
|
|
QSqlQuery query;
|
|
query.prepare(QStringLiteral("UPDATE Enclosures SET size=:size WHERE id=:id AND feed=:feed"));
|
|
query.bindValue(QStringLiteral(":id"), m_entry->id());
|
|
query.bindValue(QStringLiteral(":feed"), m_entry->feed()->url());
|
|
query.bindValue(QStringLiteral(":size"), m_size);
|
|
Database::instance().execute(query);
|
|
}
|