diff --git a/CMakeLists.txt b/CMakeLists.txt index a3c257c62..97371bf78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ option(ENABLE_CDPARANOIA "Enable CDParanoia libraries(required for AudioCD suppo option(ENABLE_CDDB "Enable CDDB libraries(either this or MusicBrianz required for AudioCD support)" ON) option(ENABLE_MUSICBRAINZ "Enable MusicBrianz libraries(either this or CDDB required for AudioCD support)" ON) option(ENABLE_PROXY_CONFIG "Enable proxy config in settings dialog" OFF) -option(ENABLE_EXTERNAL_TAGS "Enable usage of external app for reading/writing tags" ON) +option(ENABLE_EXTERNAL_TAGS "Enable usage of external app for reading/writing tags" OFF) if (ENABLE_QT5) set(ENABLE_KDE FALSE) @@ -128,7 +128,8 @@ if (ENABLE_QT5) find_package(Qt5Concurrent REQUIRED) set(QTCORELIBS ${Qt5Core_LIBRARIES}) set(QTNETWORKLIBS ${Qt5Network_LIBRARIES}) - set(QTLIBS ${QTCORELIBS} ${Qt5Widgets_LIBRARIES} ${QTNETWORKLIBS} ${Qt5Xml_LIBRARIES} ${Qt5Concurrent_LIBRARIES}) + set(QTGUILIBS ${Qt5Gui_LIBRARIES}) + set(QTLIBS ${QTCORELIBS} ${Qt5Widgets_LIBRARIES} ${QTNETWORKLIBS} ${QTGUILIBS} ${Qt5Xml_LIBRARIES} ${Qt5Concurrent_LIBRARIES}) set(QTINCLUDES ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5Xml_DEFINITIONS} ${Qt5Concurrent_DEFINITIONS}) set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") @@ -143,7 +144,8 @@ else (ENABLE_QT5) find_package(Qt4 REQUIRED QtCore QtGui QtXml QtNetwork) set(QTCORELIBS ${QT_QTCORE_LIBRARY}) set(QTNETWORKLIBS ${QT_QTNETWORK_LIBRARY}) - set(QTLIBS ${QT_QTSVG_LIBRARY} ${QT_QTXML_LIBRARY} ${QTCORELIBS} ${QT_QTGUI_LIBRARY} ${QTNETWORKLIBS}) + set(QTGUILIBS ${QT_QTGUI_LIBRARY}) + set(QTLIBS ${QT_QTSVG_LIBRARY} ${QT_QTXML_LIBRARY} ${QTCORELIBS} ${QTGUILIBS} ${QTNETWORKLIBS}) if (QT_QTDBUS_FOUND) set(QTLIBS ${QTLIBS} ${QT_QTDBUS_LIBRARY}) endif (QT_QTDBUS_FOUND) @@ -310,10 +312,10 @@ set(CANTATA_RCS cantata.qrc) if (TAGLIB_FOUND) set(CANTATA_SRCS ${CANTATA_SRCS} - tags/tageditor.cpp tags/trackorganiser.cpp tags/tagclient.cpp + tags/tageditor.cpp tags/trackorganiser.cpp devices/filenameschemedialog.cpp) set(CANTATA_MOC_HDRS ${CANTATA_MOC_HDRS} - tags/tageditor.h tags/trackorganiser.h tags/tagclient.h + tags/tageditor.h tags/trackorganiser.h devices/filenameschemedialog.h devices/device.h) set(CANTATA_UIS ${CANTATA_UIS} tags/tageditor.ui tags/trackorganiser.ui @@ -328,6 +330,7 @@ if (TAGLIB_FOUND) add_subdirectory(replaygain) endif (FFMPEG_FOUND OR MPG123_FOUND) if (ENABLE_EXTERNAL_TAGS) + set(CANTATA_SRCS ${CANTATA_SRCS} tags/tagclient.cpp) add_subdirectory(tags) else (ENABLE_EXTERNAL_TAGS) set(CANTATA_SRCS ${CANTATA_SRCS} tags/tags.cpp tags/filetyperesolver.cpp) @@ -628,6 +631,11 @@ if (TAGLIB_FOUND) endif (NOT ENABLE_PROXY_CONFIG AND NOT ENABLE_KDE) endif (NOT TAGLIB_FOUND OR NOT MTP_FOUND OR NOT AUDIOCD_SUPPORT OR NOT ENABLE_REPLAYGAIN_SUPPORT OR NOT ENABLE_HTTP_STREAM_PLAYBACK OR NOT ENABLE_REMOTE_DEVICES OR (NOT ENABLE_PROXY_CONFIG AND NOT ENABLE_KDE)) + if (ENABLE_EXTERNAL_TAGS) + message(" Tags will be read/written via an external helper app") + message(" NOTE: This is EXPERIMENTAL, and is NOT CURRENTLY WORKING!!!!") + message(" Do NOT report bugs with this build!!!") + endif (ENABLE_EXTERNAL_TAGS) else (TAGLIB_FOUND) message(" Disabled features:") diff --git a/ChangeLog b/ChangeLog index 3c01312cd..ea3ba19eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -81,8 +81,6 @@ 46. When displaying tag editor, track orgainiser, or replay gain dialogs, check that the song files can be accessed. (For speed reasons, only the 1st few files are checked) -47. Read/write tags in an external app - as per Clementine and Amarok. Isolates - Cantata from TagLib crashes. 1.1.3 ----- diff --git a/INSTALL b/INSTALL index 1437a6407..d55d73ae1 100644 --- a/INSTALL +++ b/INSTALL @@ -79,7 +79,8 @@ The following options may be passed to CMake: -DENABLE_EXTERNAL_TAGS=ON Enable usage of external app for reading/writing tags. Helps to isoloate Cantata from TagLib crashes. - Default: ON + EXPERIMENTAL - CURRENTLY **NOT** WORKING!!! + Default: OFF Windows specific: diff --git a/README b/README index c97d0bce6..fa6338a32 100644 --- a/README +++ b/README @@ -716,6 +716,7 @@ The following debug values may be used: Stream Fetching 512 Http Server 1024 Song Dialog file checks 2048 (Tag Editor, Track Organiser, etc) + Tag Reader/Writer 4096 (Only if built with external reader/writer) These values may be combined to enable multiple output. e.g. to enable MPD and covers logging: diff --git a/context/songview.cpp b/context/songview.cpp index d7675965b..5c7d23433 100644 --- a/context/songview.cpp +++ b/context/songview.cpp @@ -31,7 +31,7 @@ #include "messagebox.h" #include "localize.h" #ifdef TAGLIB_FOUND -#include "tagclient.h" +#include "tags.h" #endif #include "icons.h" #include "utils.h" @@ -309,7 +309,7 @@ void SongView::update(const Song &s, bool force) return; } else { #ifdef TAGLIB_FOUND - QString tagLyrics=TagClient::self()->readLyrics(MPDConnection::self()->getDetails().dir+songFile); + QString tagLyrics=Tags::readLyrics(MPDConnection::self()->getDetails().dir+songFile); if (!tagLyrics.isEmpty()) { text->setText(fixNewLines(tagLyrics)); diff --git a/devices/actiondialog.cpp b/devices/actiondialog.cpp index a49d49071..6b3e9a161 100644 --- a/devices/actiondialog.cpp +++ b/devices/actiondialog.cpp @@ -41,7 +41,7 @@ #include "freespaceinfo.h" #include "icons.h" #include "config.h" -#include "tagclient.h" +#include "tags.h" #include "treeview.h" #include "onlineservicesmodel.h" #ifdef ENABLE_REPLAYGAIN_SUPPORT @@ -600,7 +600,7 @@ void ActionDialog::actionStatus(int status, bool copiedCover) actionedTime+=currentSong.time; #endif #ifdef ENABLE_REPLAYGAIN_SUPPORT - if (Copy==mode && sourceIsAudioCd && !albumsWithoutRgTags.contains(currentSong.album) && TagClient::self()->readReplaygain(destFile).isEmpty()) { + if (Copy==mode && sourceIsAudioCd && !albumsWithoutRgTags.contains(currentSong.album) && Tags::readReplaygain(destFile).isEmpty()) { albumsWithoutRgTags.insert(currentSong.album); } #endif diff --git a/devices/device.cpp b/devices/device.cpp index 116abe8e5..a9c0d9b51 100644 --- a/devices/device.cpp +++ b/devices/device.cpp @@ -39,7 +39,7 @@ #include "audiocddevice.h" #endif // defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND #include "encoders.h" -#include "tagclient.h" +#include "tags.h" #include "song.h" #include "mpdparseutils.h" #include "musiclibraryitemartist.h" @@ -198,7 +198,7 @@ bool Device::fixVariousArtists(const QString &file, Song &song, bool applyFix) { Song orig=song; if (!file.isEmpty() && song.albumartist.isEmpty()) { - song=TagClient::self()->read(file); + song=Tags::read(file); } if (song.artist.isEmpty() || song.albumartist.isEmpty() || !Song::isVariousArtists(song.albumartist)) { @@ -214,7 +214,7 @@ bool Device::fixVariousArtists(const QString &file, Song &song, bool applyFix) needsUpdating=song.fixVariousArtists(); } - if (needsUpdating && (file.isEmpty() || Tags::Update_Modified==TagClient::self()->updateArtistAndTitle(file, song))) { + if (needsUpdating && (file.isEmpty() || Tags::Update_Modified==Tags::updateArtistAndTitle(file, song))) { return true; } song=orig; @@ -232,7 +232,7 @@ static QByteArray save(const QImage &img) { void Device::embedCover(const QString &file, Song &song, unsigned int coverMaxSize) { - if (TagClient::self()->readImage(file).isNull()) { + if (Tags::readImage(file).isNull()) { Covers::Image coverImage=Covers::self()->getImage(song); if (!coverImage.img.isNull()) { QByteArray imgData; @@ -248,7 +248,7 @@ void Device::embedCover(const QString &file, Song &song, unsigned int coverMaxSi imgData=save(coverImage.img); } } - TagClient::self()->embedImage(file, imgData); + Tags::embedImage(file, imgData); } } } diff --git a/devices/extractjob.cpp b/devices/extractjob.cpp index 33837cc0f..e99cfd22f 100644 --- a/devices/extractjob.cpp +++ b/devices/extractjob.cpp @@ -23,7 +23,7 @@ #include "extractjob.h" #include "device.h" #include "utils.h" -#include "tagclient.h" +#include "tags.h" #include "cdparanoia.h" #include "covers.h" #include "mpdconnection.h" @@ -150,7 +150,7 @@ void ExtractJob::run() process.closeWriteChannel(); process.waitForFinished(); Utils::setFilePerms(destFile); - TagClient::self()->update(destFile, Song(), song, 3); + Tags::update(destFile, Song(), song, 3); if (!stopRequested && !coverFile.isEmpty()) { QString mpdCover=MPDConnection::self()->getDetails().coverName; diff --git a/devices/fsdevice.cpp b/devices/fsdevice.cpp index dff2d6744..b3ab1843d 100644 --- a/devices/fsdevice.cpp +++ b/devices/fsdevice.cpp @@ -22,7 +22,7 @@ */ #include "umsdevice.h" -#include "tagclient.h" +#include "tags.h" #include "musiclibrarymodel.h" #include "musiclibraryitemsong.h" #include "musiclibraryitemalbum.h" @@ -162,7 +162,7 @@ void MusicScanner::scanFolder(MusicLibraryItemRoot *library, const QString &topL song.file=fname; QSet::iterator it=existing.find(song); if (existing.end()==it) { - song=TagClient::self()->read(info.absoluteFilePath()); + song=Tags::read(info.absoluteFilePath()); song.file=fname; } else { song=*it; diff --git a/gui/covers.cpp b/gui/covers.cpp index 45230b5da..a2c5e9d22 100644 --- a/gui/covers.cpp +++ b/gui/covers.cpp @@ -34,7 +34,7 @@ #include "podcastservice.h" #include "onlineservicesmodel.h" #ifdef TAGLIB_FOUND -#include "tagclient.h" +#include "tags.h" #endif #include #include @@ -907,7 +907,7 @@ Covers::Image Covers::locateImage(const Song &song) #ifdef TAGLIB_FOUND QImage img; if (prevFileName.startsWith(constCoverInTagPrefix)) { - img=TagClient::self()->readImage(prevFileName.mid(constCoverInTagPrefix.length())); + img=Tags::readImage(prevFileName.mid(constCoverInTagPrefix.length())); } else { img=QImage(prevFileName); } @@ -990,7 +990,7 @@ Covers::Image Covers::locateImage(const Song &song) #ifdef TAGLIB_FOUND QString fileName=haveAbsPath ? song.file : (MPDConnection::self()->getDetails().dir+songFile); if (QFile::exists(fileName)) { - QImage img(TagClient::self()->readImage(fileName)); + QImage img(Tags::readImage(fileName)); if (!img.isNull()) { DBUG_CLASS("Covers") << "Got cover image from tag" << fileName; return Image(img, constCoverInTagPrefix+fileName); diff --git a/gui/main.cpp b/gui/main.cpp index f2eda62e3..f2ac58322 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -55,6 +55,9 @@ #include "streamfetcher.h" #include "httpserver.h" #include "songdialog.h" +#ifdef ENABLE_EXTERNAL_TAGS +#include "tagclient.h" +#endif #include #include @@ -137,9 +140,10 @@ enum Debug { Dbg_StreamFetching = 0x0200, Dbg_HttpServer = 0x0400, Dbg_SongDialogs = 0x0800, + Dbg_TagHelper = 0x1000, // NOTE: MUST UPDATE Dbg_All IF ADD NEW ITEMS!!! - Dbg_All = 0x0FFF + Dbg_All = 0x1FFF }; int main(int argc, char *argv[]) @@ -262,6 +266,11 @@ int main(int argc, char *argv[]) if (dbg&Dbg_SongDialogs) { SongDialog::enableDebug(); } + #ifdef ENABLE_EXTERNAL_TAGS + if (dbg&Dbg_TagHelper) { + TagClient::enableDebug(); + } + #endif if (dbg&Dbg_All && logToFile) { #if QT_VERSION < 0x050000 qInstallMsgHandler(cantataQtMsgHandler); diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 859c2237d..020bc3960 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -93,7 +93,6 @@ #ifdef TAGLIB_FOUND #include "trackorganiser.h" #include "tageditor.h" -#include "tagclient.h" #ifdef ENABLE_REPLAYGAIN_SUPPORT #include "rgdialog.h" #endif @@ -881,9 +880,6 @@ MainWindow::~MainWindow() #ifndef ENABLE_KDE_SUPPORT MediaKeys::self()->stop(); #endif - #ifdef TAGLIB_FOUND - TagClient::self()->stop(); - #endif } void MainWindow::initSizes() diff --git a/http/httpserver.cpp b/http/httpserver.cpp index 6fc95654b..d36c2db64 100644 --- a/http/httpserver.cpp +++ b/http/httpserver.cpp @@ -24,7 +24,7 @@ #include "httpserver.h" #include "httpsocket.h" #ifdef TAGLIB_FOUND -#include "tagclient.h" +#include "tags.h" #endif #include "settings.h" #include "thread.h" @@ -201,13 +201,13 @@ QByteArray HttpServer::encodeUrl(const QString &file) const } } #ifdef TAGLIB_FOUND - s=TagClient::self()->read(f); + s=Tags::read(f); #endif s.file=f; #else DBUG << "file" << file; #ifdef TAGLIB_FOUND - s=TagClient::self()->read(file); + s=Tags::read(file); #endif s.file=file; #endif diff --git a/models/albumsmodel.cpp b/models/albumsmodel.cpp index 2f3c75f36..c987301d7 100644 --- a/models/albumsmodel.cpp +++ b/models/albumsmodel.cpp @@ -235,11 +235,11 @@ QVariant AlbumsModel::data(const QModelIndex &index, int role) const .scaled(QSize(cSize, cSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } if (!al->coverRequested && iSize && Song::SingleTracks!=al->type) { + al->coverRequested=true; al->getCover(); if (al->cover) { return *(al->cover); } - al->coverRequested=true; } return *theDefaultIcon; } @@ -549,10 +549,8 @@ void AlbumsModel::loadAllCovers() } foreach (AlbumItem *al, items) { if (!al->coverRequested && Song::SingleTracks!=al->type) { + al->coverRequested=true; al->getCover(); - if (!al->cover) { - al->coverRequested=true; - } } } } diff --git a/replaygain/rgdialog.cpp b/replaygain/rgdialog.cpp index 728bb5e8a..dbf921dbe 100644 --- a/replaygain/rgdialog.cpp +++ b/replaygain/rgdialog.cpp @@ -27,7 +27,7 @@ #endif #include "devicesmodel.h" #include "settings.h" -#include "tagclient.h" +#include "tags.h" #include "tagreader.h" #include "utils.h" #include "localize.h" @@ -413,7 +413,7 @@ bool RgDialog::saveTags() QMap::ConstIterator end=tagsToSave.constEnd(); for (; it!=end; ++it) { - switch (TagClient::self()->updateReplaygain(base+origSongs.at(it.key()).file, it.value())) { + switch (Tags::updateReplaygain(base+origSongs.at(it.key()).file, it.value())) { case Tags::Update_Failed: failed.append(origSongs.at(it.key()).file); break; diff --git a/replaygain/tagreader.cpp b/replaygain/tagreader.cpp index 10e1d8340..6ea8ed9fb 100644 --- a/replaygain/tagreader.cpp +++ b/replaygain/tagreader.cpp @@ -22,7 +22,7 @@ */ #include "tagreader.h" -#include "tagclient.h" +#include "tags.h" void TagReader::setDetails(const QList &s, const QString &dir) { @@ -38,7 +38,7 @@ void TagReader::run() return; } - emit progress(i, TagClient::self()->readReplaygain(baseDir+songs.at(i).file)); + emit progress(i, Tags::readReplaygain(baseDir+songs.at(i).file)); } setFinished(true); } diff --git a/tags/CMakeLists.txt b/tags/CMakeLists.txt index b3e6cab64..cafcc85d9 100644 --- a/tags/CMakeLists.txt +++ b/tags/CMakeLists.txt @@ -1,17 +1,10 @@ include_directories(${QTINCLUDES} ${TAGLIB_INCLUDES} ${CMAKE_SOURCE_DIR}/tags) set(CANTATA_TAGS_SRCS main.cpp tagserver.cpp tags.cpp filetyperesolver.cpp ../mpd/song.cpp) -set(CANTATA_TAGS_MOC_HDRS tagserver.h) if (ENABLE_KDE_SUPPORT) kde4_add_executable(cantata-tags ${CANTATA_TAGS_SRCS} ${CANTATA_TAGS_MOC_SRCS}) install(TARGETS cantata-tags RUNTIME DESTINATION lib/cantata) else (ENABLE_KDE_SUPPORT) - if (ENABLE_QT5) - QT5_WRAP_CPP(CANTATA_TAGS_MOC_SRCS ${CANTATA_TAGS_MOC_HDRS}) - else (ENABLE_QT5) - QT4_WRAP_CPP(CANTATA_TAGS_MOC_SRCS ${CANTATA_TAGS_MOC_HDRS}) - endif (ENABLE_QT5) - if (WIN32) set(CMAKE_BUILD_TYPE "Release") ADD_EXECUTABLE(cantata-tags WIN32 ${CANTATA_TAGS_SRCS} ${CANTATA_TAGS_MOC_SRCS}) @@ -22,8 +15,8 @@ else (ENABLE_KDE_SUPPORT) endif (WIN32) endif (ENABLE_KDE_SUPPORT) -add_definitions(-DCANTATA_NO_SONG_TIME_FUNCTION) -target_link_libraries(cantata-tags ${TAGLIB_LIBRARIES} ${QTCORELIBS} ${QTNETWORKLIBS}) +add_definitions(-DCANTATA_NO_SONG_TIME_FUNCTION -DCANTATA_TAG_SERVER) +target_link_libraries(cantata-tags ${TAGLIB_LIBRARIES} ${QTGUILIBS} ${QTCORELIBS} ${QTNETWORKLIBS}) if (TAGLIB-EXTRAS_FOUND) target_link_libraries(cantata-tags ${TAGLIB-EXTRAS_LIBRARIES}) include_directories(${TAGLIB-EXTRAS_INCLUDES}) diff --git a/tags/main.cpp b/tags/main.cpp index d076a9d29..a1eb93c7f 100644 --- a/tags/main.cpp +++ b/tags/main.cpp @@ -22,15 +22,10 @@ */ #include -#include #include "tagserver.h" int main(int argc, char *argv[]) { - if (argc<2) { - return -1; - } - QCoreApplication app(argc, argv); - TagServer *srv=new TagServer(argv[1]); - return srv->ok() ? app.exec() : -1; + TagServer server; + return server.process(); } diff --git a/tags/tagclient.cpp b/tags/tagclient.cpp index 53ad778e3..a19521fc7 100644 --- a/tags/tagclient.cpp +++ b/tags/tagclient.cpp @@ -16,351 +16,276 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to + * along with this program; see the file COPYING. If not, readStatusite to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "tagclient.h" +#include "tags.h" +#include "config.h" #include #include -#include -#ifdef ENABLE_KDE_SUPPORT -#include -K_GLOBAL_STATIC(TagClient, instance) -#endif -#ifdef ENABLE_EXTERNAL_TAGS #include #include -#include -#include -#include #include -#endif +#include + #include +static bool debugEnabled=false; +#define DBUG if (debugEnabled) qWarning() << "TagClient" << __FUNCTION__ + +void TagClient::enableDebug() +{ + debugEnabled=true; +} + +static void stopHelper(); + +static void signalHandler(int signum) +{ + stopHelper(); + exit(signum); +} + +static struct TagClientClose { ~TagClientClose() { stopHelper(); } } closer; static const int constMaxWait=5000; +static QMutex mutex; +static QProcess *proc=0; -TagClient * TagClient::self() +static void init() { - #ifdef ENABLE_KDE_SUPPORT - return instance; - #else - static TagClient *instance=0; - if(!instance) { - instance=new TagClient; + static bool initialised=false; + if (!initialised) { + // Need to stop helper if Cantata crashes... + QList sig=QList() << SIGINT << SIGILL << SIGTRAP << SIGTRAP << SIGABRT << SIGBUS << SIGFPE << SIGSEGV << SIGTERM; + foreach (int s, sig) { + signal(s, signalHandler); + } + initialised=true; } - return instance; - #endif } -TagClient::TagClient() - : mutex(new QMutex) - #ifdef ENABLE_EXTERNAL_TAGS - , loop(0) - , proc(0) - , server(0) - , socket(0) - #endif +enum ReadStatus { + Read_Ok, + Read_Timeout, + Read_Closed, + Read_Error +}; + +static bool running() { + return proc && QProcess::Running==proc->state() && proc->isOpen(); } -TagClient::~TagClient() +static void stopHelper() { - stop(); - delete mutex; + if (!proc) { + return; + } + DBUG << (void *)proc; + QProcess *p=proc; + + proc=0; + if (p) { + p->terminate(); + p->kill(); + p->deleteLater(); + } } -void TagClient::stop() +static bool startHelper() { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + DBUG << (void *)proc; + if (!running()) { + init(); + stopHelper(); + for (int i=0; i<5; ++i) { // Max5 start attempts... + DBUG << "start process"; + proc=new QProcess; + proc->setProcessChannelMode(QProcess::SeparateChannels); + proc->setReadChannel(QProcess::StandardOutput); + #ifdef Q_OS_WIN + proc->start(qApp->applicationDirPath()+"/cantata-tags.exe"); + #else + proc->start(INSTALL_PREFIX"/lib/cantata/cantata-tags"); + #endif + if (proc->waitForStarted(constMaxWait)) { + DBUG << "started"; + return true; + } else { + DBUG << "failed to start"; + stopHelper(); + } + } + return false; + } + return true; +} + +static ReadStatus readReply(QByteArray &data) +{ + DBUG << (void *)proc; + if (!running()) { + DBUG << "not running?"; + stopHelper(); + return Read_Closed; + } + if (proc->waitForReadyRead(constMaxWait)) { + data=proc->readAllStandardOutput(); + DBUG << "read reply, bytes:" << data.length(); + return data.isEmpty() ? Read_Error : Read_Ok; + } + DBUG << "wait for read failed " << running() << (proc ? (int)proc->state() : 12345); stopHelper(); - #endif + return !running() ? Read_Closed : Read_Timeout; } Song TagClient::read(const QString &fileName) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); Song resp; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName; - if (Wait_Ok==waitForReply()) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName; + QByteArray data; + if (Read_Ok==readReply(data)) { + QDataStream inStream(data); + inStream >> resp; } } return resp; - #else - return Tags::read(fileName); - #endif } QImage TagClient::readImage(const QString &fileName) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS - QByteArray data; + QMutexLocker locker(&mutex); + QImage resp; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName; - if (Wait_Ok==waitForReply()) { - stream >> data; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName; + QByteArray data; + if (Read_Ok==readReply(data)) { + QDataStream inStream(data); + inStream >> resp; } } - #else - QByteArray data=Tags::readImage(fileName); - #endif - QImage img; - if (!data.isEmpty()) { - img.loadFromData(data); - if (img.isNull()) { - img.loadFromData(QByteArray::fromBase64(data)); - } - } - return img; + return resp; } QString TagClient::readLyrics(const QString &fileName) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); QString resp; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName; - if (Wait_Ok==waitForReply()) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName; + QByteArray data; + if (Read_Ok==readReply(data)) { + QDataStream inStream(data); + inStream >> resp; } } return resp; - #else - return Tags::readLyrics(fileName); - #endif } -Tags::Update TagClient::updateArtistAndTitle(const QString &fileName, const Song &song) +int TagClient::updateArtistAndTitle(const QString &fileName, const Song &song) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); int resp=Tags::Update_Failed; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName << song; - WaitReply wr=waitForReply(); - if (Wait_Ok==wr) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName << song; + QByteArray data; + ReadStatus readStatus=readReply(data); + if (Read_Ok==readStatus) { + QDataStream inStream(data); + inStream >> resp; } else { - resp=Wait_Timeout==wr ? Tags::Update_Timedout : Tags::Update_BadFile; + resp=Read_Timeout==readStatus ? Tags::Update_Timedout : Tags::Update_BadFile; } } - return (Tags::Update)resp; - #else - return Tags::updateArtistAndTitle(fileName, song); - #endif + return resp; } -Tags::Update TagClient::update(const QString &fileName, const Song &from, const Song &to, int id3Ver) +int TagClient::update(const QString &fileName, const Song &from, const Song &to, int id3Ver) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); int resp=Tags::Update_Failed; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName << from << to << id3Ver; - WaitReply wr=waitForReply(); - if (Wait_Ok==wr) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName << from << to << id3Ver; + QByteArray data; + ReadStatus readStatus=readReply(data); + if (Read_Ok==readStatus) { + QDataStream inStream(data); + inStream >> resp; } else { - resp=Wait_Timeout==wr ? Tags::Update_Timedout : Tags::Update_BadFile; + resp=Read_Timeout==readStatus ? Tags::Update_Timedout : Tags::Update_BadFile; } } - return (Tags::Update)resp; - #else - return Tags::update(fileName, from, to, id3Ver); - #endif + return resp; } Tags::ReplayGain TagClient::readReplaygain(const QString &fileName) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); Tags::ReplayGain resp; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName; - if (Wait_Ok==waitForReply()) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName; + QByteArray data; + if (Read_Ok==readReply(data)) { + QDataStream inStream(data); + inStream >> resp; } } return resp; - #else - return Tags::readReplaygain(fileName); - #endif } -Tags::Update TagClient::updateReplaygain(const QString &fileName, const Tags::ReplayGain &rg) +int TagClient::updateReplaygain(const QString &fileName, const Tags::ReplayGain &rg) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); int resp=Tags::Update_Failed; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName << rg; - WaitReply wr=waitForReply(); - if (Wait_Ok==wr) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName << rg; + QByteArray data; + ReadStatus readStatus=readReply(data); + if (Read_Ok==readStatus) { + QDataStream inStream(data); + inStream >> resp; } else { - resp=Wait_Timeout==wr ? Tags::Update_Timedout : Tags::Update_BadFile; + resp=Read_Timeout==readStatus ? Tags::Update_Timedout : Tags::Update_BadFile; } } - return (Tags::Update)resp; - #else - return Tags::updateReplaygain(fileName, rg); - #endif + return resp; } -Tags::Update TagClient::embedImage(const QString &fileName, const QByteArray &cover) +int TagClient::embedImage(const QString &fileName, const QByteArray &cover) { - QMutexLocker locker(mutex); - #ifdef ENABLE_EXTERNAL_TAGS + QMutexLocker locker(&mutex); int resp=Tags::Update_Failed; if (startHelper()) { - QDataStream stream(socket); - stream << QString(__FUNCTION__) << fileName << cover; - WaitReply wr=waitForReply(); - if (Wait_Ok==wr) { - stream >> resp; + QDataStream outStream(proc); + DBUG << __FUNCTION__ << fileName; + outStream << QString(__FUNCTION__) << fileName << cover; + QByteArray data; + ReadStatus readStatus=readReply(data); + if (Read_Ok==readStatus) { + QDataStream inStream(data); + inStream >> resp; } else { - resp=Wait_Timeout==wr ? Tags::Update_Timedout : Tags::Update_BadFile; + resp=Read_Timeout==readStatus ? Tags::Update_Timedout : Tags::Update_BadFile; } } - return (Tags::Update)resp; - #else - return Tags::embedImage(fileName, cover); - #endif + return resp; } - -#ifdef ENABLE_EXTERNAL_TAGS -enum ErrorCodes { - Connected = 0, - FailedToStart = 1, - OtherError = 2 -}; - -#endif - -void TagClient::processError(QProcess::ProcessError error) -{ - #ifdef ENABLE_EXTERNAL_TAGS - switch (error) { - case QProcess::FailedToStart: - qWarning() << "Failed to start tag reader/writer"; - if (loop && loop->isRunning()) { - loop->exit(FailedToStart); - } - break; - default: - qWarning() << "Tag reader/writer failed with error " << error << " - restarting"; - stopHelper(); - if (loop && loop->isRunning()) { - loop->exit(OtherError); - } - break; - } - #endif -} - -void TagClient::newConnection() -{ - #ifdef ENABLE_EXTERNAL_TAGS - socket = server->nextPendingConnection(); - socket->setParent(this); - closeServerSocket(); - if (loop && loop->isRunning()) { - loop->exit(Connected); - } - #endif -} - -#ifdef ENABLE_EXTERNAL_TAGS -bool TagClient::startHelper() -{ - if (!proc) { - for (int i=0; i<5; ++i) { // Max5 start attempts... - proc=new QProcess(this); - server=new QLocalServer(this); - - connect(server, SIGNAL(newConnection()), this, SLOT(newConnection())); - connect(proc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - - forever { - const QString name = QString("cantata_tags_%1").arg(qrand() ^ ((int)(quint64(this) & 0xFFFFFFFF))); - if (server->listen(name)) { - break; - } - } - - proc->setProcessChannelMode(QProcess::ForwardedChannels); - #ifdef Q_OS_WIN - proc->start(qApp->applicationDirPath()+"/cantata-tags.exe", QStringList() << server->fullServerName()); - #else - proc->start(INSTALL_PREFIX"/lib/cantata/cantata-tags", QStringList() << server->fullServerName()); - #endif - - if (!loop) { - loop=new QEventLoop(this); - } - int rv=loop->exec(QEventLoop::ExcludeUserInputEvents); - loop->deleteLater(); - loop=0; - if (rv!=OtherError) { - break; - } - } - } - - return 0!=socket; -} - -void TagClient::stopHelper() -{ - QProcess *p=proc; - QLocalSocket *s=socket; - - proc=0; - socket=0; - if (p) { - disconnect(p, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - p->kill(); - p->deleteLater(); - } - if (s) { - s->deleteLater(); - } - closeServerSocket(); -} - -void TagClient::closeServerSocket() -{ - QLocalServer *s=server; - server=0; - if (s) { - disconnect(s, SIGNAL(newConnection()), this, SLOT(newConnection())); - s->deleteLater(); - } -} - -TagClient::WaitReply TagClient::waitForReply() -{ - if (!socket) { - return Wait_Closed; - } - if (socket->waitForReadyRead(constMaxWait)) { - return Wait_Ok; - } - return !socket || QLocalSocket::ConnectedState!=socket->state() ? Wait_Closed : Wait_Timeout; -} - -#endif diff --git a/tags/tagclient.h b/tags/tagclient.h index 90b530e91..cf0349198 100644 --- a/tags/tagclient.h +++ b/tags/tagclient.h @@ -24,68 +24,26 @@ #ifndef TAG_CLIENT_H #define TAG_CLIENT_H -#include "tags.h" -#include "config.h" -#ifdef ENABLE_EXTERNAL_TAGS -#include -#include -#endif -#include +#include "song.h" +#include +#include -#ifdef ENABLE_EXTERNAL_TAGS -class QEventLoop; -class QLocalServer; -class QLocalSocket; -#endif -class QMutex; - -class TagClient : public QObject +namespace Tags { - Q_OBJECT + struct ReplayGain; +} -public: - static TagClient * self(); - - TagClient(); - ~TagClient(); - - void stop(); - - Song read(const QString &fileName); - QImage readImage(const QString &fileName); - QString readLyrics(const QString &fileName); - Tags::Update updateArtistAndTitle(const QString &fileName, const Song &song); - Tags::Update update(const QString &fileName, const Song &from, const Song &to, int id3Ver=-1); - Tags::ReplayGain readReplaygain(const QString &fileName); - Tags::Update updateReplaygain(const QString &fileName, const Tags::ReplayGain &rg); - Tags::Update embedImage(const QString &fileName, const QByteArray &cover); - -private Q_SLOTS: - void processError(QProcess::ProcessError error); - void newConnection(); - -private: - #ifdef ENABLE_EXTERNAL_TAGS - enum WaitReply { - Wait_Ok, - Wait_Timeout, - Wait_Closed - }; - - bool startHelper(); - void stopHelper(); - void closeServerSocket(); - WaitReply waitForReply(); - #endif - -private: - QMutex *mutex; - #ifdef ENABLE_EXTERNAL_TAGS - QEventLoop *loop; - QProcess *proc; - QLocalServer *server; - QLocalSocket *socket; - #endif -}; +namespace TagClient +{ + extern void enableDebug(); + extern Song read(const QString &fileName); + extern QImage readImage(const QString &fileName); + extern QString readLyrics(const QString &fileName); + extern int updateArtistAndTitle(const QString &fileName, const Song &song); + extern int update(const QString &fileName, const Song &from, const Song &to, int id3Ver); + extern Tags::ReplayGain readReplaygain(const QString &fileName); + extern int updateReplaygain(const QString &fileName, const Tags::ReplayGain &rg); + extern int embedImage(const QString &fileName, const QByteArray &cover); +} #endif diff --git a/tags/tageditor.cpp b/tags/tageditor.cpp index 3deb581b6..1d475d533 100644 --- a/tags/tageditor.cpp +++ b/tags/tageditor.cpp @@ -22,7 +22,7 @@ */ #include "tageditor.h" -#include "tagclient.h" +#include "tags.h" #include "musiclibrarymodel.h" #include "mpdconnection.h" #include "settings.h" @@ -725,7 +725,7 @@ bool TagEditor::applyUpdates() continue; } - switch(TagClient::self()->update(baseDir+orig.file, orig, edit)) { + switch(Tags::update(baseDir+orig.file, orig, edit)) { case Tags::Update_Modified: #ifdef ENABLE_DEVICES_SUPPORT if (!deviceUdi.isEmpty()) { diff --git a/tags/tags.cpp b/tags/tags.cpp index 963c5a049..031b78b66 100644 --- a/tags/tags.cpp +++ b/tags/tags.cpp @@ -77,6 +77,16 @@ #include #endif +#ifdef ENABLE_EXTERNAL_TAGS +// Mutex is locked in client, and server (that accesses this class) is single threaded +#define LOCK_MUTEX +#else +#include +#include +static QMutex mutex; +#define LOCK_MUTEX QMutexLocker locker(&mutex); +#endif + namespace Tags { @@ -185,7 +195,7 @@ static QPair splitDiscNumber(const QString &value) } // -- taken from rgtag.cpp from libebur128 -- START -static bool clearTxxxTag(TagLib::ID3v2::Tag* tag, TagLib::String tagName) +static bool clearTxxxTag(TagLib::ID3v2::Tag *tag, TagLib::String tagName) { TagLib::ID3v2::FrameList l = tag->frameList("TXXX"); for (TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it) { @@ -198,7 +208,7 @@ static bool clearTxxxTag(TagLib::ID3v2::Tag* tag, TagLib::String tagName) return false; } -static bool clearRva2Tag(TagLib::ID3v2::Tag* tag, TagLib::String tagName) +static bool clearRva2Tag(TagLib::ID3v2::Tag *tag, TagLib::String tagName) { TagLib::ID3v2::FrameList l = tag->frameList("RVA2"); for (TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it) { @@ -211,7 +221,7 @@ static bool clearRva2Tag(TagLib::ID3v2::Tag* tag, TagLib::String tagName) return false; } -static void setTxxxTag(TagLib::ID3v2::Tag* tag, const std::string &tagName, const std::string &value) +static void setTxxxTag(TagLib::ID3v2::Tag *tag, const std::string &tagName, const std::string &value) { TagLib::ID3v2::UserTextIdentificationFrame *frame = TagLib::ID3v2::UserTextIdentificationFrame::find(tag, tagName); if (!frame) { @@ -222,14 +232,14 @@ static void setTxxxTag(TagLib::ID3v2::Tag* tag, const std::string &tagName, cons frame->setText(value); } -static void setRva2Tag(TagLib::ID3v2::Tag* tag, const std::string &tagName, double gain, double peak) +static void setRva2Tag(TagLib::ID3v2::Tag *tag, const std::string &tagName, double gain, double peak) { TagLib::ID3v2::RelativeVolumeFrame *frame = NULL; TagLib::ID3v2::FrameList frameList = tag->frameList("RVA2"); TagLib::ID3v2::FrameList::ConstIterator it = frameList.begin(); for (; it != frameList.end(); ++it) { TagLib::ID3v2::RelativeVolumeFrame *fr=dynamic_cast(*it); - if (fr->identification() == tagName) { + if (fr && fr->identification() == tagName) { frame = fr; break; } @@ -251,7 +261,7 @@ static void setRva2Tag(TagLib::ID3v2::Tag* tag, const std::string &tagName, doub } // -- taken from rgtag.cpp from libebur128 -- END -static void readID3v2Tags(TagLib::ID3v2::Tag *tag, Song *song, ReplayGain *rg, QByteArray *img, QString *lyrics) +static void readID3v2Tags(TagLib::ID3v2::Tag *tag, Song *song, ReplayGain *rg, QImage *img, QString *lyrics) { if (song) { const TagLib::ID3v2::FrameList &albumArtist = tag->frameListMap()["TPE2"]; @@ -310,8 +320,8 @@ static void readID3v2Tags(TagLib::ID3v2::Tag *tag, Song *song, ReplayGain *rg, Q for (; it != end && !found; ++it) { TagLib::ID3v2::AttachedPictureFrame *pic=dynamic_cast(*it); if (pic && TagLib::ID3v2::AttachedPictureFrame::FrontCover==pic->type()) { - *img=QByteArray((const char *) pic->picture().data(), (int) pic->picture().size()); - if (!img->isEmpty()) { + img->loadFromData((const uchar *) pic->picture().data(), pic->picture().size()); + if (!img->isNull()) { found=true; } } @@ -320,7 +330,7 @@ static void readID3v2Tags(TagLib::ID3v2::Tag *tag, Song *song, ReplayGain *rg, Q if (!found) { // Just use first image! TagLib::ID3v2::AttachedPictureFrame *pic=static_cast(frames.front()); - *img=QByteArray((const char *) pic->picture().data(), (int) pic->picture().size()); + img->loadFromData((const uchar *) pic->picture().data(), pic->picture().size()); } } } @@ -516,7 +526,7 @@ static TagLib::String readVorbisTag(TagLib::Ogg::XiphComment *tag, const char *f return TagLib::String(); } -static void readVorbisCommentTags(TagLib::Ogg::XiphComment *tag, Song *song, ReplayGain *rg, QByteArray *img) +static void readVorbisCommentTags(TagLib::Ogg::XiphComment *tag, Song *song, ReplayGain *rg, QImage *img) { if (song) { TagLib::String str=readVorbisTag(tag, "ALBUMARTIST"); @@ -545,17 +555,22 @@ static void readVorbisCommentTags(TagLib::Ogg::XiphComment *tag, Song *song, Rep // Ogg lacks a definitive standard for embedding cover art, but it seems // b64 encoding a field called COVERART is the general convention if (map.contains("COVERART")) { - *img=map["COVERART"].toString().toCString(); + QByteArray data=map["COVERART"].toString().toCString(); + img->loadFromData(QByteArray::fromBase64(data)); + if (img->isNull()) { + img->loadFromData(data); // not base64?? + } } } } #if (TAGLIB_MAJOR_VERSION > 1) || (TAGLIB_MAJOR_VERSION == 1 && TAGLIB_MINOR_VERSION >= 7) -static void readFlacPicture(const TagLib::List &pics, QByteArray *img) +static void readFlacPicture(const TagLib::List &pics, QImage *img) { if (!pics.isEmpty() && 1==pics.size()) { TagLib::FLAC::Picture *picture = *(pics.begin()); - *img=QByteArray(picture->data().data(), picture->data().size()); + QByteArray data(picture->data().data(), picture->data().size()); + img->loadFromData(data); } } #endif @@ -617,7 +632,7 @@ static bool writeVorbisCommentTags(TagLib::Ogg::XiphComment *tag, const Song &fr } #ifdef TAGLIB_MP4_FOUND -static void readMP4Tags(TagLib::MP4::Tag *tag, Song *song, ReplayGain *rg, QByteArray *img) +static void readMP4Tags(TagLib::MP4::Tag *tag, Song *song, ReplayGain *rg, QImage *img) { TagLib::MP4::ItemListMap &map = tag->itemListMap(); @@ -652,7 +667,7 @@ static void readMP4Tags(TagLib::MP4::Tag *tag, Song *song, ReplayGain *rg, QByte TagLib::MP4::CoverArtList coverArtList = coverItem.toCoverArtList(); if (!coverArtList.isEmpty()) { TagLib::MP4::CoverArt coverArt = coverArtList.front(); - *img=QByteArray((const char *) coverArt.data().data(), (int) coverArt.data().size()); + img->loadFromData((const uchar *) coverArt.data().data(), coverArt.data().size()); } } } @@ -775,7 +790,7 @@ static bool writeASFTags(TagLib::ASF::Tag *tag, const Song &from, const Song &to } #endif -static void readTags(const TagLib::FileRef fileref, Song *song, ReplayGain *rg, QByteArray *img, QString *lyrics) +static void readTags(const TagLib::FileRef fileref, Song *song, ReplayGain *rg, QImage *img, QString *lyrics) { TagLib::Tag *tag=fileref.tag(); if (song) { @@ -984,9 +999,9 @@ static bool writeTags(const TagLib::FileRef fileref, const Song &from, const Son Song read(const QString &fileName) { + LOCK_MUTEX Song song; TagLib::FileRef fileref = getFileRef(fileName); - if (fileref.isNull()) { return song; } @@ -997,11 +1012,11 @@ Song read(const QString &fileName) return song; } -QByteArray readImage(const QString &fileName) +QImage readImage(const QString &fileName) { - QByteArray img; + LOCK_MUTEX + QImage img; TagLib::FileRef fileref = getFileRef(fileName); - if (fileref.isNull()) { return img; } @@ -1012,9 +1027,9 @@ QByteArray readImage(const QString &fileName) QString readLyrics(const QString &fileName) { + LOCK_MUTEX QString lyrics; TagLib::FileRef fileref = getFileRef(fileName); - if (fileref.isNull()) { return lyrics; } @@ -1047,8 +1062,8 @@ static Update update(const TagLib::FileRef fileref, const Song &from, const Song Update updateArtistAndTitle(const QString &fileName, const Song &song) { + LOCK_MUTEX TagLib::FileRef fileref = getFileRef(fileName); - if (fileref.isNull()) { return Update_Failed; } @@ -1074,14 +1089,15 @@ Update updateArtistAndTitle(const QString &fileName, const Song &song) Update update(const QString &fileName, const Song &from, const Song &to, int id3Ver) { + LOCK_MUTEX TagLib::FileRef fileref = getFileRef(fileName); return fileref.isNull() ? Update_Failed : update(fileref, from, to, RgTags(), QByteArray(), id3Ver); } ReplayGain readReplaygain(const QString &fileName) { + LOCK_MUTEX TagLib::FileRef fileref = getFileRef(fileName); - if (fileref.isNull()) { return false; } @@ -1093,12 +1109,14 @@ ReplayGain readReplaygain(const QString &fileName) Update updateReplaygain(const QString &fileName, const ReplayGain &rg) { + LOCK_MUTEX TagLib::FileRef fileref = getFileRef(fileName); return fileref.isNull() ? Update_Failed : update(fileref, Song(), Song(), RgTags(rg), QByteArray()); } Update embedImage(const QString &fileName, const QByteArray &cover) { + LOCK_MUTEX TagLib::FileRef fileref = getFileRef(fileName); return fileref.isNull() ? Update_Failed : update(fileref, Song(), Song(), RgTags(), cover); } diff --git a/tags/tags.h b/tags/tags.h index 0311a7b12..0dce2b097 100644 --- a/tags/tags.h +++ b/tags/tags.h @@ -26,9 +26,14 @@ #include "song.h" #include "utils.h" -#include +#include "config.h" +#include #include +#if defined ENABLE_EXTERNAL_TAGS && !defined CANTATA_TAG_SERVER +#include "tagclient.h" +#endif + namespace Tags { struct ReplayGain @@ -62,14 +67,25 @@ namespace Tags #endif }; + #if defined ENABLE_EXTERNAL_TAGS && !defined CANTATA_TAG_SERVER + inline Song read(const QString &fileName) { return TagClient::read(fileName); } + inline QImage readImage(const QString &fileName) { return TagClient::readImage(fileName); } + inline QString readLyrics(const QString &fileName) { return TagClient::readLyrics(fileName); } + inline Update updateArtistAndTitle(const QString &fileName, const Song &song) { return (Update)TagClient::updateArtistAndTitle(fileName, song); } + inline Update update(const QString &fileName, const Song &from, const Song &to, int id3Ver=-1) { return (Update)TagClient::update(fileName, from, to, id3Ver); } + inline ReplayGain readReplaygain(const QString &fileName) { return TagClient::readReplaygain(fileName); } + inline Update updateReplaygain(const QString &fileName, const ReplayGain &rg) { return (Update)TagClient::updateReplaygain(fileName, rg); } + inline Update embedImage(const QString &fileName, const QByteArray &cover) { return (Update)TagClient::embedImage(fileName, cover); } + #else extern Song read(const QString &fileName); - extern QByteArray readImage(const QString &fileName); + extern QImage readImage(const QString &fileName); extern QString readLyrics(const QString &fileName); extern Update updateArtistAndTitle(const QString &fileName, const Song &song); extern Update update(const QString &fileName, const Song &from, const Song &to, int id3Ver=-1); extern ReplayGain readReplaygain(const QString &fileName); extern Update updateReplaygain(const QString &fileName, const ReplayGain &rg); extern Update embedImage(const QString &fileName, const QByteArray &cover); + #endif } #ifdef ENABLE_EXTERNAL_TAGS diff --git a/tags/tagserver.cpp b/tags/tagserver.cpp index 3ef90794b..1f4eea9d7 100644 --- a/tags/tagserver.cpp +++ b/tags/tagserver.cpp @@ -26,68 +26,67 @@ #include #include #include +#include -TagServer::TagServer(const char *socketName) - : QObject(0) - , socket(new QLocalSocket(this)) +TagServer::TagServer() { - socket->connectToServer(socketName); - if (socket->waitForConnected(1000)) { - connect(socket, SIGNAL(readyRead()), this, SLOT(readRequest())); - connect(socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), this, SLOT(stateChanged(QLocalSocket::LocalSocketState))); - } else { - socket->close(); - socket->deleteLater(); - socket=0; - } + in=new QFile(0); + in->open(stdin, QIODevice::ReadOnly); + out=new QFile(0); + out->open(stdout, QIODevice::WriteOnly); } TagServer::~TagServer() { - if (socket) { - socket->close(); - socket->deleteLater(); - } + delete in; + delete out; } -void TagServer::readRequest() +int TagServer::process() { - QDataStream stream(socket); - QString request; - QString fileName; - stream >> request >> fileName; + while (in->isReadable() && out->isWritable()) { + QString request; + QString fileName; + QDataStream inStream(in); + QDataStream outStream(out); - if (QLatin1String("read")==request) { - stream << Tags::read(fileName); - } else if (QLatin1String("readImage")==request) { - stream << Tags::readImage(fileName); - } else if (QLatin1String("readLyrics")==request) { - stream << Tags::readLyrics(fileName); - } else if (QLatin1String("updateArtistAndTitle")==request) { - Song song; - stream << (int)Tags::updateArtistAndTitle(fileName, song); - } else if (QLatin1String("update")==request) { - Song from; - Song to; - int id3Ver; - stream >> from >> to >> id3Ver; - stream << (int)Tags::update(fileName, from, to, id3Ver); - } else if (QLatin1String("readReplaygain")==request) { - stream << Tags::readReplaygain(fileName); - } else if (QLatin1String("updateReplaygain")==request) { - Tags::ReplayGain rg; - stream >> rg; - stream << (int)Tags::updateReplaygain(fileName, rg); - } else if (QLatin1String("embedImage")==request) { - QByteArray cover; - stream >> cover; - stream << (int)Tags::embedImage(fileName, cover); - } -} + inStream >> request >> fileName; -void TagServer::stateChanged(QLocalSocket::LocalSocketState state) -{ - if (QLocalSocket::ClosingState==state || QLocalSocket::UnconnectedState==state) { - qApp->exit(0); + if (QLatin1String("read")==request) { + outStream << Tags::read(fileName); + out->flush(); + } else if (QLatin1String("readImage")==request) { + outStream << Tags::readImage(fileName); + out->flush(); + } else if (QLatin1String("readLyrics")==request) { + outStream << Tags::readLyrics(fileName); + out->flush(); + } else if (QLatin1String("updateArtistAndTitle")==request) { + Song song; + outStream << (int)Tags::updateArtistAndTitle(fileName, song); + out->flush(); + } else if (QLatin1String("update")==request) { + Song from; + Song to; + int id3Ver; + inStream >> from >> to >> id3Ver; + outStream << (int)Tags::update(fileName, from, to, id3Ver); + out->flush(); + } else if (QLatin1String("readReplaygain")==request) { + Tags::ReplayGain rg=Tags::readReplaygain(fileName); + outStream << rg; + out->flush(); + } else if (QLatin1String("updateReplaygain")==request) { + Tags::ReplayGain rg; + inStream >> rg; + outStream << (int)Tags::updateReplaygain(fileName, rg); + out->flush(); + } else if (QLatin1String("embedImage")==request) { + QByteArray cover; + inStream >> cover; + outStream << (int)Tags::embedImage(fileName, cover); + out->flush(); + } } + return 0; } diff --git a/tags/tagserver.h b/tags/tagserver.h index 48059eeb8..54129d92d 100644 --- a/tags/tagserver.h +++ b/tags/tagserver.h @@ -24,25 +24,19 @@ #ifndef TAG_SERVER_H #define TAG_SERVER_H -#include -#include +class QFile; -class TagServer : public QObject +class TagServer { - Q_OBJECT - public: - TagServer(const char *socketName); + TagServer(); ~TagServer(); - bool ok() const { return 0!=socket; } - -private Q_SLOTS: - void readRequest(); - void stateChanged(QLocalSocket::LocalSocketState state); + int process(); private: - QLocalSocket *socket; + QFile *in; + QFile *out; }; #endif