2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine .
* Copyright 2010 , David Sansome < me @ davidsansome . com >
2023-05-14 11:34:55 +02:00
* Copyright 2019 - 2023 , Jonas Kvinge < jonas @ jkvinge . net >
2018-02-27 18:06:05 +01:00
*
* 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/>.
2018-08-09 18:39:44 +02:00
*
2018-02-27 18:06:05 +01:00
*/
# include "config.h"
2018-05-01 00:41:33 +02:00
# include <string>
2018-02-27 18:06:05 +01:00
2018-05-01 00:41:33 +02:00
# include <QtGlobal>
# include <QObject>
2018-02-27 18:06:05 +01:00
# include <QThread>
2018-05-01 00:41:33 +02:00
# include <QByteArray>
# include <QString>
# include <QImage>
# include "core/logging.h"
# include "core/workerpool.h"
# include "song.h"
# include "tagreaderclient.h"
2018-02-27 18:06:05 +01:00
2024-04-11 02:56:01 +02:00
namespace {
constexpr char kWorkerExecutableName [ ] = " strawberry-tagreader " ;
}
2018-02-27 18:06:05 +01:00
TagReaderClient * TagReaderClient : : sInstance = nullptr ;
TagReaderClient : : TagReaderClient ( QObject * parent ) : QObject ( parent ) , worker_pool_ ( new WorkerPool < HandlerType > ( this ) ) {
sInstance = this ;
2019-07-24 23:29:09 +02:00
original_thread_ = thread ( ) ;
2018-02-27 18:06:05 +01:00
2024-04-11 02:56:01 +02:00
worker_pool_ - > SetExecutableName ( QLatin1String ( kWorkerExecutableName ) ) ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( worker_pool_ , & WorkerPool < HandlerType > : : WorkerFailedToStart , this , & TagReaderClient : : WorkerFailedToStart ) ;
2019-10-19 15:09:18 +02:00
2018-02-27 18:06:05 +01:00
}
void TagReaderClient : : Start ( ) { worker_pool_ - > Start ( ) ; }
2019-07-24 23:29:09 +02:00
void TagReaderClient : : ExitAsync ( ) {
2023-05-03 20:08:51 +02:00
QMetaObject : : invokeMethod ( this , & TagReaderClient : : Exit , Qt : : QueuedConnection ) ;
2019-07-24 23:29:09 +02:00
}
void TagReaderClient : : Exit ( ) {
2021-09-27 19:09:18 +02:00
Q_ASSERT ( QThread : : currentThread ( ) = = thread ( ) ) ;
2019-07-24 23:29:09 +02:00
moveToThread ( original_thread_ ) ;
emit ExitFinished ( ) ;
}
2018-02-27 18:06:05 +01:00
void TagReaderClient : : WorkerFailedToStart ( ) {
qLog ( Error ) < < " The " < < kWorkerExecutableName < < " executable was not found in the current directory or on the PATH. Strawberry will not be able to read music file tags without it. " ;
}
2021-10-18 23:15:30 +02:00
TagReaderReply * TagReaderClient : : IsMediaFile ( const QString & filename ) {
2018-10-02 00:38:52 +02:00
2021-02-20 17:06:55 +01:00
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : IsMediaFileRequest * request = message . mutable_is_media_file_request ( ) ;
2018-02-27 18:06:05 +01:00
2023-03-18 20:03:07 +01:00
const QByteArray filename_data = filename . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
2018-02-27 18:06:05 +01:00
return worker_pool_ - > SendMessageWithReply ( & message ) ;
}
2021-10-18 23:15:30 +02:00
TagReaderReply * TagReaderClient : : ReadFile ( const QString & filename ) {
2018-02-27 18:06:05 +01:00
2021-02-20 17:06:55 +01:00
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : ReadFileRequest * request = message . mutable_read_file_request ( ) ;
2018-02-27 18:06:05 +01:00
2023-03-18 20:03:07 +01:00
const QByteArray filename_data = filename . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
2018-02-27 18:06:05 +01:00
2021-10-18 23:15:30 +02:00
return worker_pool_ - > SendMessageWithReply ( & message ) ;
2018-02-27 18:06:05 +01:00
}
2023-05-14 11:34:55 +02:00
TagReaderReply * TagReaderClient : : SaveFile ( const QString & filename , const Song & metadata , const SaveTypes save_types , const SaveCoverOptions & save_cover_options ) {
2018-10-02 00:38:52 +02:00
2021-02-20 17:06:55 +01:00
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : SaveFileRequest * request = message . mutable_save_file_request ( ) ;
const QByteArray filename_data = filename . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
2023-05-14 11:34:55 +02:00
request - > set_save_tags ( save_types . testFlag ( SaveType : : Tags ) ) ;
request - > set_save_playcount ( save_types . testFlag ( SaveType : : PlayCount ) ) ;
request - > set_save_rating ( save_types . testFlag ( SaveType : : Rating ) ) ;
request - > set_save_cover ( save_types . testFlag ( SaveType : : Cover ) ) ;
2023-03-18 20:03:07 +01:00
if ( save_cover_options . cover_filename . length ( ) > 0 ) {
2023-05-14 11:34:55 +02:00
const QByteArray cover_filename = save_cover_options . cover_filename . toUtf8 ( ) ;
2023-03-18 20:03:07 +01:00
request - > set_cover_filename ( cover_filename . constData ( ) , cover_filename . length ( ) ) ;
}
if ( save_cover_options . cover_data . length ( ) > 0 ) {
request - > set_cover_data ( save_cover_options . cover_data . constData ( ) , save_cover_options . cover_data . length ( ) ) ;
}
2023-05-14 11:34:55 +02:00
if ( save_cover_options . mime_type . length ( ) > 0 ) {
const QByteArray cover_mime_type = save_cover_options . mime_type . toUtf8 ( ) ;
request - > set_cover_mime_type ( cover_mime_type . constData ( ) , cover_mime_type . length ( ) ) ;
}
2023-03-18 20:03:07 +01:00
metadata . ToProtobuf ( request - > mutable_metadata ( ) ) ;
2018-02-27 18:06:05 +01:00
2021-10-18 23:15:30 +02:00
ReplyType * reply = worker_pool_ - > SendMessageWithReply ( & message ) ;
return reply ;
2018-02-27 18:06:05 +01:00
}
TagReaderReply * TagReaderClient : : LoadEmbeddedArt ( const QString & filename ) {
2018-10-02 00:38:52 +02:00
2021-02-20 17:06:55 +01:00
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : LoadEmbeddedArtRequest * request = message . mutable_load_embedded_art_request ( ) ;
2018-02-27 18:06:05 +01:00
2023-03-18 20:03:07 +01:00
const QByteArray filename_data = filename . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
2018-02-27 18:06:05 +01:00
return worker_pool_ - > SendMessageWithReply ( & message ) ;
}
2023-03-18 20:03:07 +01:00
TagReaderReply * TagReaderClient : : SaveEmbeddedArt ( const QString & filename , const SaveCoverOptions & save_cover_options ) {
2021-02-16 22:50:35 +01:00
2021-02-20 17:06:55 +01:00
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : SaveEmbeddedArtRequest * request = message . mutable_save_embedded_art_request ( ) ;
const QByteArray filename_data = filename . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
if ( save_cover_options . cover_filename . length ( ) > 0 ) {
2023-05-14 11:34:55 +02:00
const QByteArray cover_filename = save_cover_options . cover_filename . toUtf8 ( ) ;
2023-03-18 20:03:07 +01:00
request - > set_cover_filename ( cover_filename . constData ( ) , cover_filename . length ( ) ) ;
}
if ( save_cover_options . cover_data . length ( ) > 0 ) {
request - > set_cover_data ( save_cover_options . cover_data . constData ( ) , save_cover_options . cover_data . length ( ) ) ;
}
2023-05-14 11:34:55 +02:00
if ( save_cover_options . mime_type . length ( ) > 0 ) {
const QByteArray cover_mime_type = save_cover_options . mime_type . toUtf8 ( ) ;
request - > set_cover_mime_type ( cover_mime_type . constData ( ) , cover_mime_type . length ( ) ) ;
}
2021-02-16 22:50:35 +01:00
return worker_pool_ - > SendMessageWithReply ( & message ) ;
}
2021-10-24 16:08:17 +02:00
TagReaderReply * TagReaderClient : : UpdateSongPlaycount ( const Song & metadata ) {
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : SaveSongPlaycountToFileRequest * request = message . mutable_save_song_playcount_to_file_request ( ) ;
2021-10-24 16:08:17 +02:00
2023-03-18 20:03:07 +01:00
const QByteArray filename_data = metadata . url ( ) . toLocalFile ( ) . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
metadata . ToProtobuf ( request - > mutable_metadata ( ) ) ;
2021-10-24 16:08:17 +02:00
return worker_pool_ - > SendMessageWithReply ( & message ) ;
}
void TagReaderClient : : UpdateSongsPlaycount ( const SongList & songs ) {
for ( const Song & song : songs ) {
TagReaderReply * reply = UpdateSongPlaycount ( song ) ;
QObject : : connect ( reply , & TagReaderReply : : Finished , reply , & TagReaderReply : : deleteLater ) ;
}
}
TagReaderReply * TagReaderClient : : UpdateSongRating ( const Song & metadata ) {
spb : : tagreader : : Message message ;
2023-03-18 20:03:07 +01:00
spb : : tagreader : : SaveSongRatingToFileRequest * request = message . mutable_save_song_rating_to_file_request ( ) ;
2021-10-24 16:08:17 +02:00
2023-03-18 20:03:07 +01:00
const QByteArray filename_data = metadata . url ( ) . toLocalFile ( ) . toUtf8 ( ) ;
request - > set_filename ( filename_data . constData ( ) , filename_data . length ( ) ) ;
metadata . ToProtobuf ( request - > mutable_metadata ( ) ) ;
2021-10-24 16:08:17 +02:00
return worker_pool_ - > SendMessageWithReply ( & message ) ;
}
void TagReaderClient : : UpdateSongsRating ( const SongList & songs ) {
for ( const Song & song : songs ) {
TagReaderReply * reply = UpdateSongRating ( song ) ;
QObject : : connect ( reply , & TagReaderReply : : Finished , reply , & TagReaderReply : : deleteLater ) ;
}
}
2021-10-18 23:15:30 +02:00
bool TagReaderClient : : IsMediaFileBlocking ( const QString & filename ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
2021-10-18 23:15:30 +02:00
bool ret = false ;
TagReaderReply * reply = IsMediaFile ( filename ) ;
2018-02-27 18:06:05 +01:00
if ( reply - > WaitForFinished ( ) ) {
2021-10-18 23:15:30 +02:00
ret = reply - > message ( ) . is_media_file_response ( ) . success ( ) ;
2018-02-27 18:06:05 +01:00
}
2023-03-18 20:03:07 +01:00
reply - > deleteLater ( ) ;
2018-02-27 18:06:05 +01:00
2021-10-18 23:15:30 +02:00
return ret ;
2018-02-27 18:06:05 +01:00
}
2021-10-18 23:15:30 +02:00
void TagReaderClient : : ReadFileBlocking ( const QString & filename , Song * song ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
2021-10-18 23:15:30 +02:00
TagReaderReply * reply = ReadFile ( filename ) ;
2018-02-27 18:06:05 +01:00
if ( reply - > WaitForFinished ( ) ) {
2021-10-18 23:15:30 +02:00
song - > InitFromProtobuf ( reply - > message ( ) . read_file_response ( ) . metadata ( ) ) ;
2018-02-27 18:06:05 +01:00
}
2023-03-18 20:03:07 +01:00
reply - > deleteLater ( ) ;
2018-02-27 18:06:05 +01:00
}
2023-05-14 11:34:55 +02:00
bool TagReaderClient : : SaveFileBlocking ( const QString & filename , const Song & metadata , const SaveTypes save_types , const SaveCoverOptions & save_cover_options ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
bool ret = false ;
2023-05-14 11:34:55 +02:00
TagReaderReply * reply = SaveFile ( filename , metadata , save_types , save_cover_options ) ;
2018-02-27 18:06:05 +01:00
if ( reply - > WaitForFinished ( ) ) {
2021-10-18 23:15:30 +02:00
ret = reply - > message ( ) . save_file_response ( ) . success ( ) ;
2018-02-27 18:06:05 +01:00
}
2023-03-18 20:03:07 +01:00
reply - > deleteLater ( ) ;
2018-02-27 18:06:05 +01:00
return ret ;
}
2021-02-26 21:03:51 +01:00
QByteArray TagReaderClient : : LoadEmbeddedArtBlocking ( const QString & filename ) {
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
QByteArray ret ;
TagReaderReply * reply = LoadEmbeddedArt ( filename ) ;
if ( reply - > WaitForFinished ( ) ) {
const std : : string & data_str = reply - > message ( ) . load_embedded_art_response ( ) . data ( ) ;
2021-10-30 02:21:29 +02:00
ret = QByteArray ( data_str . data ( ) , static_cast < qint64 > ( data_str . size ( ) ) ) ;
2021-02-26 21:03:51 +01:00
}
2023-03-18 20:03:07 +01:00
reply - > deleteLater ( ) ;
2021-02-26 21:03:51 +01:00
return ret ;
}
QImage TagReaderClient : : LoadEmbeddedArtAsImageBlocking ( const QString & filename ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
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 ( ) ;
2021-10-30 02:21:29 +02:00
ret . loadFromData ( QByteArray ( data_str . data ( ) , static_cast < qint64 > ( data_str . size ( ) ) ) ) ;
2018-02-27 18:06:05 +01:00
}
2023-03-18 20:03:07 +01:00
reply - > deleteLater ( ) ;
2021-02-16 22:50:35 +01:00
return ret ;
}
2023-03-18 20:03:07 +01:00
bool TagReaderClient : : SaveEmbeddedArtBlocking ( const QString & filename , const SaveCoverOptions & save_cover_options ) {
2021-02-16 22:50:35 +01:00
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
2021-10-24 16:08:17 +02:00
bool success = false ;
2021-02-16 22:50:35 +01:00
2023-03-18 20:03:07 +01:00
TagReaderReply * reply = SaveEmbeddedArt ( filename , save_cover_options ) ;
2021-02-16 22:50:35 +01:00
if ( reply - > WaitForFinished ( ) ) {
2021-10-24 16:08:17 +02:00
success = reply - > message ( ) . save_embedded_art_response ( ) . success ( ) ;
2021-02-16 22:50:35 +01:00
}
2023-03-18 20:03:07 +01:00
reply - > deleteLater ( ) ;
2018-02-27 18:06:05 +01:00
2021-10-24 16:08:17 +02:00
return success ;
}
bool TagReaderClient : : UpdateSongPlaycountBlocking ( const Song & metadata ) {
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
bool success = false ;
TagReaderReply * reply = UpdateSongPlaycount ( metadata ) ;
if ( reply - > WaitForFinished ( ) ) {
success = reply - > message ( ) . save_song_playcount_to_file_response ( ) . success ( ) ;
}
reply - > deleteLater ( ) ;
return success ;
}
bool TagReaderClient : : UpdateSongRatingBlocking ( const Song & metadata ) {
Q_ASSERT ( QThread : : currentThread ( ) ! = thread ( ) ) ;
bool success = false ;
TagReaderReply * reply = UpdateSongRating ( metadata ) ;
if ( reply - > WaitForFinished ( ) ) {
success = reply - > message ( ) . save_song_rating_to_file_response ( ) . success ( ) ;
}
reply - > deleteLater ( ) ;
return success ;
2018-02-27 18:06:05 +01:00
}