Clementine-audio-player-Mac.../src/internet/seafile/seafileservice.cpp

687 lines
21 KiB
C++
Raw Permalink Normal View History

/* This file is part of Clementine.
Copyright 2014, Chocobozzz <djidane14ff@hotmail.fr>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, David Sansome <me@davidsansome.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
2014-06-19 15:33:45 +02:00
#include "seafileservice.h"
2020-09-18 16:15:19 +02:00
#include <QJsonArray>
2015-04-15 18:26:09 +02:00
#include <QJsonDocument>
#include <QJsonObject>
2020-09-18 16:15:19 +02:00
#include <QTimer>
#include <QUrlQuery>
#include <cmath>
2014-06-03 14:33:07 +02:00
#include "core/application.h"
#include "core/player.h"
2020-09-18 16:15:19 +02:00
#include "core/taskmanager.h"
2014-06-03 14:33:07 +02:00
#include "core/waitforsignal.h"
2020-09-18 16:15:19 +02:00
#include "internet/core/oauthenticator.h"
#include "internet/seafile/seafileurlhandler.h"
2014-06-03 14:33:07 +02:00
#include "library/librarybackend.h"
#include "ui/iconloader.h"
2014-06-03 14:33:07 +02:00
const char* SeafileService::kServiceName = "Seafile";
const char* SeafileService::kSettingsGroup = "Seafile";
namespace {
2014-06-04 17:58:28 +02:00
static const char* kAuthTokenUrl = "/api2/auth-token/";
2014-06-03 14:33:07 +02:00
2014-06-04 17:58:28 +02:00
static const char* kFolderItemsUrl = "/api2/repos/%1/dir/";
static const char* kListReposUrl = "/api2/repos/";
2014-06-03 14:33:07 +02:00
static const char* kFileUrl = "/api2/repos/%1/file/";
2014-06-04 17:58:28 +02:00
static const char* kFileContentUrl = "/api2/repos/%1/file/detail/";
static const int kMaxTries = 10;
} // namespace
2014-06-03 14:33:07 +02:00
SeafileService::SeafileService(Application* app, InternetModel* parent)
2014-06-04 17:58:28 +02:00
: CloudFileService(app, parent, kServiceName, kSettingsGroup,
IconLoader::Load("seafile", IconLoader::Provider),
SettingsDialog::Page_Seafile),
indexing_task_id_(-1),
indexing_task_max_(0),
indexing_task_progress_(0),
changing_libary_(false) {
2014-06-03 14:33:07 +02:00
QSettings s;
s.beginGroup(kSettingsGroup);
access_token_ = s.value("access_token").toString();
server_ = s.value("server").toString();
QByteArray tree_bytes = s.value("tree").toByteArray();
2014-06-04 17:58:28 +02:00
if (!tree_bytes.isEmpty()) {
2014-06-03 14:33:07 +02:00
QDataStream stream(&tree_bytes, QIODevice::ReadOnly);
stream >> tree_;
}
app->player()->RegisterUrlHandler(new SeafileUrlHandler(this, this));
2014-06-04 17:58:28 +02:00
connect(&tree_, SIGNAL(ToAdd(QString, QString, SeafileTree::Entry)), this,
SLOT(AddEntry(QString, QString, SeafileTree::Entry)));
connect(&tree_, SIGNAL(ToDelete(QString, QString, SeafileTree::Entry)), this,
SLOT(DeleteEntry(QString, QString, SeafileTree::Entry)));
connect(&tree_, SIGNAL(ToUpdate(QString, QString, SeafileTree::Entry)), this,
SLOT(UpdateEntry(QString, QString, SeafileTree::Entry)));
2014-06-03 14:33:07 +02:00
}
bool SeafileService::has_credentials() const {
return !access_token_.isEmpty();
}
void SeafileService::AddAuthorizationHeader(QNetworkRequest* request) const {
2014-06-04 17:58:28 +02:00
request->setRawHeader("Authorization",
2015-04-15 18:26:09 +02:00
QString("Token %1").arg(access_token_).toLatin1());
2014-06-03 14:33:07 +02:00
}
void SeafileService::ForgetCredentials() {
QSettings s;
s.beginGroup(kSettingsGroup);
s.remove("access_token");
s.remove("tree");
access_token_.clear();
tree_.Clear();
server_.clear();
}
2014-06-04 17:58:28 +02:00
bool SeafileService::GetToken(const QString& mail, const QString& password,
const QString& server) {
QUrl url(server + kAuthTokenUrl);
2015-04-15 18:26:09 +02:00
QUrlQuery url_query;
url_query.addQueryItem("username", mail);
url_query.addQueryItem("password", password);
2014-06-03 14:33:07 +02:00
QNetworkRequest request(url);
AddAuthorizationHeader(&request);
2020-09-18 16:15:19 +02:00
QNetworkReply* reply =
network_->post(request, url_query.toString().toLatin1());
2014-06-03 14:33:07 +02:00
WaitForSignal(reply, SIGNAL(finished()));
2014-06-04 17:58:28 +02:00
if (!CheckReply(&reply)) {
2014-06-03 14:33:07 +02:00
qLog(Warning) << "Something wrong with the reply... (GetToken)";
return false;
}
reply->deleteLater();
2020-09-18 16:15:19 +02:00
QJsonObject json_response =
QJsonDocument::fromJson(reply->readAll()).object();
2014-06-03 14:33:07 +02:00
// Because the server responds "token"
2015-04-15 18:26:09 +02:00
access_token_ = json_response["token"].toString().replace("\"", "");
2014-06-03 14:33:07 +02:00
2014-06-04 17:58:28 +02:00
if (access_token_.isEmpty()) {
2014-06-03 14:33:07 +02:00
return false;
}
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("access_token", access_token_);
server_ = server;
emit Connected();
return true;
}
void SeafileService::GetLibraries() {
2014-06-04 17:58:28 +02:00
QUrl url(server_ + kListReposUrl);
2014-06-03 14:33:07 +02:00
QNetworkRequest request(url);
AddAuthorizationHeader(&request);
2014-06-04 17:58:28 +02:00
QNetworkReply* reply = network_->get(request);
2014-06-03 14:33:07 +02:00
2014-06-04 17:58:28 +02:00
NewClosure(reply, SIGNAL(finished()), this,
SLOT(GetLibrariesFinished(QNetworkReply*)), reply);
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
void SeafileService::GetLibrariesFinished(QNetworkReply* reply) {
if (!CheckReply(&reply)) {
2014-06-03 14:33:07 +02:00
qLog(Warning) << "Something wrong with the reply... (GetLibraries)";
return;
}
reply->deleteLater();
// key : id, value : name
QMap<QString, QString> libraries;
QByteArray data = reply->readAll();
2015-04-15 18:26:09 +02:00
QJsonArray json_repos = QJsonDocument::fromJson(data).array();
2020-09-18 16:15:19 +02:00
for (const QJsonValue& json_repo : json_repos) {
2015-04-15 18:26:09 +02:00
QJsonObject repo = json_repo.toObject();
2014-06-03 14:33:07 +02:00
QString repo_name = repo["name"].toString(),
2014-06-04 17:58:28 +02:00
repo_id = repo["id"].toString();
2014-06-03 14:33:07 +02:00
2014-06-04 17:58:28 +02:00
// One library can appear several times and we don't add encrypted libraries
// (not supported yet)
if (!libraries.contains(repo_id) && !repo["encrypted"].toBool()) {
2014-06-03 14:33:07 +02:00
libraries.insert(repo_id, repo_name);
}
}
emit GetLibrariesFinishedSignal(libraries);
}
2014-06-04 17:58:28 +02:00
void SeafileService::ChangeLibrary(const QString& new_library) {
if (new_library == library_updated_ || changing_libary_) return;
if (indexing_task_id_ != -1) {
qLog(Debug) << "Want to change the Seafile library, but Clementine waits "
"the previous indexing...";
changing_libary_ = true;
NewClosure(this, SIGNAL(UpdatingLibrariesFinishedSignal()), this,
SLOT(ChangeLibrary(QString)), new_library);
return;
}
AbortReadTagsReplies();
qLog(Debug) << "Change the Seafile library";
2014-06-03 14:33:07 +02:00
// Every other libraries have to be destroyed from the tree
2014-06-04 17:58:28 +02:00
if (new_library != "all") {
for (SeafileTree::TreeItem* library : tree_.libraries()) {
2014-06-03 14:33:07 +02:00
if (new_library != library->entry().id()) {
DeleteEntry(library->entry().id(), "/", library->entry());
}
}
}
changing_libary_ = false;
2014-06-03 14:33:07 +02:00
UpdateLibraries();
}
void SeafileService::Connect() {
if (has_credentials()) {
2014-06-03 14:33:07 +02:00
UpdateLibraries();
2014-06-04 17:58:28 +02:00
} else {
ShowConfig();
2014-06-03 14:33:07 +02:00
}
}
void SeafileService::UpdateLibraries() {
// Quit if we are already updating the libraries
if (indexing_task_id_ != -1) {
return;
}
indexing_task_id_ =
app_->task_manager()->StartTask(tr("Building Seafile index..."));
2014-06-04 17:58:28 +02:00
connect(this, SIGNAL(GetLibrariesFinishedSignal(QMap<QString, QString>)),
this, SLOT(UpdateLibrariesInProgress(QMap<QString, QString>)));
2014-06-03 14:33:07 +02:00
GetLibraries();
}
2014-06-04 17:58:28 +02:00
void SeafileService::UpdateLibrariesInProgress(
const QMap<QString, QString>& libraries) {
disconnect(this, SIGNAL(GetLibrariesFinishedSignal(QMap<QString, QString>)),
this, SLOT(UpdateLibrariesInProgress(QMap<QString, QString>)));
2014-06-03 14:33:07 +02:00
QSettings s;
s.beginGroup(kSettingsGroup);
QString library_to_update = s.value("library").toString();
// If the library didn't change, we don't need to update
2014-06-03 14:33:07 +02:00
if (!library_updated_.isNull() && library_updated_ == library_to_update) {
app_->task_manager()->SetTaskFinished(indexing_task_id_);
indexing_task_id_ = -1;
UpdatingLibrariesFinishedSignal();
2014-06-03 14:33:07 +02:00
return;
}
library_updated_ = library_to_update;
if (library_to_update.isEmpty() || library_to_update == "none") {
app_->task_manager()->SetTaskFinished(indexing_task_id_);
indexing_task_id_ = -1;
UpdatingLibrariesFinishedSignal();
2014-06-03 14:33:07 +02:00
return;
}
QMapIterator<QString, QString> library(libraries);
while (library.hasNext()) {
library.next();
// Need to check this library ?
if (library_to_update == "all" || library.key() == library_to_update) {
FetchAndCheckFolderItems(
2014-06-04 17:58:28 +02:00
SeafileTree::Entry(library.value(), library.key(),
SeafileTree::Entry::LIBRARY),
"/");
// If not, we can destroy the library from the tree
} else {
2014-06-04 17:58:28 +02:00
// If the library was not in the tree, it's not a problem because
// DeleteEntry won't do anything
2014-06-03 14:33:07 +02:00
DeleteEntry(library.key(), "/",
2014-06-04 17:58:28 +02:00
SeafileTree::Entry(library.value(), library.key(),
SeafileTree::Entry::LIBRARY));
2014-06-03 14:33:07 +02:00
}
}
// If we didn't do anything, set the task finished
if (indexing_task_max_ == 0) {
app_->task_manager()->SetTaskFinished(indexing_task_id_);
indexing_task_id_ = -1;
UpdatingLibrariesFinishedSignal();
}
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
QNetworkReply* SeafileService::PrepareFetchFolderItems(const QString& library,
const QString& path) {
QUrl url(server_ + QString(kFolderItemsUrl).arg(library));
2015-04-15 18:26:09 +02:00
QUrlQuery url_query;
url_query.addQueryItem("p", path);
url.setQuery(url_query);
2014-06-03 14:33:07 +02:00
QNetworkRequest request(url);
AddAuthorizationHeader(&request);
QNetworkReply* reply = network_->get(request);
return reply;
}
2014-06-04 17:58:28 +02:00
void SeafileService::FetchAndCheckFolderItems(const SeafileTree::Entry& library,
const QString& path) {
StartTaskInProgress();
2014-06-04 17:58:28 +02:00
QNetworkReply* reply = PrepareFetchFolderItems(library.id(), path);
2014-06-03 14:33:07 +02:00
NewClosure(reply, SIGNAL(finished()), this,
2014-06-04 17:58:28 +02:00
SLOT(FetchAndCheckFolderItemsFinished(
QNetworkReply*, SeafileTree::Entry, QString)),
2014-06-03 14:33:07 +02:00
reply, library, path);
}
void SeafileService::FetchAndCheckFolderItemsFinished(
2014-06-04 17:58:28 +02:00
QNetworkReply* reply, const SeafileTree::Entry& library,
const QString& path) {
if (!CheckReply(&reply)) {
qLog(Warning)
<< "Something wrong with the reply... (FetchFolderItemsToList)";
FinishedTaskInProgress();
2014-06-03 14:33:07 +02:00
return;
}
reply->deleteLater();
QByteArray data = reply->readAll();
2015-04-15 18:26:09 +02:00
QJsonArray json_entries = QJsonDocument::fromJson(data).array();
2014-06-03 14:33:07 +02:00
SeafileTree::Entries entries;
2015-04-15 18:26:09 +02:00
for (const QJsonValue& e : json_entries) {
QJsonObject entry = e.toObject();
2014-06-04 17:58:28 +02:00
SeafileTree::Entry::Type entry_type =
SeafileTree::Entry::StringToType(entry["type"].toString());
2014-06-03 14:33:07 +02:00
QString entry_name = entry["name"].toString();
// We just want libraries/directories and files which could be songs.
if (entry_type == SeafileTree::Entry::NONE) {
qLog(Warning) << "Type entry unknown for this entry";
2014-06-04 17:58:28 +02:00
} else if (entry_type == SeafileTree::Entry::FILE &&
GuessMimeTypeForFile(entry_name).isNull()) {
2014-06-03 14:33:07 +02:00
continue;
}
2014-06-04 17:58:28 +02:00
entries.append(
SeafileTree::Entry(entry_name, entry["id"].toString(), entry_type));
2014-06-03 14:33:07 +02:00
}
tree_.CheckEntries(entries, library, path);
FinishedTaskInProgress();
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
void SeafileService::AddRecursivelyFolderItems(const QString& library,
const QString& path) {
StartTaskInProgress();
2014-06-04 17:58:28 +02:00
QNetworkReply* reply = PrepareFetchFolderItems(library, path);
NewClosure(
reply, SIGNAL(finished()), this,
SLOT(AddRecursivelyFolderItemsFinished(QNetworkReply*, QString, QString)),
reply, library, path);
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply,
const QString& library,
const QString& path) {
if (!CheckReply(&reply)) {
2014-06-03 14:33:07 +02:00
qLog(Warning) << "Something wrong with the reply... (FetchFolderItems)";
FinishedTaskInProgress();
2014-06-03 14:33:07 +02:00
return;
}
reply->deleteLater();
QByteArray data = reply->readAll();
2015-04-15 18:26:09 +02:00
QJsonArray json_entries = QJsonDocument::fromJson(data).array();
2014-06-03 14:33:07 +02:00
2015-04-15 18:26:09 +02:00
for (const QJsonValue& e : json_entries) {
QJsonObject json_entry = e.toObject();
2014-06-04 17:58:28 +02:00
SeafileTree::Entry::Type entry_type =
2015-04-15 18:26:09 +02:00
SeafileTree::Entry::StringToType(json_entry["type"].toString());
QString entry_name = json_entry["name"].toString();
2014-06-03 14:33:07 +02:00
// We just want libraries/directories and files which could be songs.
if (entry_type == SeafileTree::Entry::NONE) {
qLog(Warning) << "Type entry unknown for this entry";
2014-06-04 17:58:28 +02:00
} else if (entry_type == SeafileTree::Entry::FILE &&
GuessMimeTypeForFile(entry_name).isNull()) {
2014-06-03 14:33:07 +02:00
continue;
}
2015-04-15 18:26:09 +02:00
SeafileTree::Entry entry(entry_name, json_entry["id"].toString(),
2014-06-04 17:58:28 +02:00
entry_type);
2014-06-03 14:33:07 +02:00
// If AddEntry was not successful we stop
2014-06-04 17:58:28 +02:00
if (!tree_.AddEntry(library, path, entry)) {
FinishedTaskInProgress();
2014-06-03 14:33:07 +02:00
return;
}
if (entry.is_dir()) {
AddRecursivelyFolderItems(library, path + entry.name() + "/");
2014-06-04 17:58:28 +02:00
} else {
2014-06-03 14:33:07 +02:00
MaybeAddFileEntry(entry.name(), library, path);
}
}
FinishedTaskInProgress();
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
QNetworkReply* SeafileService::PrepareFetchContentForFile(
const QString& library, const QString& filepath) {
QUrl content_url(server_ + QString(kFileContentUrl).arg(library));
2015-04-15 18:26:09 +02:00
QUrlQuery content_url_query;
content_url_query.addQueryItem("p", filepath);
content_url.setQuery(content_url_query);
2014-06-03 14:33:07 +02:00
QNetworkRequest request(content_url);
AddAuthorizationHeader(&request);
QNetworkReply* reply = network_->get(request);
return reply;
}
2014-06-04 17:58:28 +02:00
void SeafileService::MaybeAddFileEntry(const QString& entry_name,
const QString& library,
const QString& path) {
2014-06-03 14:33:07 +02:00
QString mime_type = GuessMimeTypeForFile(entry_name);
2014-06-04 17:58:28 +02:00
if (mime_type.isNull()) return;
2014-06-03 14:33:07 +02:00
// Get the details of the entry
2014-06-04 17:58:28 +02:00
QNetworkReply* reply = PrepareFetchContentForFile(library, path + entry_name);
2014-06-03 14:33:07 +02:00
NewClosure(reply, SIGNAL(finished()), this,
2014-06-04 17:58:28 +02:00
SLOT(MaybeAddFileEntryInProgress(QNetworkReply*, QString, QString,
QString)),
2014-06-03 14:33:07 +02:00
reply, library, path, mime_type);
}
2014-06-04 17:58:28 +02:00
void SeafileService::MaybeAddFileEntryInProgress(QNetworkReply* reply,
const QString& library,
const QString& path,
const QString& mime_type) {
if (!CheckReply(&reply)) {
2014-06-03 14:33:07 +02:00
qLog(Warning) << "Something wrong with the reply... (MaybeAddFileEntry)";
return;
}
reply->deleteLater();
QByteArray data = reply->readAll();
2015-04-15 18:26:09 +02:00
QJsonObject json_entry_detail = QJsonDocument::fromJson(data).object();
2014-06-03 14:33:07 +02:00
QUrl url;
url.setScheme("seafile");
2015-04-15 18:26:09 +02:00
url.setPath("/" + library + path + json_entry_detail["name"].toString());
2014-06-03 14:33:07 +02:00
Song song;
song.set_url(url);
song.set_ctime(0);
2015-04-15 18:26:09 +02:00
song.set_mtime(json_entry_detail["mtime"].toInt());
song.set_filesize(json_entry_detail["size"].toInt());
song.set_title(json_entry_detail["name"].toString());
2014-06-03 14:33:07 +02:00
// Get the download url of the entry
2014-06-04 17:58:28 +02:00
reply = PrepareFetchContentUrlForFile(
2015-04-15 18:26:09 +02:00
library, path + json_entry_detail["name"].toString());
2014-06-04 17:58:28 +02:00
NewClosure(
reply, SIGNAL(finished()), this,
SLOT(FetchContentUrlForFileFinished(QNetworkReply*, Song, QString)),
reply, song, mime_type);
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
QNetworkReply* SeafileService::PrepareFetchContentUrlForFile(
const QString& library, const QString& filepath) {
2014-06-03 14:33:07 +02:00
QUrl content_url(server_ + QString(kFileUrl).arg(library));
2015-04-15 18:26:09 +02:00
QUrlQuery content_url_query;
content_url_query.addQueryItem("p", filepath);
// See https://github.com/haiwen/seahub/issues/677
content_url_query.addQueryItem("reuse", "1");
2015-04-15 18:26:09 +02:00
content_url.setQuery(content_url_query);
2014-06-03 14:33:07 +02:00
QNetworkRequest request(content_url);
AddAuthorizationHeader(&request);
QNetworkReply* reply = network_->get(request);
return reply;
}
2014-06-04 17:58:28 +02:00
void SeafileService::FetchContentUrlForFileFinished(QNetworkReply* reply,
const Song& song,
const QString& mime_type) {
if (!CheckReply(&reply)) {
qLog(Warning)
<< "Something wrong with the reply... (FetchContentUrlForFile)";
2014-06-03 14:33:07 +02:00
return;
}
reply->deleteLater();
// Because server response is "http://..."
QString real_url = QString(reply->readAll()).replace("\"", "");
2014-06-04 17:58:28 +02:00
MaybeAddFileToDatabase(song, mime_type, QUrl(real_url),
QString("Token %1").arg(access_token_));
2014-06-03 14:33:07 +02:00
}
2014-06-04 17:58:28 +02:00
QUrl SeafileService::GetStreamingUrlFromSongId(const QString& library,
const QString& filepath) {
2014-06-03 14:33:07 +02:00
QNetworkReply* reply = PrepareFetchContentUrlForFile(library, filepath);
WaitForSignal(reply, SIGNAL(finished()));
2014-06-04 17:58:28 +02:00
if (!CheckReply(&reply)) {
qLog(Warning)
<< "Something wrong with the reply... (GetStreamingUrlFromSongId)";
2014-06-03 14:33:07 +02:00
return QUrl("");
}
reply->deleteLater();
QString response = QString(reply->readAll()).replace("\"", "");
return QUrl(response);
}
2014-06-04 17:58:28 +02:00
void SeafileService::AddEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry) {
2014-06-03 14:33:07 +02:00
if (entry.is_library()) {
tree_.AddLibrary(entry.name(), entry.id());
AddRecursivelyFolderItems(library, "/");
2014-06-04 17:58:28 +02:00
} else {
2014-06-03 14:33:07 +02:00
// If AddEntry was not successful we stop
2014-06-04 17:58:28 +02:00
// It could happen when the user changes the library to update while an
// update was in progress
if (!tree_.AddEntry(library, path, entry)) {
2014-06-03 14:33:07 +02:00
return;
}
if (entry.is_file()) {
MaybeAddFileEntry(entry.name(), library, path);
2014-06-04 17:58:28 +02:00
} else {
AddRecursivelyFolderItems(library, path + entry.name() + "/");
2014-06-03 14:33:07 +02:00
}
}
}
2014-06-04 17:58:28 +02:00
void SeafileService::UpdateEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry) {
2014-06-03 14:33:07 +02:00
if (entry.is_file()) {
DeleteEntry(library, path, entry);
AddEntry(library, path, entry);
2014-06-04 17:58:28 +02:00
} else {
2014-06-03 14:33:07 +02:00
QString entry_path = path;
2014-06-04 17:58:28 +02:00
if (entry.is_dir()) {
2014-06-03 14:33:07 +02:00
entry_path += entry.name() + "/";
}
2014-06-04 17:58:28 +02:00
FetchAndCheckFolderItems(
SeafileTree::Entry("", library, SeafileTree::Entry::LIBRARY),
entry_path);
2014-06-03 14:33:07 +02:00
}
}
2014-06-04 17:58:28 +02:00
void SeafileService::DeleteEntry(const QString& library, const QString& path,
const SeafileTree::Entry& entry) {
2014-06-03 14:33:07 +02:00
// For the QPair -> 1 : path, 2 : entry
QList<QPair<QString, SeafileTree::Entry>> files_to_delete;
2014-06-04 17:58:28 +02:00
if (entry.is_library()) {
SeafileTree::TreeItem* item = tree_.FindLibrary(library);
2014-06-03 14:33:07 +02:00
files_to_delete = tree_.GetRecursiveFilesOfDir("/", item);
tree_.DeleteLibrary(library);
2014-06-04 17:58:28 +02:00
} else {
if (entry.is_dir()) {
SeafileTree::TreeItem* item =
tree_.FindFromAbsolutePath(library, path + entry.name() + "/");
files_to_delete =
tree_.GetRecursiveFilesOfDir(path + entry.name() + "/", item);
} else {
2014-06-03 14:33:07 +02:00
files_to_delete.append(qMakePair(path, entry));
}
2014-06-04 17:58:28 +02:00
if (!tree_.DeleteEntry(library, path, entry)) {
2014-06-03 14:33:07 +02:00
return;
}
}
// Delete songs from the library of Clementine
2014-06-04 17:58:28 +02:00
for (const QPair<QString, SeafileTree::Entry>& file_to_delete :
files_to_delete) {
if (!GuessMimeTypeForFile(file_to_delete.second.name()).isEmpty()) {
QUrl song_url("seafile:/" + library + file_to_delete.first +
file_to_delete.second.name());
2014-06-03 14:33:07 +02:00
Song song = library_backend_->GetSongByUrl(song_url);
if (song.is_valid()) {
library_backend_->DeleteSongs(SongList() << song);
2014-06-04 17:58:28 +02:00
} else {
qLog(Warning) << "Can't delete song from the Clementine's library : "
<< song_url;
2014-06-03 14:33:07 +02:00
}
}
}
}
2014-06-04 17:58:28 +02:00
bool SeafileService::CheckReply(QNetworkReply** reply, int tries) {
if (!(*reply)) {
return false;
} else if (tries > kMaxTries) {
(*reply)->deleteLater();
2014-06-03 14:33:07 +02:00
return false;
}
2014-06-04 17:58:28 +02:00
QVariant status_code_variant =
(*reply)->attribute(QNetworkRequest::HttpStatusCodeAttribute);
2014-06-03 14:33:07 +02:00
if (status_code_variant.isValid()) {
int status_code = status_code_variant.toInt();
if (status_code == NO_ERROR) {
return true;
2014-06-04 17:58:28 +02:00
} else if (status_code == TOO_MANY_REQUESTS) {
2014-06-03 14:33:07 +02:00
qLog(Debug) << "Too many requests, wait...";
2014-06-04 17:58:28 +02:00
int seconds_to_wait;
if ((*reply)->hasRawHeader("X-Throttle-Wait-Seconds")) {
seconds_to_wait =
((*reply)->rawHeader("X-Throttle-Wait-Seconds").toInt() + 1) * 1000;
} else {
2014-06-19 15:33:45 +02:00
seconds_to_wait = std::pow(tries, 2) * 1000;
2014-06-04 17:58:28 +02:00
}
2014-06-03 14:33:07 +02:00
QTimer timer;
2014-06-04 17:58:28 +02:00
timer.start(seconds_to_wait);
2014-06-03 14:33:07 +02:00
WaitForSignal(&timer, SIGNAL(timeout()));
(*reply)->deleteLater();
2014-06-04 17:58:28 +02:00
// We execute the reply again
2014-06-03 14:33:07 +02:00
*reply = network_->get((*reply)->request());
WaitForSignal(*reply, SIGNAL(finished()));
2014-06-04 17:58:28 +02:00
return CheckReply(reply, ++tries);
2014-06-03 14:33:07 +02:00
}
}
// Unknown, 404 ...
(*reply)->deleteLater();
2015-04-15 18:26:09 +02:00
qLog(Warning) << "Error with the reply : " << status_code_variant.toInt();
2014-06-03 14:33:07 +02:00
return false;
}
void SeafileService::StartTaskInProgress() {
indexing_task_max_++;
task_manager_->SetTaskProgress(indexing_task_id_, indexing_task_progress_,
indexing_task_max_);
}
void SeafileService::FinishedTaskInProgress() {
indexing_task_progress_++;
if (indexing_task_progress_ == indexing_task_max_) {
task_manager_->SetTaskFinished(indexing_task_id_);
indexing_task_id_ = -1;
UpdatingLibrariesFinishedSignal();
} else {
task_manager_->SetTaskProgress(indexing_task_id_, indexing_task_progress_,
indexing_task_max_);
}
}
2014-06-03 14:33:07 +02:00
SeafileService::~SeafileService() {
// Save the tree !
QSettings s;
s.beginGroup(kSettingsGroup);
QByteArray tree_byte;
QDataStream stream(&tree_byte, QIODevice::WriteOnly);
stream << tree_;
s.setValue("tree", tree_byte);
}