2012-01-02 18:21:07 +01:00
|
|
|
/* This file is part of Clementine.
|
2014-11-02 19:36:21 +01:00
|
|
|
Copyright 2012, David Sansome <me@davidsansome.com>
|
|
|
|
Copyright 2012, 2014, John Maguire <john.maguire@gmail.com>
|
|
|
|
Copyright 2013, Arnaud Bienner <arnaud.bienner@gmail.com>
|
2014-11-02 19:40:52 +01:00
|
|
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
2012-01-02 18:21:07 +01:00
|
|
|
|
|
|
|
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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tagreaderclient.h"
|
|
|
|
|
2012-01-06 00:22:51 +01:00
|
|
|
#include <QCoreApplication>
|
2021-05-14 08:18:30 +02:00
|
|
|
#include <QDir>
|
2012-01-06 00:22:51 +01:00
|
|
|
#include <QFile>
|
2021-05-14 08:18:30 +02:00
|
|
|
#include <QFileInfo>
|
2012-01-02 18:21:07 +01:00
|
|
|
#include <QProcess>
|
2012-01-06 00:22:51 +01:00
|
|
|
#include <QTcpServer>
|
2012-11-30 13:50:44 +01:00
|
|
|
#include <QThread>
|
2012-07-28 20:35:12 +02:00
|
|
|
#include <QUrl>
|
2012-01-06 00:22:51 +01:00
|
|
|
|
2020-09-18 16:15:19 +02:00
|
|
|
#include "player.h"
|
2021-05-14 08:18:30 +02:00
|
|
|
#include "songpathparser.h"
|
2020-09-18 16:15:19 +02:00
|
|
|
|
2012-01-06 00:22:51 +01:00
|
|
|
const char* TagReaderClient::kWorkerExecutableName = "clementine-tagreader";
|
2014-02-06 16:49:49 +01:00
|
|
|
TagReaderClient* TagReaderClient::sInstance = nullptr;
|
2012-01-02 18:21:07 +01:00
|
|
|
|
|
|
|
TagReaderClient::TagReaderClient(QObject* parent)
|
2021-05-14 08:18:30 +02:00
|
|
|
: QObject(parent),
|
|
|
|
worker_pool_(new WorkerPool<HandlerType>(this)),
|
|
|
|
path_parser_(new SongPathParser()) {
|
2012-01-06 22:27:02 +01:00
|
|
|
sInstance = this;
|
2020-05-27 07:36:26 +02:00
|
|
|
setObjectName("Tag reader client");
|
2012-01-06 22:27:02 +01:00
|
|
|
|
Introduce limit for number of tag client processes.
Previously, the number of processes spawned was always
QThread::idealThreadCount() (returning the number of logical CPU
cores). On new systems with many cores, however, this can result
in 12, 16, 24, or ... processes being spawned, which is a bit
excessive.
This establishes a new config variable,
'max_numprocs_tagclients' within the Settings group, in order
to limit the maximum number of tag client processes that get
spawned. It also adds a means of setting this via the Behavior
page in Settings. It can be set to any integer in the interval
[1, QThread::idealThreadCount()]; it defaults to the maximal value
so as to emulate the old behavior.
2019-03-28 17:37:54 +01:00
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(Player::kSettingsGroup);
|
|
|
|
|
|
|
|
int max_workers = QThread::idealThreadCount();
|
|
|
|
int num_workers = s.value("max_numprocs_tagclients", max_workers).toInt();
|
|
|
|
|
2012-01-06 22:27:02 +01:00
|
|
|
worker_pool_->SetExecutableName(kWorkerExecutableName);
|
Introduce limit for number of tag client processes.
Previously, the number of processes spawned was always
QThread::idealThreadCount() (returning the number of logical CPU
cores). On new systems with many cores, however, this can result
in 12, 16, 24, or ... processes being spawned, which is a bit
excessive.
This establishes a new config variable,
'max_numprocs_tagclients' within the Settings group, in order
to limit the maximum number of tag client processes that get
spawned. It also adds a means of setting this via the Behavior
page in Settings. It can be set to any integer in the interval
[1, QThread::idealThreadCount()]; it defaults to the maximal value
so as to emulate the old behavior.
2019-03-28 17:37:54 +01:00
|
|
|
worker_pool_->SetWorkerCount(num_workers);
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(worker_pool_, SIGNAL(WorkerFailedToStart()),
|
|
|
|
SLOT(WorkerFailedToStart()));
|
2012-01-02 18:21:07 +01:00
|
|
|
}
|
|
|
|
|
2021-05-14 08:18:30 +02:00
|
|
|
TagReaderClient::~TagReaderClient() {}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void TagReaderClient::Start() { worker_pool_->Start(); }
|
2012-01-02 18:21:07 +01:00
|
|
|
|
2021-05-17 20:17:29 +02:00
|
|
|
void TagReaderClient::ReloadSettings() { path_parser_->ReloadSettings(); }
|
|
|
|
|
2012-01-07 23:58:30 +01:00
|
|
|
void TagReaderClient::WorkerFailedToStart() {
|
|
|
|
qLog(Error) << "The" << kWorkerExecutableName << "executable was not found"
|
|
|
|
<< "in the current directory or on the PATH. Clementine will"
|
|
|
|
<< "not be able to read music file tags without it.";
|
|
|
|
}
|
|
|
|
|
2012-01-02 18:21:07 +01:00
|
|
|
TagReaderReply* TagReaderClient::ReadFile(const QString& filename) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::ReadFileRequest* req = message.mutable_read_file_request();
|
2012-01-02 18:21:07 +01:00
|
|
|
|
|
|
|
req->set_filename(DataCommaSizeFromQString(filename));
|
|
|
|
|
2012-01-22 19:41:26 +01:00
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
2012-01-02 18:21:07 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
TagReaderReply* TagReaderClient::SaveFile(const QString& filename,
|
|
|
|
const Song& metadata) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::SaveFileRequest* req = message.mutable_save_file_request();
|
2012-01-02 18:21:07 +01:00
|
|
|
|
|
|
|
req->set_filename(DataCommaSizeFromQString(filename));
|
|
|
|
metadata.ToProtobuf(req->mutable_metadata());
|
|
|
|
|
2012-01-22 19:41:26 +01:00
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
2012-01-02 18:21:07 +01:00
|
|
|
}
|
|
|
|
|
2013-02-24 17:45:25 +01:00
|
|
|
TagReaderReply* TagReaderClient::UpdateSongStatistics(const Song& metadata) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::SaveSongStatisticsToFileRequest* req =
|
2013-02-24 17:45:25 +01:00
|
|
|
message.mutable_save_song_statistics_to_file_request();
|
|
|
|
|
|
|
|
req->set_filename(DataCommaSizeFromQString(metadata.url().toLocalFile()));
|
|
|
|
metadata.ToProtobuf(req->mutable_metadata());
|
|
|
|
|
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TagReaderClient::UpdateSongsStatistics(const SongList& songs) {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const Song& song : songs) {
|
2013-02-24 17:45:25 +01:00
|
|
|
TagReaderReply* reply = UpdateSongStatistics(song);
|
|
|
|
connect(reply, SIGNAL(Finished(bool)), reply, SLOT(deleteLater()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-30 23:42:29 +01:00
|
|
|
TagReaderReply* TagReaderClient::UpdateSongRating(const Song& metadata) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::SaveSongRatingToFileRequest* req =
|
2013-03-30 23:42:29 +01:00
|
|
|
message.mutable_save_song_rating_to_file_request();
|
|
|
|
|
|
|
|
req->set_filename(DataCommaSizeFromQString(metadata.url().toLocalFile()));
|
|
|
|
metadata.ToProtobuf(req->mutable_metadata());
|
|
|
|
|
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TagReaderClient::UpdateSongsRating(const SongList& songs) {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const Song& song : songs) {
|
2013-03-30 23:42:29 +01:00
|
|
|
TagReaderReply* reply = UpdateSongRating(song);
|
|
|
|
connect(reply, SIGNAL(Finished(bool)), reply, SLOT(deleteLater()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-02 18:21:07 +01:00
|
|
|
TagReaderReply* TagReaderClient::IsMediaFile(const QString& filename) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::IsMediaFileRequest* req =
|
2014-02-07 16:34:20 +01:00
|
|
|
message.mutable_is_media_file_request();
|
2012-01-02 18:21:07 +01:00
|
|
|
|
|
|
|
req->set_filename(DataCommaSizeFromQString(filename));
|
|
|
|
|
2012-01-22 19:41:26 +01:00
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
2012-01-02 18:21:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TagReaderReply* TagReaderClient::LoadEmbeddedArt(const QString& filename) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::LoadEmbeddedArtRequest* req =
|
2014-02-07 16:34:20 +01:00
|
|
|
message.mutable_load_embedded_art_request();
|
2012-01-02 18:21:07 +01:00
|
|
|
|
|
|
|
req->set_filename(DataCommaSizeFromQString(filename));
|
|
|
|
|
2012-01-22 19:41:26 +01:00
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
2012-01-06 22:27:02 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
TagReaderReply* TagReaderClient::ReadCloudFile(
|
|
|
|
const QUrl& download_url, const QString& title, int size,
|
|
|
|
const QString& mime_type, const QString& authorisation_header) {
|
2021-02-20 22:20:04 +01:00
|
|
|
cpb::tagreader::Message message;
|
|
|
|
cpb::tagreader::ReadCloudFileRequest* req =
|
2012-11-28 16:34:10 +01:00
|
|
|
message.mutable_read_cloud_file_request();
|
2012-07-28 20:35:12 +02:00
|
|
|
|
|
|
|
const QString url_string = download_url.toEncoded();
|
|
|
|
req->set_download_url(DataCommaSizeFromQString(url_string));
|
|
|
|
req->set_title(DataCommaSizeFromQString(title));
|
|
|
|
req->set_size(size);
|
2012-07-31 11:57:04 +02:00
|
|
|
req->set_mime_type(DataCommaSizeFromQString(mime_type));
|
2012-11-28 14:43:03 +01:00
|
|
|
req->set_authorisation_header(DataCommaSizeFromQString(authorisation_header));
|
2012-07-28 20:35:12 +02:00
|
|
|
|
|
|
|
return worker_pool_->SendMessageWithReply(&message);
|
|
|
|
}
|
|
|
|
|
2012-01-06 22:27:02 +01:00
|
|
|
void TagReaderClient::ReadFileBlocking(const QString& filename, Song* song) {
|
|
|
|
Q_ASSERT(QThread::currentThread() != thread());
|
|
|
|
|
|
|
|
TagReaderReply* reply = ReadFile(filename);
|
|
|
|
if (reply->WaitForFinished()) {
|
|
|
|
song->InitFromProtobuf(reply->message().read_file_response().metadata());
|
2021-05-14 08:18:30 +02:00
|
|
|
path_parser_->GuessMissingFields(song, filename);
|
2012-01-06 22:27:02 +01:00
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool TagReaderClient::SaveFileBlocking(const QString& filename,
|
|
|
|
const Song& metadata) {
|
2012-01-06 22:27:02 +01:00
|
|
|
Q_ASSERT(QThread::currentThread() != thread());
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
TagReaderReply* reply = SaveFile(filename, metadata);
|
|
|
|
if (reply->WaitForFinished()) {
|
|
|
|
ret = reply->message().save_file_response().success();
|
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-03-26 23:56:46 +01:00
|
|
|
bool TagReaderClient::UpdateSongStatisticsBlocking(const Song& metadata) {
|
|
|
|
Q_ASSERT(QThread::currentThread() != thread());
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
TagReaderReply* reply = UpdateSongStatistics(metadata);
|
|
|
|
if (reply->WaitForFinished()) {
|
|
|
|
ret = reply->message().save_song_statistics_to_file_response().success();
|
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-03-30 23:42:29 +01:00
|
|
|
bool TagReaderClient::UpdateSongRatingBlocking(const Song& metadata) {
|
|
|
|
Q_ASSERT(QThread::currentThread() != thread());
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
TagReaderReply* reply = UpdateSongRating(metadata);
|
|
|
|
if (reply->WaitForFinished()) {
|
|
|
|
ret = reply->message().save_song_rating_to_file_response().success();
|
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-06 22:27:02 +01:00
|
|
|
bool TagReaderClient::IsMediaFileBlocking(const QString& filename) {
|
|
|
|
Q_ASSERT(QThread::currentThread() != thread());
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
TagReaderReply* reply = IsMediaFile(filename);
|
|
|
|
if (reply->WaitForFinished()) {
|
|
|
|
ret = reply->message().is_media_file_response().success();
|
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
QImage TagReaderClient::LoadEmbeddedArtBlocking(const QString& filename) {
|
|
|
|
Q_ASSERT(QThread::currentThread() != thread());
|
|
|
|
|
|
|
|
QImage ret;
|
|
|
|
|
|
|
|
TagReaderReply* reply = LoadEmbeddedArt(filename);
|
|
|
|
if (reply->WaitForFinished()) {
|
|
|
|
const std::string& data_str =
|
|
|
|
reply->message().load_embedded_art_response().data();
|
|
|
|
ret.loadFromData(QByteArray(data_str.data(), data_str.size()));
|
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
|
|
|
|
return ret;
|
2012-01-02 18:21:07 +01:00
|
|
|
}
|