Remove external tagreader
This commit is contained in:
423
src/tagreader/tagreaderclient.cpp
Normal file
423
src/tagreader/tagreaderclient.cpp
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2019-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry 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.
|
||||
*
|
||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QImage>
|
||||
#include <QScopeGuard>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/song.h"
|
||||
|
||||
#include "tagreaderclient.h"
|
||||
#include "tagreadertaglib.h"
|
||||
#include "tagreaderresult.h"
|
||||
#include "tagreaderrequest.h"
|
||||
#include "tagreaderismediafilerequest.h"
|
||||
#include "tagreaderreadfilerequest.h"
|
||||
#include "tagreaderwritefilerequest.h"
|
||||
#include "tagreaderloadcoverdatarequest.h"
|
||||
#include "tagreaderloadcoverimagerequest.h"
|
||||
#include "tagreadersavecoverrequest.h"
|
||||
#include "tagreadersaveplaycountrequest.h"
|
||||
#include "tagreadersaveratingrequest.h"
|
||||
#include "tagreaderreply.h"
|
||||
#include "tagreaderreadfilereply.h"
|
||||
#include "tagreaderloadcoverdatareply.h"
|
||||
#include "tagreaderloadcoverimagereply.h"
|
||||
|
||||
using std::dynamic_pointer_cast;
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
TagReaderClient *TagReaderClient::sInstance = nullptr;
|
||||
|
||||
TagReaderClient::TagReaderClient(QObject *parent)
|
||||
: QObject(parent),
|
||||
original_thread_(thread()),
|
||||
abort_(false),
|
||||
processing_(false) {
|
||||
|
||||
setObjectName(QLatin1String(metaObject()->className()));
|
||||
|
||||
sInstance = this;
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::ExitAsync() {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
abort_ = true;
|
||||
QMetaObject::invokeMethod(this, &TagReaderClient::Exit, Qt::QueuedConnection);
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::Exit() {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
moveToThread(original_thread_);
|
||||
Q_EMIT ExitFinished();
|
||||
|
||||
}
|
||||
|
||||
bool TagReaderClient::HaveRequests() const {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
{
|
||||
QMutexLocker l(&mutex_requests_);
|
||||
return !requests_.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::EnqueueRequest(TagReaderRequestPtr request) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
{
|
||||
QMutexLocker l(&mutex_requests_);
|
||||
requests_.enqueue(request);
|
||||
}
|
||||
|
||||
if (!processing_.value()) {
|
||||
ProcessRequestsAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TagReaderRequestPtr TagReaderClient::DequeueRequest() {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
{
|
||||
QMutexLocker l(&mutex_requests_);
|
||||
if (requests_.isEmpty()) return TagReaderRequestPtr();
|
||||
return requests_.dequeue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::ProcessRequestsAsync() {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
QMetaObject::invokeMethod(this, &TagReaderClient::ProcessRequests, Qt::QueuedConnection);
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::ProcessRequests() {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
processing_ = true;
|
||||
|
||||
const QScopeGuard scopeguard_processing = qScopeGuard([this]() {
|
||||
processing_ = false;
|
||||
});
|
||||
|
||||
while (HaveRequests()) {
|
||||
if (abort_.value()) return;
|
||||
ProcessRequest(DequeueRequest());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::ProcessRequest(TagReaderRequestPtr request) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
TagReaderReplyPtr reply = request->reply;
|
||||
|
||||
TagReaderResult result;
|
||||
|
||||
if (TagReaderIsMediaFileRequestPtr is_media_file_request = std::dynamic_pointer_cast<TagReaderIsMediaFileRequest>(request)) {
|
||||
result = tagreader_.IsMediaFile(is_media_file_request->filename);
|
||||
if (result.error_code == TagReaderResult::ErrorCode::Unsupported) {
|
||||
result = gmereader_.IsMediaFile(is_media_file_request->filename);
|
||||
}
|
||||
}
|
||||
else if (TagReaderReadFileRequestPtr read_file_request = std::dynamic_pointer_cast<TagReaderReadFileRequest>(request)) {
|
||||
Song song;
|
||||
result = ReadFileBlocking(read_file_request->filename, &song);
|
||||
if (result.error_code == TagReaderResult::ErrorCode::Unsupported) {
|
||||
result = gmereader_.ReadFile(read_file_request->filename, &song);
|
||||
}
|
||||
if (result.success()) {
|
||||
if (TagReaderReadFileReplyPtr read_file_reply = std::dynamic_pointer_cast<TagReaderReadFileReply>(reply)) {
|
||||
read_file_reply->set_song(song);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TagReaderWriteFileRequestPtr write_file_request = dynamic_pointer_cast<TagReaderWriteFileRequest>(request)) {
|
||||
result = WriteFileBlocking(write_file_request->filename, write_file_request->song, write_file_request->save_tags_options, write_file_request->save_tag_cover_data);
|
||||
}
|
||||
else if (TagReaderLoadCoverDataRequestPtr load_cover_data_request = dynamic_pointer_cast<TagReaderLoadCoverDataRequest>(request)) {
|
||||
QByteArray cover_data;
|
||||
result = LoadCoverDataBlocking(load_cover_data_request->filename, cover_data);
|
||||
if (result.success()) {
|
||||
if (TagReaderLoadCoverDataReplyPtr load_cover_data_reply = std::dynamic_pointer_cast<TagReaderLoadCoverDataReply>(reply)) {
|
||||
load_cover_data_reply->set_data(cover_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TagReaderLoadCoverImageRequestPtr load_cover_image_request = dynamic_pointer_cast<TagReaderLoadCoverImageRequest>(request)) {
|
||||
QImage cover_image;
|
||||
result = LoadCoverImageBlocking(load_cover_image_request->filename, cover_image);
|
||||
if (result.success()) {
|
||||
if (TagReaderLoadCoverImageReplyPtr load_cover_image_reply = std::dynamic_pointer_cast<TagReaderLoadCoverImageReply>(reply)) {
|
||||
load_cover_image_reply->set_image(cover_image);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TagReaderSaveCoverRequestPtr save_cover_request = dynamic_pointer_cast<TagReaderSaveCoverRequest>(request)) {
|
||||
result = SaveCoverBlocking(save_cover_request->filename, save_cover_request->save_tag_cover_data);
|
||||
}
|
||||
else if (TagReaderSavePlaycountRequestPtr save_playcount_request = dynamic_pointer_cast<TagReaderSavePlaycountRequest>(request)) {
|
||||
result = SaveSongPlaycountBlocking(save_playcount_request->filename, save_playcount_request->playcount);
|
||||
}
|
||||
else if (TagReaderSaveRatingRequestPtr save_rating_request = dynamic_pointer_cast<TagReaderSaveRatingRequest>(request)) {
|
||||
result = SaveSongRatingBlocking(save_rating_request->filename, save_rating_request->rating);
|
||||
}
|
||||
|
||||
reply->set_result(result);
|
||||
|
||||
reply->Finish();
|
||||
|
||||
}
|
||||
|
||||
bool TagReaderClient::IsMediaFileBlocking(const QString &filename) const {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
return tagreader_.IsMediaFile(filename).success();
|
||||
|
||||
}
|
||||
|
||||
TagReaderReplyPtr TagReaderClient::IsMediaFileAsync(const QString &filename) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderReplyPtr reply = TagReaderReply::Create<TagReaderReply>(filename);
|
||||
|
||||
TagReaderIsMediaFileRequestPtr request = TagReaderIsMediaFileRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::ReadFileBlocking(const QString &filename, Song *song) {
|
||||
|
||||
return tagreader_.ReadFile(filename, song);
|
||||
|
||||
}
|
||||
|
||||
TagReaderReadFileReplyPtr TagReaderClient::ReadFileAsync(const QString &filename) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderReadFileReplyPtr reply = TagReaderReply::Create<TagReaderReadFileReply>(filename);
|
||||
|
||||
TagReaderReadFileRequestPtr request = TagReaderReadFileRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::WriteFileBlocking(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) {
|
||||
|
||||
return tagreader_.WriteFile(filename, song, save_tags_options, save_tag_cover_data);
|
||||
|
||||
}
|
||||
|
||||
TagReaderReplyPtr TagReaderClient::WriteFileAsync(const QString &filename, const Song &song, const SaveTagsOptions save_tags_options, const SaveTagCoverData &save_tag_cover_data) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderReplyPtr reply = TagReaderReply::Create<TagReaderReply>(filename);
|
||||
|
||||
TagReaderWriteFileRequestPtr request = TagReaderWriteFileRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
request->song = song;
|
||||
request->save_tags_options = save_tags_options;
|
||||
request->save_tag_cover_data = save_tag_cover_data;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::LoadCoverDataBlocking(const QString &filename, QByteArray &data) {
|
||||
|
||||
return tagreader_.LoadEmbeddedCover(filename, data);
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::LoadCoverImageBlocking(const QString &filename, QImage &image) {
|
||||
|
||||
QByteArray data;
|
||||
TagReaderResult result = LoadCoverDataBlocking(filename, data);
|
||||
if (result.error_code == TagReaderResult::ErrorCode::Success && !image.loadFromData(data)) {
|
||||
result.error_code = TagReaderResult::ErrorCode::Unsupported;
|
||||
result.error_text = QObject::tr("Failed to load image from data for %1").arg(filename);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
TagReaderLoadCoverDataReplyPtr TagReaderClient::LoadCoverDataAsync(const QString &filename) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderLoadCoverDataReplyPtr reply = TagReaderReply::Create<TagReaderLoadCoverDataReply>(filename);
|
||||
|
||||
TagReaderLoadCoverDataRequestPtr request = TagReaderLoadCoverDataRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderLoadCoverImageReplyPtr TagReaderClient::LoadCoverImageAsync(const QString &filename) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderLoadCoverImageReplyPtr reply = TagReaderReply::Create<TagReaderLoadCoverImageReply>(filename);
|
||||
|
||||
TagReaderLoadCoverImageRequestPtr request = TagReaderLoadCoverImageRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::SaveCoverBlocking(const QString &filename, const SaveTagCoverData &save_tag_cover_data) {
|
||||
|
||||
return tagreader_.SaveEmbeddedCover(filename, save_tag_cover_data);
|
||||
|
||||
}
|
||||
|
||||
TagReaderReplyPtr TagReaderClient::SaveCoverAsync(const QString &filename, const SaveTagCoverData &save_tag_cover_data) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderReplyPtr reply = TagReaderReply::Create<TagReaderReply>(filename);
|
||||
|
||||
TagReaderSaveCoverRequestPtr request = TagReaderSaveCoverRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
request->save_tag_cover_data = save_tag_cover_data;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderReplyPtr TagReaderClient::SaveSongPlaycountAsync(const QString &filename, const uint playcount) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderReplyPtr reply = TagReaderReply::Create<TagReaderReply>(filename);
|
||||
|
||||
TagReaderSavePlaycountRequestPtr request = TagReaderSavePlaycountRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
request->playcount = playcount;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::SaveSongPlaycountBlocking(const QString &filename, const uint playcount) {
|
||||
|
||||
return tagreader_.SaveSongPlaycount(filename, playcount);
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::SaveSongsPlaycountAsync(const SongList &songs) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
for (const Song &song : songs) {
|
||||
TagReaderReplyPtr reply = SaveSongPlaycountAsync(song.url().toLocalFile(), song.playcount());
|
||||
QObject::connect(&*reply, &TagReaderReply::Finished, &*reply, &TagReaderReply::deleteLater);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TagReaderResult TagReaderClient::SaveSongRatingBlocking(const QString &filename, const float rating) {
|
||||
|
||||
return tagreader_.SaveSongRating(filename, rating);
|
||||
|
||||
}
|
||||
|
||||
TagReaderReplyPtr TagReaderClient::SaveSongRatingAsync(const QString &filename, const float rating) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
TagReaderReplyPtr reply = TagReaderReply::Create<TagReaderReply>(filename);
|
||||
|
||||
TagReaderSaveRatingRequestPtr request = TagReaderSaveRatingRequest::Create(filename);
|
||||
request->reply = reply;
|
||||
request->filename = filename;
|
||||
request->rating = rating;
|
||||
|
||||
EnqueueRequest(request);
|
||||
|
||||
return reply;
|
||||
|
||||
}
|
||||
|
||||
void TagReaderClient::SaveSongsRatingAsync(const SongList &songs) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
for (const Song &song : songs) {
|
||||
TagReaderReplyPtr reply = SaveSongRatingAsync(song.url().toLocalFile(), song.rating());
|
||||
QObject::connect(&*reply, &TagReaderReply::Finished, &*reply, &TagReaderReply::deleteLater);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user